Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(phone_verify): Add Kavenegar backend #34

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5f3d7f6
ignore vscode files to commit
SepehrHasanabadi Dec 12, 2019
d9468a1
chore: using otp method of kavenegar
SepehrHasanabadi Dec 23, 2019
a061379
chore: using otp method of kavenegar
SepehrHasanabadi Dec 23, 2019
9c4b316
kavenegar api iranian OTP
SepehrHasanabadi Dec 29, 2019
5596a2e
feat(docs): Add Iranian sending message platform (Kavenegar)
SepehrHasanabadi Jan 19, 2020
7dcdc99
chore(*): Fix test case errors.
SepehrHasanabadi Jan 19, 2020
6659037
refactor(*): Change indentions form tab to space.
SepehrHasanabadi Jan 20, 2020
ccbb2e9
chore(): Upgrade requirements
SepehrHasanabadi Jan 25, 2020
ca42409
Merge branch 'upgrade' into kavenegar-api
SepehrHasanabadi Jan 25, 2020
6381fdc
refactor(): Phone verification in settings consists the active backend
SepehrHasanabadi Jan 25, 2020
de56ea4
refactor(*): Test coverage, code improvements.
SepehrHasanabadi Jan 26, 2020
5884cde
refactor(README): Add Kavenegar Docs to README.rst
SepehrHasanabadi Jan 26, 2020
53c2e27
refactor(*): Phone registration test have DRY approach.
SepehrHasanabadi Jan 27, 2020
87281a7
refactor(*): Test services for available backends, Alter exception ha…
SepehrHasanabadi Jan 30, 2020
ca4faad
refactor(init): Resolve flake8 error in test file __init__.
SepehrHasanabadi Jan 30, 2020
92681ff
Merge branch 'master' into kavenegar-api
CuriousLearner Feb 18, 2020
7f2e976
Update to Py3 syntax
CuriousLearner Feb 21, 2020
1847bac
Merge branch 'master' of github.com:CuriousLearner/django-phone-verif…
CuriousLearner Feb 21, 2020
e4532ba
Merge branch 'master' of github.com:CuriousLearner/django-phone-verif…
CuriousLearner Feb 21, 2020
c59e927
Merge branch 'master' of github.com:CuriousLearner/django-phone-verif…
gutsytechster Mar 10, 2020
391e505
fix: Modify sending sms parameters
SepehrHasanabadi Mar 28, 2020
d3aec32
Merge branch 'kavenegar-api' of github.com:SepehrHasanabadi/django-ph…
SepehrHasanabadi Mar 28, 2020
b1af51b
Merge branch 'master' into SepehrHasanabadi-kavenegar-api
CuriousLearner Apr 30, 2020
987cbca
refactor(gitignore): add idea folder to gitignore
SepehrHasanabadi May 17, 2020
facc894
fix(test): Modified kavenegar test_data
SepehrHasanabadi May 17, 2020
b10b1da
Merge branch 'kavenegar-api' of github.com:SepehrHasanabadi/django-ph…
SepehrHasanabadi May 17, 2020
0c45d81
fix(test): Modified tests, Create KavenegarException class.
SepehrHasanabadi May 18, 2020
18707fd
fix: modified test kavenegar, Add Kavenegar sandbox
SepehrHasanabadi May 19, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ venv.bak/

# mypy
.mypy_cache/

# vscode configuration
.vscode
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.get("BACKEND", None):
backend_import = settings.PHONE_VERIFICATION["BACKEND"]
if settings.PHONE_VERIFICATION['DEFAULT'].get("BACKEND", None):
backend_import = settings.PHONE_VERIFICATION['DEFAULT']["BACKEND"]

backend_cls = import_string(backend_import)
return backend_cls(**settings.PHONE_VERIFICATION["OPTIONS"])
return backend_cls(**settings.PHONE_VERIFICATION['DEFAULT']["OPTIONS"])
8 changes: 4 additions & 4 deletions phone_verify/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self, **settings):
self.exception_class = None

@abstractmethod
def send_sms(self, numbers, message):
def send_sms(self, number, message):
raise NotImplementedError()

@abstractmethod
Expand All @@ -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.get(
token_length = django_settings.PHONE_VERIFICATION['DEFAULT'].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.get(
if time_difference.seconds > django_settings.PHONE_VERIFICATION['DEFAULT'].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.get(
if stored_verification.is_verified and django_settings.PHONE_VERIFICATION['DEFAULT'].get(
"VERIFY_SECURITY_CODE_ONLY_ONCE"
):
return stored_verification, self.SECURITY_CODE_VERIFIED
Expand Down
48 changes: 48 additions & 0 deletions phone_verify/backends/kavenegar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import

# Third Party Stuff
from kavenegar import KavenegarAPI, APIException, HTTPException

# Local
from .base import BaseBackend


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 = KavenegarAPI(self._api_key)

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)

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)
58 changes: 29 additions & 29 deletions phone_verify/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,35 @@


class PhoneSerializer(serializers.Serializer):
phone_number = PhoneNumberField()
phone_number = PhoneNumberField()


class SMSVerificationSerializer(serializers.Serializer):
phone_number = PhoneNumberField(required=True)
SepehrHasanabadi marked this conversation as resolved.
Show resolved Hide resolved
session_token = serializers.CharField(required=True)
security_code = serializers.CharField(required=True)

def validate(self, attrs):
attrs = super().validate(attrs)
phone_number = attrs.get("phone_number", None)
security_code, session_token = (
attrs.get("security_code", None),
attrs.get("session_token", None),
)
backend = get_sms_backend(phone_number=phone_number)
verification, token_validatation = backend.validate_security_code(
security_code=security_code,
phone_number=phone_number,
session_token=session_token,
)

if verification is None:
raise serializers.ValidationError(_("Security code is not valid"))
elif token_validatation == backend.SESSION_TOKEN_INVALID:
raise serializers.ValidationError(_("Session Token mis-match"))
elif token_validatation == backend.SECURITY_CODE_EXPIRED:
raise serializers.ValidationError(_("Security code has expired"))
elif token_validatation == backend.SECURITY_CODE_VERIFIED:
raise serializers.ValidationError(_("Security code is already verified"))

return attrs
phone_number = PhoneNumberField(required=True)
session_token = serializers.CharField(required=True)
security_code = serializers.CharField(required=True)

def validate(self, attrs):
attrs = super().validate(attrs)
phone_number = attrs.get("phone_number", None)
security_code, session_token = (
attrs.get("security_code", None),
attrs.get("session_token", None),
)
backend = get_sms_backend(phone_number=phone_number)
verification, token_validatation = backend.validate_security_code(
security_code=security_code,
phone_number=phone_number,
session_token=session_token,
)

if verification is None:
raise serializers.ValidationError(_("Security code is not valid"))
elif token_validatation == backend.SESSION_TOKEN_INVALID:
raise serializers.ValidationError(_("Session Token mis-match"))
elif token_validatation == backend.SECURITY_CODE_EXPIRED:
raise serializers.ValidationError(_("Security code has expired"))
elif token_validatation == backend.SECURITY_CODE_VERIFIED:
raise serializers.ValidationError(_("Security code is already verified"))

return attrs
1 change: 1 addition & 0 deletions requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ python-dotenv==0.10.0
phonenumbers==8.10.2
django-phonenumber-field==2.1.0
twilio==6.21.0
kavenegar==1.1.2
4 changes: 2 additions & 2 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Testing
# -------------------------------------
pytest==4.2.1
pytest-django==3.4.4
pytest==5.3.1
pytest-django==3.7.0
pytest-cov==2.6.1

django-dynamic-fixture==2.0.0
Expand Down
4 changes: 2 additions & 2 deletions tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@


def create_verification(**kwargs):
SMSVerification = apps.get_model("phone_verify", "SMSVerification")
verification = G(SMSVerification, **kwargs)
sms_verification = apps.get_model("phone_verify", "SMSVerification")
verification = G(sms_verification, **kwargs)
return verification
Loading