Skip to content

Commit

Permalink
refactor(): Phone verification in settings consists the active backend
Browse files Browse the repository at this point in the history
  • Loading branch information
SepehrHasanabadi committed Jan 25, 2020
1 parent ca42409 commit 6381fdc
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 67 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Configuration
"VERIFY_SECURITY_CODE_ONLY_ONCE": False, # If False, then a security code can be used multiple times for verification
}
- In case of using Kavenegar as your backend service, you have to replace ``BACKEND`` with ``phone_verify.backends.kavenegar.KavenegarBackend`` and locate your ``API-KEY` in ``SECRET`` and ``SENDER`` in ``FROM``, extra fields could be omitted.
Usage
-----

Expand Down
6 changes: 3 additions & 3 deletions phone_verify/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ def get_sms_backend(phone_number):
if not backend:
backend_import = DEFAULT_SERVICE

if settings.PHONE_VERIFICATION['DEFAULT'].get("BACKEND", None):
backend_import = settings.PHONE_VERIFICATION['DEFAULT']["BACKEND"]
if settings.PHONE_VERIFICATION.get("BACKEND", None):
backend_import = settings.PHONE_VERIFICATION["BACKEND"]

backend_cls = import_string(backend_import)
return backend_cls(**settings.PHONE_VERIFICATION['DEFAULT']["OPTIONS"])
return backend_cls(**settings.PHONE_VERIFICATION["OPTIONS"])
6 changes: 3 additions & 3 deletions phone_verify/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def generate_security_code(cls):
"""
Returns a unique random `security_code` for given `TOKEN_LENGTH` in the settings.
"""
token_length = django_settings.PHONE_VERIFICATION['DEFAULT'].get(
token_length = django_settings.PHONE_VERIFICATION.get(
"TOKEN_LENGTH", DEFAULT_TOKEN_LENGTH
)
return get_random_string(token_length, allowed_chars="0123456789")
Expand All @@ -56,7 +56,7 @@ def check_security_code_expiry(cls, stored_verification):
Returns True if the `security_code` for the `stored_verification` is expired.
"""
time_difference = timezone.now() - stored_verification.created_at
if time_difference.seconds > django_settings.PHONE_VERIFICATION['DEFAULT'].get(
if time_difference.seconds > django_settings.PHONE_VERIFICATION.get(
"SECURITY_CODE_EXPIRATION_TIME"
):
return True
Expand Down Expand Up @@ -126,7 +126,7 @@ def validate_security_code(self, security_code, phone_number, session_token):
return stored_verification, self.SECURITY_CODE_EXPIRED

# check security_code is not verified
if stored_verification.is_verified and django_settings.PHONE_VERIFICATION['DEFAULT'].get(
if stored_verification.is_verified and django_settings.PHONE_VERIFICATION.get(
"VERIFY_SECURITY_CODE_ONLY_ONCE"
):
return stored_verification, self.SECURITY_CODE_VERIFIED
Expand Down
40 changes: 12 additions & 28 deletions phone_verify/backends/kavenegar.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,25 @@
from .base import BaseBackend


class KavenegarException(APIException, HTTPException):
pass


class KavenegarBackend(BaseBackend):
def __init__(self, **options):
super(KavenegarBackend, self).__init__(**options)
# Lower case it just to be sure
options = {key.lower(): value for key, value in options.items()}
self._api_key = options.get("api_key", None)
self._sender = options.get("sender", None)
self.api_key = options.get("secret", None)
self.sender = options.get("from", None)

self._api = KavenegarAPI(self._api_key)
self.client = KavenegarAPI(self.api_key)
self.exception_class = KavenegarException

def send_sms(self, number, message):
try:
params = {
'receptor': number,
'template': '',
'token': message,
'type': 'sms'
}
response = self._api.sms_send(params)
print(response)
except APIException as exp:
print(exp)
except HTTPException as exp:
print(exp)
params = {'receptor': number, 'template': '', 'token': message, 'type': 'sms'}
self.client.sms_send(params)

def send_bulk_sms(self, numbers, message):
try:
params = {
'sender': self._sender,
'receptor': numbers,
'message': message,
}
response = self._api.sms_sendarray(params)
print(response)
except APIException as exp:
print(exp)
except HTTPException as exp:
print(exp)
params = {'sender': self.sender, 'receptor': numbers, 'message': message, }
self.client.sms_sendarray(params)
6 changes: 3 additions & 3 deletions phone_verify/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

class PhoneVerificationService(object):
try:
phone_settings = settings.PHONE_VERIFICATION['DEFAULT']
phone_settings = settings.PHONE_VERIFICATION
except AttributeError:
raise ImproperlyConfigured("Please define PHONE_VERIFICATION in settings")

Expand All @@ -44,7 +44,7 @@ def send_verification(self, number, security_code):

def _generate_message(self, security_code):
return self.verification_message.format(
app=settings.PHONE_VERIFICATION['DEFAULT'].get("APP_NAME", DEFAULT_APP_NAME),
app=settings.PHONE_VERIFICATION.get("APP_NAME", DEFAULT_APP_NAME),
security_code=security_code,
)

Expand All @@ -58,7 +58,7 @@ def _check_required_settings(self):
"SECURITY_CODE_EXPIRATION_TIME",
"VERIFY_SECURITY_CODE_ONLY_ONCE",
}
user_settings = set(settings.PHONE_VERIFICATION['DEFAULT'].keys())
user_settings = set(settings.PHONE_VERIFICATION.keys())
if not required_settings.issubset(user_settings):
raise ImproperlyConfigured(
"Please specify following settings in settings.py: {}".format(
Expand Down
21 changes: 17 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,27 @@ def test_phone_registration_sends_message(client, mocker):
url = reverse("phone-register")
phone_number = PHONE_NUMBER
data = {"phone_number": phone_number}
twilio_api = mocker.patch(
api = mocker.patch(
"phone_verify.services.PhoneVerificationService.send_verification"
)

response = client.post(url, data)

assert response.status_code == 200
assert twilio_api.called
assert api.called
assert "session_token" in response.data
sms_verification = apps.get_model("phone_verify", "SMSVerification")
assert sms_verification.objects.get(
session_token=response.data["session_token"], phone_number=phone_number
)

settings.DJANGO_SETTINGS["PHONE_VERIFICATION"][
"BACKEND"
] = 'phone_verify.backends.kavenegar.KavenegarBackend'
response = client.post(url, data)

assert response.status_code == 200
assert api.called
assert "session_token" in response.data
sms_verification = apps.get_model("phone_verify", "SMSVerification")
assert sms_verification.objects.get(
Expand Down Expand Up @@ -151,7 +164,7 @@ def test_verified_security_code(client):
}

# Security code verification is restricted to one time
settings.DJANGO_SETTINGS["PHONE_VERIFICATION"]['DEFAULT'][
settings.DJANGO_SETTINGS["PHONE_VERIFICATION"][
"VERIFY_SECURITY_CODE_ONLY_ONCE"
] = True
response = client.json.post(url, data=data)
Expand All @@ -160,7 +173,7 @@ def test_verified_security_code(client):
assert response_data["non_field_errors"][0] == "Security code is already verified"

# Security code verification is not restricted to one time
settings.DJANGO_SETTINGS["PHONE_VERIFICATION"]['DEFAULT'][
settings.DJANGO_SETTINGS["PHONE_VERIFICATION"][
"VERIFY_SECURITY_CODE_ONLY_ONCE"
] = False
response = client.json.post(url, data=data)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

def test_message_generation_and_sending_service(client, mocker):
service = PhoneVerificationService(phone_number="+13478379634")
service_api = mocker.patch(f'{settings.PHONE_VERIFICATION["DEFAULT"]["BACKEND"]}.send_sms')
service_api = mocker.patch(f'{settings.PHONE_VERIFICATION["BACKEND"]}.send_sms')
service.send_verification("+13478379634", "123456")

assert service_api.called
37 changes: 12 additions & 25 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,18 @@
],
# PHONE VERIFICATION
"PHONE_VERIFICATION": {
"TWILIO": {
"BACKEND": "phone_verify.backends.twilio.TwilioBackend",
"OPTIONS": {
"SID": "fake",
"SECRET": "fake",
"FROM": "+14755292729",
"SANDBOX_TOKEN": "123456",
},
"TOKEN_LENGTH": 6,
"MESSAGE": "Welcome to {app}! Please use security code {security_code} to proceed.",
"APP_NAME": "Phone Verify",
"SECURITY_CODE_EXPIRATION_TIME": 1, # In seconds only
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,
"BACKEND": "phone_verify.backends.twilio.TwilioBackend",
"OPTIONS": {
"SID": "fake",
"SECRET": "fake",
"FROM": "+14755292729",
"SANDBOX_TOKEN": "123456",
},
"DEFAULT": {
"BACKEND": "phone_verify.backends.kavenegar.KavenegarBackend",
"OPTIONS": {
"API_KEY": "fake",
"SENDER": "+14755292729"
},
"TOKEN_LENGTH": 6,
"MESSAGE": "Welcome to {app}! Please use security code {security_code} to proceed.",
"APP_NAME": "Phone Verify",
"SECURITY_CODE_EXPIRATION_TIME": 1, # In seconds only
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,
}
"TOKEN_LENGTH": 6,
"MESSAGE": "Welcome to {app}! Please use security code {security_code} to proceed.",
"APP_NAME": "Phone Verify",
"SECURITY_CODE_EXPIRATION_TIME": 1, # In seconds only
"VERIFY_SECURITY_CODE_ONLY_ONCE": False,

},
}

0 comments on commit 6381fdc

Please sign in to comment.