profile end points user model otp stuff base

This commit is contained in:
Parsa Nazer
2024-12-13 23:02:19 +03:30
parent eef8263869
commit 259099cb9e
16 changed files with 425 additions and 7 deletions
+7 -1
View File
@@ -1,3 +1,9 @@
from django.contrib import admin from django.contrib import admin
from .models import *
from unfold.admin import ModelAdmin
# Register your models here.
@admin.register(User)
class UserAdmin(ModelAdmin):
list_display = ['phone', 'email', 'is_superuser']
readonly_fields = ['password', 'last_login', 'otp_expiry']
@@ -0,0 +1,39 @@
# Generated by Django 5.1.2 on 2024-12-13 17:49
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.BigAutoField(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')),
('email', models.EmailField(max_length=255, unique=True, verbose_name='ایمیل')),
('phone_number', models.CharField(max_length=12, unique=True, verbose_name='شماره تماس')),
('first_name', models.CharField(blank=True, max_length=50, verbose_name='نام')),
('last_name', models.CharField(blank=True, max_length=50, verbose_name='نام خانوادگی')),
('profile_photo', models.ImageField(blank=True, null=True, upload_to='profile_photos/', verbose_name='عکس پروفایل')),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=False)),
('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')),
('otp', models.CharField(blank=True, max_length=6, null=True, verbose_name='تاریخ ثبتنام')),
('otp_expiry', models.DateTimeField(blank=True, null=True, verbose_name='تاریخ تمام شدن otp')),
('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={
'abstract': False,
},
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-12-13 17:51
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='phone_number',
new_name='phone',
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-12-13 17:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0002_rename_phone_number_user_phone'),
]
operations = [
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(max_length=255, verbose_name='ایمیل'),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-12-13 19:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0003_alter_user_email'),
]
operations = [
migrations.AlterField(
model_name='user',
name='email',
field=models.EmailField(blank=True, max_length=255, null=True, verbose_name='ایمیل'),
),
]
@@ -0,0 +1,21 @@
# Generated by Django 5.1.2 on 2024-12-13 19:13
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0004_alter_user_email'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='groups',
),
migrations.RemoveField(
model_name='user',
name='user_permissions',
),
]
+98 -1
View File
@@ -1,3 +1,100 @@
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _
import random
from datetime import datetime, timedelta
from django.utils import timezone
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken, OutstandingToken
class UserManager(BaseUserManager):
def create_user(self, phone, password=None):
if not phone:
raise ValueError('Users must have a phone number')
user = self.model(
phone=phone,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, phone, password=None):
user = self.create_user(
phone=phone,
)
user.is_staff = True
user.is_superuser = True
user.set_password(password)
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, verbose_name='ایمیل', blank=True, null=True)
phone = models.CharField(max_length=12, verbose_name='شماره تماس', unique=True)
first_name = models.CharField(max_length=50, blank=True, verbose_name='نام')
last_name = models.CharField(max_length=50, blank=True, verbose_name='نام خانوادگی')
profile_photo = models.ImageField(upload_to='profile_photos/', null=True, blank=True, verbose_name='عکس پروفایل')
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
otp = models.CharField(max_length=6, blank=True, null=True, verbose_name='تاریخ ثبتنام')
otp_expiry = models.DateTimeField(blank=True, null=True, verbose_name='تاریخ تمام شدن otp')
objects = UserManager()
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = []
@property
def groups(self):
return None
@property
def user_permissions(self):
return None
def set_otp(self):
self.otp = str(random.randint(100000, 999999))
self.otp_expiry = timezone.now() + timedelta(minutes=5)
self.save()
def clear_otp(self):
self.otp = None
self.otp_expiry = None
self.save()
def verify_otp(self, otp_code):
if self.otp == otp_code and self.otp_expiry > timezone.now():
return True
return False
def blacklist_user_tokens(self):
try:
tokens = OutstandingToken.objects.filter(user=self)
for token in tokens:
BlacklistedToken.objects.get_or_create(token=token)
print('done')
except Exception as e:
print(f"ridi dadash")
def __str__(self):
if self.first_name and self.last_name:
return f'{self.first_name} {self.last_name}'
else:
return self.email
def get_name(self):
if self.first_name and self.last_name:
return f'{self.first_name} {self.last_name}'
else:
return self.email
# Create your models here.
+11
View File
@@ -0,0 +1,11 @@
from .models import *
from rest_framework import serializers
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'profile_photo', 'phone']
read_only_fields = ("phone",)
+6
View File
@@ -0,0 +1,6 @@
from django.urls import path
from . import views
urlpatterns = [
path('profile', views.ProfileView.as_view()),
]
+20 -1
View File
@@ -1,3 +1,22 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.views import APIView
from .serializers import ProfileSerializer
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
from rest_framework.response import Response
class ProfileView(APIView):
serializer_class = ProfileSerializer
permission_classes = [IsAuthenticated]
def get(self, request):
user_ser = self.serializer_class(instance=request.user)
return Response(user_ser.data, status=status.HTTP_200_OK)
# Create your views here.
def patch(self, request):
user = request.user
user_ser = self.serializer_class(user, data=request.data, partial=True)
if user_ser.is_valid():
user_ser.save()
return Response(user_ser.data)
return Response(user_ser.errors, status=status.HTTP_400_BAD_REQUEST)
+25 -3
View File
@@ -94,7 +94,9 @@ INSTALLED_APPS = [
'rest_framework.authtoken', 'rest_framework.authtoken',
'djoser', 'djoser',
# custom apps # custom apps
'product' 'product',
'account',
'entertainment',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@@ -278,7 +280,7 @@ UNFOLD = {
{ {
"title": _("محصولات"), "title": _("محصولات"),
"icon": "redeem", "icon": "redeem",
"link": reverse_lazy("admin:product_product_changelist"), "link": reverse_lazy("admin:product_productmodel_changelist"),
}, },
# esm category model ro lower case bezar inja amir # esm category model ro lower case bezar inja amir
@@ -296,12 +298,32 @@ UNFOLD = {
], ],
}, },
{
"title": _("بخش کاربران و مشتریان"),
"separator": True,
"collapsible": True,
"items": [
{
"title": _("users"),
"icon": "person",
"link": reverse_lazy("admin:account_user_changelist"),
},
],
},
], ],
}, },
} }
AUTH_USER_MODEL = 'account.User'
def environment_callback(request): def environment_callback(request):
return ["Development", "warning"] return ["Development", "warning"]
+2
View File
@@ -5,6 +5,7 @@ from drf_spectacular.views import SpectacularSwaggerView, SpectacularAPIView
from django.conf import settings from django.conf import settings
from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView
from product import views from product import views
urlpatterns = [ urlpatterns = [
# djoser # djoser
@@ -18,6 +19,7 @@ urlpatterns = [
path('schema/', SpectacularAPIView.as_view(), name='schema'), path('schema/', SpectacularAPIView.as_view(), name='schema'),
# path('comment/<int:pk>', views.CommentView.as_view(), name='comment-list'), # path('comment/<int:pk>', views.CommentView.as_view(), name='comment-list'),
path('products/', include('product.urls')), path('products/', include('product.urls')),
path('accounts/', include('account.urls')),
path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), path('', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
] ]
@@ -0,0 +1,141 @@
# Generated by Django 5.1.2 on 2024-12-13 17:49
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='abjad',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('word', models.TextField(verbose_name='صورت ی سوال')),
('image', models.ImageField(blank=True, null=True, upload_to='media/', verbose_name='عکس بازی افتابه')),
('difficulty_type', models.CharField(choices=[('hard', 'سخت'), ('normal', 'متوسط'), ('easy', 'اسون')], max_length=13, verbose_name='سختی')),
('answer', models.CharField(max_length=30, verbose_name='جواب')),
('option2', models.CharField(blank=True, max_length=30, null=True, verbose_name='گزینه ی اشتباه')),
('option3', models.CharField(blank=True, max_length=30, null=True, verbose_name='گزینه ی اشتباه')),
('option4', models.CharField(blank=True, max_length=30, null=True, verbose_name='گزینه ی اشتباه')),
],
options={
'verbose_name': 'سوال ابجد',
'verbose_name_plural': 'سوالات ابجد',
},
),
migrations.CreateModel(
name='challenge',
fields=[
('type', models.CharField(choices=[('map', 'نقشه ی گنج'), ('prize', 'جوایز')], max_length=30, primary_key=True, serialize=False, verbose_name='نوع چالش')),
('image', models.ImageField(upload_to='media/', verbose_name='عکس')),
('link', models.URLField(verbose_name='لینک')),
('text', models.TextField(verbose_name='متن توضیحات')),
('button_text', models.CharField(max_length=40, verbose_name='متن دکمه')),
],
options={
'verbose_name': 'چالش',
'verbose_name_plural': 'چالش ها',
},
),
migrations.CreateModel(
name='Dare',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lang1', models.CharField(max_length=200, verbose_name='فارسی')),
('is_for_adults', models.BooleanField(verbose_name='+18 سوال')),
],
options={
'verbose_name': 'شجاعت',
'verbose_name_plural': 'شجاعت ها',
},
),
migrations.CreateModel(
name='MovieCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=40, verbose_name='نام دسته بندی')),
],
options={
'verbose_name': 'دسته بندی قیلم',
'verbose_name_plural': 'دسته بندی فیلم ها',
},
),
migrations.CreateModel(
name='UploadParent',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=300, verbose_name='نام')),
('message_id', models.CharField(max_length=40, verbose_name='ای دی پیام تلگرام')),
],
),
migrations.CreateModel(
name='MusicCategory',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=40, verbose_name='نام دسته بندی')),
],
options={
'verbose_name': 'دسته بندی موزیک',
'verbose_name_plural': 'دسته بندی موزیک ها',
},
),
migrations.CreateModel(
name='Truth',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lang1', models.CharField(max_length=200, verbose_name='فارسی')),
('is_for_adults', models.BooleanField(verbose_name='+18 سوال')),
],
options={
'verbose_name': 'حقیقت',
'verbose_name_plural': 'حقیقت ها',
},
),
migrations.CreateModel(
name='Would_you_rather',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('lang1', models.CharField(max_length=200, verbose_name='فارسی')),
('is_for_adults', models.BooleanField(verbose_name='+18 سوال')),
],
options={
'verbose_name': 'ترجیح میدی',
'verbose_name_plural': 'ترجیح میدی ها',
},
),
migrations.CreateModel(
name='MovieModel',
fields=[
('uploadparent_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='entertainment.uploadparent')),
('description', models.CharField(blank=True, max_length=4000, null=True, verbose_name='توضیحات فیلم')),
('receommended', models.BooleanField(default=False, verbose_name='پیشنهادی')),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='entertainment.moviecategory', verbose_name='دسته بندی')),
],
options={
'verbose_name': 'مدل فیلم',
'verbose_name_plural': 'مدل فیلم ها',
},
bases=('entertainment.uploadparent',),
),
migrations.CreateModel(
name='MusicModel',
fields=[
('uploadparent_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='entertainment.uploadparent')),
('lyric', models.CharField(blank=True, max_length=4000, null=True, verbose_name='متن اهنگ')),
('singer', models.CharField(blank=True, max_length=300, null=True, verbose_name='خواننده')),
('trand', models.BooleanField(default=False, verbose_name='ترند')),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='entertainment.musiccategory', verbose_name='دسته بندی')),
],
options={
'verbose_name': 'مدل اهنگ',
'verbose_name_plural': 'مدل اهنگ ها',
},
bases=('entertainment.uploadparent',),
),
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
from django.db import models from django.db import models
from django.utils.text import slugify from django.utils.text import slugify
from django.contrib.auth.models import User from account.models import User
from django.urls import reverse from django.urls import reverse
class CategoryModel(models.Model): class CategoryModel(models.Model):