From 05e6f80b6d62720b8edc4702101d9ce8dad9ff58 Mon Sep 17 00:00:00 2001 From: mahdavi Date: Sun, 8 Mar 2020 15:13:49 +0330 Subject: [PATCH] use uuid instead of code --- apps/transactions/migrations/0001_initial.py | 32 ----------- .../migrations/0002_auto_20191213_1423.py | 32 ----------- apps/transactions/models.py | 8 ++- apps/users/admin.py | 4 +- apps/users/migrations/0001_initial.py | 56 ------------------- apps/users/models.py | 56 +++++++++++-------- apps/users/serializers.py | 16 +++--- apps/users/views.py | 2 +- {accounts => gooyal_accounts}/__init__.py | 0 {accounts => gooyal_accounts}/settings.py | 6 +- {accounts => gooyal_accounts}/urls.py | 4 +- {accounts => gooyal_accounts}/wsgi.py | 4 +- manage.py | 2 +- 13 files changed, 56 insertions(+), 166 deletions(-) delete mode 100644 apps/transactions/migrations/0001_initial.py delete mode 100644 apps/transactions/migrations/0002_auto_20191213_1423.py delete mode 100644 apps/users/migrations/0001_initial.py rename {accounts => gooyal_accounts}/__init__.py (100%) rename {accounts => gooyal_accounts}/settings.py (96%) rename {accounts => gooyal_accounts}/urls.py (95%) rename {accounts => gooyal_accounts}/wsgi.py (71%) diff --git a/apps/transactions/migrations/0001_initial.py b/apps/transactions/migrations/0001_initial.py deleted file mode 100644 index b4f3800..0000000 --- a/apps/transactions/migrations/0001_initial.py +++ /dev/null @@ -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)), - ], - ), - ] diff --git a/apps/transactions/migrations/0002_auto_20191213_1423.py b/apps/transactions/migrations/0002_auto_20191213_1423.py deleted file mode 100644 index 23f6e1d..0000000 --- a/apps/transactions/migrations/0002_auto_20191213_1423.py +++ /dev/null @@ -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')}, - ), - ] diff --git a/apps/transactions/models.py b/apps/transactions/models.py index 04e4feb..9c79708 100755 --- a/apps/transactions/models.py +++ b/apps/transactions/models.py @@ -1,14 +1,16 @@ import datetime import random +import uuid from django.db import models +from django.db import transaction from django.db.models import F 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 rest_framework.exceptions import APIException, ValidationError +from apps.users.models import User + class TransactionManager(models.Manager): def create_transaction(self, @@ -51,7 +53,7 @@ class Transaction(models.Model): (4, 'failed', 'failed'), (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 amount = models.IntegerField(_('amount'), blank=False) delay = models.IntegerField(default=0, blank=True) # number of days for delayed payments diff --git a/apps/users/admin.py b/apps/users/admin.py index 058bc7a..59bcb9e 100644 --- a/apps/users/admin.py +++ b/apps/users/admin.py @@ -4,6 +4,7 @@ from .models import User class UserAdmin(admin.ModelAdmin): fields = [ + 'uuid', 'name', 'avatar', 'is_active', @@ -12,7 +13,6 @@ class UserAdmin(admin.ModelAdmin): 'username', 'email', 'phone_number', - 'code', 'password', 'otp', 'is_staff', @@ -26,7 +26,7 @@ class UserAdmin(admin.ModelAdmin): 'otp_try', 'balance', ] - readonly_fields = ['last_update'] + readonly_fields = ['last_update', 'uuid'] admin.site.register(User, UserAdmin) diff --git a/apps/users/migrations/0001_initial.py b/apps/users/migrations/0001_initial.py deleted file mode 100644 index 786af23..0000000 --- a/apps/users/migrations/0001_initial.py +++ /dev/null @@ -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()), - ], - ), - ] diff --git a/apps/users/models.py b/apps/users/models.py index ec598ce..71861f6 100644 --- a/apps/users/models.py +++ b/apps/users/models.py @@ -8,6 +8,7 @@ from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ from rest_framework.exceptions import APIException +import uuid 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.set_password(password) user.set_otp() - user.set_code() user.date_joined = timezone.now() user.save(using=self._db) @@ -58,16 +58,25 @@ class UserManager(BaseUserManager): class User(AbstractUser): - # id - # first_name - # last_name - # email - # is_staff - # is_active - # password - + uuid = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, unique=True, db_index=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 = models.CharField( _('username'), @@ -93,11 +102,10 @@ class User(AbstractUser): iban_verified = models.BooleanField(null=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_login - # date_joined + last_login = models.DateTimeField(_('last login'), blank=True, null=True) + date_joined = models.DateTimeField(_('date joined'), default=timezone.now) objects = UserManager() @@ -111,16 +119,16 @@ class User(AbstractUser): self.otp_expire = timezone.now() + timedelta(minutes=5) self.otp_try = 0 - def set_code(self): - for code in random.sample(range(10000, 100000), 90000): - try: - code = str(code) - self.code = code - return self.save() - except: - pass - - raise APIException('system error') + # def set_code(self): + # for code in random.sample(range(10000, 100000), 90000): + # try: + # code = str(code) + # self.code = code + # return self.save() + # except: + # pass + # + # raise APIException('system error') def otp_is_valid(self): return bool(self.otp and timezone.now() <= self.otp_expire) @@ -160,4 +168,4 @@ class User(AbstractUser): return True def __str__(self): - return f"{self.code} - {self.username}" + return f"{self.pk} - {self.username}" diff --git a/apps/users/serializers.py b/apps/users/serializers.py index dcb8dfd..77476ec 100644 --- a/apps/users/serializers.py +++ b/apps/users/serializers.py @@ -7,20 +7,20 @@ from django.utils import timezone class PublicUserSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ('avatar', 'name', 'username', 'email', "first_name", "last_name", "code") - read_only_fields = ['avatar', 'name', 'username', 'email', 'first_name', 'last_name'] + fields = ('avatar', 'name', 'username', 'email', "first_name", "last_name", "uuid") + read_only_fields = ['avatar', 'name', 'username', 'email', 'first_name', 'last_name', "uuid"] - def to_internal_value(self, data): - code = data.get('code') - if code: - return User.objects.get(code=code) + # def to_internal_value(self, data): + # code = data.get('code') + # if code: + # return User.objects.get(code=code) class AccountSerializer(serializers.ModelSerializer): class Meta: model = User fields = ( - "code", + "uuid", 'username', 'email', 'phone_number', @@ -32,7 +32,7 @@ class AccountSerializer(serializers.ModelSerializer): 'iban', '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): diff --git a/apps/users/views.py b/apps/users/views.py index 8ac4f8d..e05f862 100644 --- a/apps/users/views.py +++ b/apps/users/views.py @@ -18,7 +18,7 @@ class UserDetailView(generics.RetrieveAPIView): permission_classes = [permissions.IsAuthenticated, IsAuthenticatedOrTokenHasScope] queryset = User.objects.all() serializer_class = PublicUserSerializer - lookup_field = 'code' + lookup_field = 'uuid' required_scopes = [] diff --git a/accounts/__init__.py b/gooyal_accounts/__init__.py similarity index 100% rename from accounts/__init__.py rename to gooyal_accounts/__init__.py diff --git a/accounts/settings.py b/gooyal_accounts/settings.py similarity index 96% rename from accounts/settings.py rename to gooyal_accounts/settings.py index 6d94e5a..dc0eb5e 100644 --- a/accounts/settings.py +++ b/gooyal_accounts/settings.py @@ -1,5 +1,5 @@ """ -Django settings for accounts project. +Django settings for gooyal_accounts project. Generated by 'django-admin startproject' using Django 2.2. @@ -76,7 +76,7 @@ REST_FRAMEWORK = { 'PAGE_SIZE': 10 } -ROOT_URLCONF = 'accounts.urls' +ROOT_URLCONF = 'gooyal_accounts.urls' TEMPLATES = [ { @@ -94,7 +94,7 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = 'accounts.wsgi.application' +WSGI_APPLICATION = 'gooyal_accounts.wsgi.application' # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases diff --git a/accounts/urls.py b/gooyal_accounts/urls.py similarity index 95% rename from accounts/urls.py rename to gooyal_accounts/urls.py index 9004df0..f372e79 100644 --- a/accounts/urls.py +++ b/gooyal_accounts/urls.py @@ -1,4 +1,4 @@ -"""accounts URL Configuration +"""gooyal_accounts URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: 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('users/', UserListView.as_view()), - path('users//', UserDetailView.as_view(), name='user_detail'), + path('users//', UserDetailView.as_view(), name='user_detail'), path('account/', AccountView.as_view(), name='account'), path('request_otp/', RequestOTPView.as_view(), name='register'), path('change_password/', ChangePasswordView.as_view(), name='change_password'), diff --git a/accounts/wsgi.py b/gooyal_accounts/wsgi.py similarity index 71% rename from accounts/wsgi.py rename to gooyal_accounts/wsgi.py index d4e6b0e..695afd4 100644 --- a/accounts/wsgi.py +++ b/gooyal_accounts/wsgi.py @@ -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``. @@ -11,6 +11,6 @@ import os 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() diff --git a/manage.py b/manage.py index 7a22e43..51b0ba5 100644 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ import sys def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'accounts.settings') + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gooyal_accounts.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: