use uuid instead of code
This commit is contained in:
parent
8471621bce
commit
05e6f80b6d
13 changed files with 56 additions and 166 deletions
|
|
@ -1,32 +0,0 @@
|
||||||
# Generated by Django 3.0 on 2019-12-06 20:24
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Transaction',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('code', models.IntegerField(verbose_name='code')),
|
|
||||||
('amount', models.IntegerField(verbose_name='amount')),
|
|
||||||
('delay', models.IntegerField(blank=True, default=0)),
|
|
||||||
('state', models.IntegerField(choices=[(1, 'created'), (2, 'delayed'), (3, 'pending'), (4, 'failed'), (5, 'done')], default=1)),
|
|
||||||
('create', models.DateTimeField(auto_now=True, null=True, verbose_name='create')),
|
|
||||||
('last_update', models.DateTimeField(auto_now=True, null=True, verbose_name='last update')),
|
|
||||||
('detail_id', models.IntegerField(blank=True, null=True, unique=True)),
|
|
||||||
('payee', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='receipts', to=settings.AUTH_USER_MODEL)),
|
|
||||||
('payer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='payments', to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
# Generated by Django 3.0 on 2019-12-13 14:23
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('transactions', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='transaction',
|
|
||||||
name='application_id',
|
|
||||||
field=models.IntegerField(blank=True, null=True, verbose_name='application ID'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='transaction',
|
|
||||||
name='code',
|
|
||||||
field=models.IntegerField(db_index=True, unique=True, verbose_name='code'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='transaction',
|
|
||||||
name='detail_id',
|
|
||||||
field=models.IntegerField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AlterUniqueTogether(
|
|
||||||
name='transaction',
|
|
||||||
unique_together={('application_id', 'detail_id')},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
import datetime
|
import datetime
|
||||||
import random
|
import random
|
||||||
|
import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db import transaction
|
||||||
from django.db.models import F
|
from django.db.models import F
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from apps.users.models import User
|
|
||||||
from django.db import transaction
|
|
||||||
from model_utils.choices import Choices
|
from model_utils.choices import Choices
|
||||||
from rest_framework.exceptions import APIException, ValidationError
|
from rest_framework.exceptions import APIException, ValidationError
|
||||||
|
|
||||||
|
from apps.users.models import User
|
||||||
|
|
||||||
|
|
||||||
class TransactionManager(models.Manager):
|
class TransactionManager(models.Manager):
|
||||||
def create_transaction(self,
|
def create_transaction(self,
|
||||||
|
|
@ -51,7 +53,7 @@ class Transaction(models.Model):
|
||||||
(4, 'failed', 'failed'),
|
(4, 'failed', 'failed'),
|
||||||
(5, 'done', 'done'),
|
(5, 'done', 'done'),
|
||||||
)
|
)
|
||||||
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True) # reserve_code
|
||||||
code = models.IntegerField(_('code'), blank=False, unique=True, db_index=True) # unique random number
|
code = models.IntegerField(_('code'), blank=False, unique=True, db_index=True) # unique random number
|
||||||
amount = models.IntegerField(_('amount'), blank=False)
|
amount = models.IntegerField(_('amount'), blank=False)
|
||||||
delay = models.IntegerField(default=0, blank=True) # number of days for delayed payments
|
delay = models.IntegerField(default=0, blank=True) # number of days for delayed payments
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from .models import User
|
||||||
|
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
fields = [
|
fields = [
|
||||||
|
'uuid',
|
||||||
'name',
|
'name',
|
||||||
'avatar',
|
'avatar',
|
||||||
'is_active',
|
'is_active',
|
||||||
|
|
@ -12,7 +13,6 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
'username',
|
'username',
|
||||||
'email',
|
'email',
|
||||||
'phone_number',
|
'phone_number',
|
||||||
'code',
|
|
||||||
'password',
|
'password',
|
||||||
'otp',
|
'otp',
|
||||||
'is_staff',
|
'is_staff',
|
||||||
|
|
@ -26,7 +26,7 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
'otp_try',
|
'otp_try',
|
||||||
'balance',
|
'balance',
|
||||||
]
|
]
|
||||||
readonly_fields = ['last_update']
|
readonly_fields = ['last_update', 'uuid']
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
# Generated by Django 2.2.7 on 2019-11-14 08:47
|
|
||||||
|
|
||||||
import apps.users.models
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0011_update_proxy_permissions'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='User',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
||||||
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
|
||||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
||||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
||||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
||||||
('name', models.CharField(blank=True, max_length=30, verbose_name='name')),
|
|
||||||
('username', models.CharField(blank=True, error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, null=True, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
||||||
('phone_number', models.CharField(blank=True, max_length=30, null=True, unique=True, verbose_name='phone number')),
|
|
||||||
('otp', models.CharField(blank=True, max_length=6, null=True, verbose_name='otp')),
|
|
||||||
('otp_expire', models.DateTimeField(blank=True, null=True, verbose_name='otp expire')),
|
|
||||||
('otp_try', models.IntegerField(blank=True, default=0, null=True, verbose_name='otp try')),
|
|
||||||
('last_checkout_request', models.DateTimeField(blank=True, max_length=30, null=True, verbose_name='otp expire')),
|
|
||||||
('balance', models.IntegerField(default=0, verbose_name='balance')),
|
|
||||||
('iban', models.CharField(blank=True, max_length=30, null=True)),
|
|
||||||
('iban_verified', models.BooleanField(null=True)),
|
|
||||||
('avatar', models.ImageField(blank=True, null=True, upload_to='avatars')),
|
|
||||||
('code', models.IntegerField(db_index=True, null=True, unique=True, verbose_name='code')),
|
|
||||||
('last_update', models.DateTimeField(auto_now=True, max_length=30, null=True, verbose_name='last update')),
|
|
||||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'user',
|
|
||||||
'verbose_name_plural': 'users',
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
managers=[
|
|
||||||
('objects', apps.users.models.UserManager()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
@ -8,6 +8,7 @@ from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
|
import uuid
|
||||||
|
|
||||||
from apps.users.constans import MAX_OTP_TRY, DEVELOPMENT_PHONE_NUMBERS
|
from apps.users.constans import MAX_OTP_TRY, DEVELOPMENT_PHONE_NUMBERS
|
||||||
|
|
||||||
|
|
@ -25,7 +26,6 @@ class UserManager(BaseUserManager):
|
||||||
user = self.model(phone_number=phone_number, username=username, email=email, **extra_fields)
|
user = self.model(phone_number=phone_number, username=username, email=email, **extra_fields)
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.set_otp()
|
user.set_otp()
|
||||||
user.set_code()
|
|
||||||
user.date_joined = timezone.now()
|
user.date_joined = timezone.now()
|
||||||
user.save(using=self._db)
|
user.save(using=self._db)
|
||||||
|
|
||||||
|
|
@ -58,16 +58,25 @@ class UserManager(BaseUserManager):
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
# id
|
uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=True)
|
||||||
# first_name
|
|
||||||
# last_name
|
|
||||||
# email
|
|
||||||
# is_staff
|
|
||||||
# is_active
|
|
||||||
# password
|
|
||||||
|
|
||||||
name = models.CharField(_('name'), max_length=30, blank=True)
|
name = models.CharField(_('name'), max_length=30, blank=True)
|
||||||
|
first_name = models.CharField(_('first name'), max_length=30, blank=True)
|
||||||
|
last_name = models.CharField(_('last name'), max_length=150, blank=True)
|
||||||
|
email = models.EmailField(_('email address'), blank=True)
|
||||||
|
is_staff = models.BooleanField(
|
||||||
|
_('staff status'),
|
||||||
|
default=False,
|
||||||
|
help_text=_('Designates whether the user can log into this admin site.'),
|
||||||
|
)
|
||||||
|
is_active = models.BooleanField(
|
||||||
|
_('active'),
|
||||||
|
default=True,
|
||||||
|
help_text=_(
|
||||||
|
'Designates whether this user should be treated as active. '
|
||||||
|
'Unselect this instead of deleting accounts.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
password = models.CharField(_('password'), max_length=128)
|
||||||
username_validator = UnicodeUsernameValidator()
|
username_validator = UnicodeUsernameValidator()
|
||||||
username = models.CharField(
|
username = models.CharField(
|
||||||
_('username'),
|
_('username'),
|
||||||
|
|
@ -93,11 +102,10 @@ class User(AbstractUser):
|
||||||
iban_verified = models.BooleanField(null=True)
|
iban_verified = models.BooleanField(null=True)
|
||||||
|
|
||||||
avatar = models.ImageField(upload_to='avatars', null=True, blank=True)
|
avatar = models.ImageField(upload_to='avatars', null=True, blank=True)
|
||||||
code = models.IntegerField(_('code'), unique=True, null=True, db_index=True) # unique random number
|
|
||||||
|
|
||||||
last_update = models.DateTimeField(_('last update'), max_length=30, blank=True, null=True, auto_now=True)
|
last_update = models.DateTimeField(_('last update'), max_length=30, blank=True, null=True, auto_now=True)
|
||||||
# last_login
|
last_login = models.DateTimeField(_('last login'), blank=True, null=True)
|
||||||
# date_joined
|
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
|
||||||
|
|
||||||
objects = UserManager()
|
objects = UserManager()
|
||||||
|
|
||||||
|
|
@ -111,16 +119,16 @@ class User(AbstractUser):
|
||||||
self.otp_expire = timezone.now() + timedelta(minutes=5)
|
self.otp_expire = timezone.now() + timedelta(minutes=5)
|
||||||
self.otp_try = 0
|
self.otp_try = 0
|
||||||
|
|
||||||
def set_code(self):
|
# def set_code(self):
|
||||||
for code in random.sample(range(10000, 100000), 90000):
|
# for code in random.sample(range(10000, 100000), 90000):
|
||||||
try:
|
# try:
|
||||||
code = str(code)
|
# code = str(code)
|
||||||
self.code = code
|
# self.code = code
|
||||||
return self.save()
|
# return self.save()
|
||||||
except:
|
# except:
|
||||||
pass
|
# pass
|
||||||
|
#
|
||||||
raise APIException('system error')
|
# raise APIException('system error')
|
||||||
|
|
||||||
def otp_is_valid(self):
|
def otp_is_valid(self):
|
||||||
return bool(self.otp and timezone.now() <= self.otp_expire)
|
return bool(self.otp and timezone.now() <= self.otp_expire)
|
||||||
|
|
@ -160,4 +168,4 @@ class User(AbstractUser):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.code} - {self.username}"
|
return f"{self.pk} - {self.username}"
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,20 @@ from django.utils import timezone
|
||||||
class PublicUserSerializer(serializers.ModelSerializer):
|
class PublicUserSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ('avatar', 'name', 'username', 'email', "first_name", "last_name", "code")
|
fields = ('avatar', 'name', 'username', 'email', "first_name", "last_name", "uuid")
|
||||||
read_only_fields = ['avatar', 'name', 'username', 'email', 'first_name', 'last_name']
|
read_only_fields = ['avatar', 'name', 'username', 'email', 'first_name', 'last_name', "uuid"]
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
# def to_internal_value(self, data):
|
||||||
code = data.get('code')
|
# code = data.get('code')
|
||||||
if code:
|
# if code:
|
||||||
return User.objects.get(code=code)
|
# return User.objects.get(code=code)
|
||||||
|
|
||||||
|
|
||||||
class AccountSerializer(serializers.ModelSerializer):
|
class AccountSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = (
|
fields = (
|
||||||
"code",
|
"uuid",
|
||||||
'username',
|
'username',
|
||||||
'email',
|
'email',
|
||||||
'phone_number',
|
'phone_number',
|
||||||
|
|
@ -32,7 +32,7 @@ class AccountSerializer(serializers.ModelSerializer):
|
||||||
'iban',
|
'iban',
|
||||||
'iban_verified',
|
'iban_verified',
|
||||||
)
|
)
|
||||||
read_only_fields = ['code', 'balance', 'email', 'phone_number', 'iban_verified']
|
read_only_fields = ['uuid', 'balance', 'email', 'phone_number', 'iban_verified']
|
||||||
|
|
||||||
|
|
||||||
class RequestOTPSerializer(serializers.ModelSerializer):
|
class RequestOTPSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class UserDetailView(generics.RetrieveAPIView):
|
||||||
permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope]
|
permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope]
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
serializer_class = PublicUserSerializer
|
serializer_class = PublicUserSerializer
|
||||||
lookup_field = 'code'
|
lookup_field = 'uuid'
|
||||||
required_scopes = []
|
required_scopes = []
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
Django settings for accounts project.
|
Django settings for gooyal_accounts project.
|
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 2.2.
|
Generated by 'django-admin startproject' using Django 2.2.
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ REST_FRAMEWORK = {
|
||||||
'PAGE_SIZE': 10
|
'PAGE_SIZE': 10
|
||||||
}
|
}
|
||||||
|
|
||||||
ROOT_URLCONF = 'accounts.urls'
|
ROOT_URLCONF = 'gooyal_accounts.urls'
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
|
|
@ -94,7 +94,7 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = 'accounts.wsgi.application'
|
WSGI_APPLICATION = 'gooyal_accounts.wsgi.application'
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""accounts URL Configuration
|
"""gooyal_accounts URL Configuration
|
||||||
|
|
||||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
https://docs.djangoproject.com/en/2.2/topics/http/urls/
|
https://docs.djangoproject.com/en/2.2/topics/http/urls/
|
||||||
|
|
@ -29,7 +29,7 @@ urlpatterns = [
|
||||||
path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')),
|
path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')),
|
||||||
|
|
||||||
path('users/', UserListView.as_view()),
|
path('users/', UserListView.as_view()),
|
||||||
path('users/<code>/', UserDetailView.as_view(), name='user_detail'),
|
path('users/<uuid>/', UserDetailView.as_view(), name='user_detail'),
|
||||||
path('account/', AccountView.as_view(), name='account'),
|
path('account/', AccountView.as_view(), name='account'),
|
||||||
path('request_otp/', RequestOTPView.as_view(), name='register'),
|
path('request_otp/', RequestOTPView.as_view(), name='register'),
|
||||||
path('change_password/', ChangePasswordView.as_view(), name='change_password'),
|
path('change_password/', ChangePasswordView.as_view(), name='change_password'),
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
"""
|
"""
|
||||||
WSGI config for accounts project.
|
WSGI config for gooyal_accounts project.
|
||||||
|
|
||||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
|
@ -11,6 +11,6 @@ import os
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'accounts.settings')
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gooyal_accounts.settings')
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
@ -5,7 +5,7 @@ import sys
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'accounts.settings')
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gooyal_accounts.settings')
|
||||||
try:
|
try:
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue