diff --git a/backend/api/admin.py b/backend/api/admin.py index 8c38f3f..12e27bd 100644 --- a/backend/api/admin.py +++ b/backend/api/admin.py @@ -1,3 +1,19 @@ from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.models import User +from .models import UserProfile -# Register your models here. +class UserProfileInline(admin.StackedInline): + model = UserProfile + can_delete = False + verbose_name = 'Профиль пользователя' + verbose_name_plural = 'Профили пользователей' + fields = ('is_active', 'phone_number', 'birthday', 'country', 'city','privacy_accepted','newsletter', 'uuid', 'image', 'authMailCode','additionalDetails') + readonly_fields = ('uuid','authMailCode') # ридонли в админке + +class UserAdmin(BaseUserAdmin): + inlines = (UserProfileInline,) + +# перерегистрируем User +admin.site.unregister(User) +admin.site.register(User, UserAdmin) \ No newline at end of file diff --git a/backend/api/auth/__init__.py b/backend/api/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/api/auth/serializers.py b/backend/api/auth/serializers.py new file mode 100644 index 0000000..3a9e6f1 --- /dev/null +++ b/backend/api/auth/serializers.py @@ -0,0 +1,70 @@ +from rest_framework import serializers + +from django.contrib.auth.models import User +from django.db.utils import IntegrityError + +from api.models import UserProfile + +class UserResponceSerializer(serializers.Serializer): + id = serializers.IntegerField() + email = serializers.EmailField() + name = serializers.CharField(source='first_name') + surname = serializers.CharField(source='last_name') + phone_number = serializers.CharField(source='userprofile.phone_number') + image = serializers.CharField(source='userprofile.image') + uuid = serializers.SerializerMethodField() + def get_uuid(self, obj): + try: + return str(obj.userprofile.uuid)[:6] + except Exception as e: + print(f"Serializer UUID Error: {e}") # лог ошибки + return None + +class ClientRegisterSerializer(serializers.ModelSerializer): + phone_number = serializers.CharField(max_length=13) + privacy_accepted = serializers.BooleanField() + email = serializers.EmailField(required=True) + username = serializers.CharField(source='first_name') + uuid = serializers.SerializerMethodField() + + class Meta: + model = User + fields = ['id', 'uuid', 'username', 'email', 'password', 'phone_number', 'privacy_accepted'] + extra_kwargs = { + 'password' : {'write_only':True}, + 'email' : {'required' : True, 'unique': True}, + 'phone_number' : {'required' : True, 'unique': True}, + } + + def validate_phone_number(self, value): + if len(value) > 18: + raise serializers.ValidationError("Номер телефона не может быть таким длинным") + return value + + def validate_privacy_accepted(self, value): + if not value: + raise serializers.ValidationError("Необходимо принять условия политики конфиденциальности") + + def create(self, validated_data): + privacy_accepted = validated_data.pop('privacy_accepted') + phone_number = validated_data.pop('phone_number') + name = validated_data.pop('first_name') + + try: + user = User.objects.create_user( + username=validated_data['name'], + email=validated_data['email'], + password=validated_data['password'], + first_name = name, + ) + + UserProfile.objects.create( + user=user, + phone_number=phone_number, + privacy_accepted=privacy_accepted + ) + + return user + + except IntegrityError: + raise serializers.ValidationError({"email": "Пользователь с таким email уже существует"}) \ No newline at end of file diff --git a/backend/api/auth/views.py b/backend/api/auth/views.py new file mode 100644 index 0000000..f650b88 --- /dev/null +++ b/backend/api/auth/views.py @@ -0,0 +1,6 @@ +from rest_framework import serializers + +from django.contrib.auth.models import User +from django.db.utils import IntegrityError +from django.contrib.auth.hashers import make_password + diff --git a/backend/api/migrations/0001_initial.py b/backend/api/migrations/0001_initial.py new file mode 100644 index 0000000..7a2ebb4 --- /dev/null +++ b/backend/api/migrations/0001_initial.py @@ -0,0 +1,36 @@ +# Generated by Django 5.2.1 on 2025-05-18 08:57 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='UserProfile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_active', models.BooleanField(default=True)), + ('phone_number', models.CharField(max_length=13)), + ('birthday', models.DateField(blank=True, null=True)), + ('privacy_accepted', models.BooleanField(default=False)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, null=True)), + ('image', models.ImageField(blank=True, null=True, upload_to='')), + ('country', models.CharField(blank=True, max_length=15, null=True)), + ('city', models.CharField(blank=True, max_length=35, null=True)), + ('newsletter', models.BooleanField(default=False)), + ('authMailCode', models.CharField(max_length=50)), + ('additionalDetails', models.TextField(blank=True, null=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index 71a8362..063ed0f 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -1,3 +1,20 @@ +from django.contrib.auth.models import User from django.db import models +import uuid -# Create your models here. +class UserProfile(models.Model): + user = models.OneToOneField(User, on_delete=models.CASCADE) + is_active = models.BooleanField(default=True) + phone_number = models.CharField(max_length=13, verbose_name="Номер телефона") + birthday = models.DateField(null=True, blank=True, verbose_name="Дата рождения") + privacy_accepted = models.BooleanField(default=False, verbose_name="Согласие с политикой конфиденциальности") + uuid = models.UUIDField(default=uuid.uuid4, editable=False, null=True) + image = models.ImageField(null=True, blank=True) + country = models.CharField(max_length=15,null=True, blank=True, verbose_name="Страна") + city = models.CharField(max_length=35, null=True, blank=True, verbose_name="Город") + newsletter = models.BooleanField(default=False, verbose_name="Подписка на новостную рассылку") + authMailCode = models.CharField(max_length=50) + additionalDetails = models.TextField(null=True, blank=True, verbose_name="Дополнительные детали") + + def __str__(self): + return {self.phone_number} \ No newline at end of file diff --git a/backend/sitemanagement/migrations/0009_alter_news_slug_alter_news_titleimage.py b/backend/sitemanagement/migrations/0009_alter_news_slug_alter_news_titleimage.py new file mode 100644 index 0000000..517979a --- /dev/null +++ b/backend/sitemanagement/migrations/0009_alter_news_slug_alter_news_titleimage.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.1 on 2025-05-18 08:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sitemanagement', '0008_alter_news_slug'), + ] + + operations = [ + migrations.AlterField( + model_name='news', + name='slug', + field=models.SlugField(blank=True, editable=False, max_length=255, null=True), + ), + migrations.AlterField( + model_name='news', + name='titleImage', + field=models.ImageField(upload_to='uploads/news/images/', verbose_name='Главная картинка'), + ), + ] diff --git a/frontend/app/(urls)/privacy-policy/page.tsx b/frontend/app/(urls)/privacy-policy/page.tsx new file mode 100644 index 0000000..2868bf2 --- /dev/null +++ b/frontend/app/(urls)/privacy-policy/page.tsx @@ -0,0 +1,7 @@ +import React from 'react' + +const page = () => { + return
page
+} + +export default page diff --git a/frontend/app/(urls)/register/page.tsx b/frontend/app/(urls)/register/page.tsx index 3d53313..4df568e 100644 --- a/frontend/app/(urls)/register/page.tsx +++ b/frontend/app/(urls)/register/page.tsx @@ -27,9 +27,7 @@ const RegisterPage = () => { return (
-

- Давайте познакомимся поближе! -

+

Давайте познакомимся поближе!