Base SMS integration
This commit is contained in:
parent
c75e3c56eb
commit
4edbf8a922
10 changed files with 105 additions and 3 deletions
|
@ -3,6 +3,9 @@ from django.conf import settings
|
|||
from geopy.geocoders import Nominatim
|
||||
|
||||
import uuid
|
||||
import string
|
||||
|
||||
from random import SystemRandom
|
||||
|
||||
def name_to_coords(name):
|
||||
geocoder = Nominatim(user_agent="JourneyJoker.at")
|
||||
|
@ -15,4 +18,8 @@ def profile_to_coords(profile):
|
|||
return name_to_coords("%s, %s, %s, %s" % (profile.street, profile.city, profile.zip, profile.country))
|
||||
|
||||
def upload_path(instance, filename):
|
||||
return f'userfiles/{instance.user.id}/{uuid.uuid4()}/{filename}'
|
||||
return f'userfiles/{instance.user.id}/{uuid.uuid4()}/{filename}'
|
||||
|
||||
def generate_token(length=6, characters=string.digits):
|
||||
return "".join([SystemRandom().choice(characters) for _ in range(length)])
|
||||
|
|
@ -6,6 +6,7 @@ from django.utils import timezone
|
|||
|
||||
from django_countries.fields import CountryField
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
from polymorphic.models import PolymorphicModel
|
||||
|
||||
from .helpers import profile_to_coords, upload_path
|
||||
|
||||
|
@ -62,6 +63,16 @@ class User(AbstractBaseUser):
|
|||
has_module_perms = has_permission
|
||||
has_perm = has_permission
|
||||
|
||||
@property
|
||||
def phone(self):
|
||||
try:
|
||||
return self.clientprofile.phone
|
||||
except:
|
||||
try:
|
||||
return self.partnerprofile.phone
|
||||
except:
|
||||
return None
|
||||
|
||||
class AddressMixin(models.Model):
|
||||
street = models.CharField("Straße", max_length=64)
|
||||
city = models.CharField("Stadt", max_length=64)
|
||||
|
@ -110,7 +121,7 @@ class PersonMixin(models.Model):
|
|||
abstract = True
|
||||
|
||||
class Profile(PersonMixin, AddressMixin, PhoneMixin):
|
||||
user = models.OneToOneField(User, models.CASCADE)
|
||||
user = models.OneToOneField(get_user_model(), models.CASCADE)
|
||||
verified = models.BooleanField(default=False)
|
||||
enabled = models.BooleanField(default=True)
|
||||
|
||||
|
@ -124,4 +135,17 @@ class Profile(PersonMixin, AddressMixin, PhoneMixin):
|
|||
return name
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
abstract = True
|
||||
|
||||
class TwoFactor(PolymorphicModel):
|
||||
user = models.ForeignKey(User, models.CASCADE)
|
||||
|
||||
@classmethod
|
||||
def initiate(cls, user):
|
||||
raise NotImplementedError("%s does not implement initiate()" % cls.__name__)
|
||||
|
||||
def send_token(self, description=""):
|
||||
return True
|
||||
|
||||
def validate_token(self, token):
|
||||
raise NotImplementedError("%s does not implement validate_token()" % cls.__name__)
|
|
@ -19,4 +19,5 @@ staticmap
|
|||
django-mathfilters
|
||||
fast-luhn
|
||||
kumisms
|
||||
django-filtersignals
|
||||
git+https://kumig.it/kumisystems/PyInvoice
|
0
sms/__init__.py
Normal file
0
sms/__init__.py
Normal file
3
sms/admin.py
Normal file
3
sms/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
sms/apps.py
Normal file
6
sms/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SmsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'sms'
|
14
sms/functions.py
Normal file
14
sms/functions.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
import kumisms
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
def sendMessage(recipients: list, content: str, api_key=None):
|
||||
api_key = api_key or getValue("kumisms.api.key")
|
||||
gateway = kumisms.KumiSMS(api_key)
|
||||
|
||||
for recipient in recipients:
|
||||
gateway.send(recipient, content)
|
||||
|
||||
def sendMessageToUsers(users: list, content: str, api_key=None):
|
||||
recipients = [user.phone for user in users]
|
||||
return sendMessage(recipients, content, api_key)
|
41
sms/models.py
Normal file
41
sms/models.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from localauth.models import TwoFactor
|
||||
from localauth.helpers import generate_token
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
from .functions import sendMessage
|
||||
|
||||
class SMSTwoFactor(TwoFactor):
|
||||
@classmethod
|
||||
def initiate(cls, user):
|
||||
if user.phone:
|
||||
cls.objects.get_or_create(user=user)
|
||||
|
||||
def send_token(self, description="%s"):
|
||||
token = SMSTwoFactorToken.objects.create(user=self)
|
||||
sendMessageToUsers([user], description % token)
|
||||
|
||||
def validate_token(self, token):
|
||||
tokens = SMSTwoFactorToken.objects.filter(
|
||||
user=self,
|
||||
token=token,
|
||||
used=False,
|
||||
created__gte=timezone.now() - timedelta(seconds=getValue("sms.token.maxage", 300))
|
||||
).all()
|
||||
|
||||
if tokens:
|
||||
tokens.update(used=True)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
class SMSTwoFactorToken(models.Model):
|
||||
user = models.ForeignKey(SMSTwoFactor, models.CASCADE)
|
||||
token = models.CharField(max_length=256, default=generate_token)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
used = models.BooleanField(default=False)
|
3
sms/tests.py
Normal file
3
sms/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
3
sms/views.py
Normal file
3
sms/views.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
Loading…
Reference in a new issue