This commit is contained in:
2026-03-20 23:16:53 +03:30
parent 4c5b1298a0
commit a98189a7e9
20 changed files with 855 additions and 76 deletions
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class AccountConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "account"
+134
View File
@@ -0,0 +1,134 @@
# Generated by Django 5.2.11 on 2026-03-18 14:09
import django.contrib.auth.models
import django.contrib.auth.validators
import django.utils.timezone
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",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, 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"
),
),
(
"phone_number",
models.CharField(db_index=True, max_length=32, unique=True),
),
(
"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={
"db_table": "users",
},
managers=[
("objects", django.contrib.auth.models.UserManager()),
],
),
]
View File
+19
View File
@@ -0,0 +1,19 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
phone_number = models.CharField(
max_length=32,
unique=True,
db_index=True,
)
USERNAME_FIELD = "phone_number"
REQUIRED_FIELDS = ["username"]
class Meta:
db_table = "users"
def __str__(self):
return self.phone_number
+16 -17
View File
@@ -1,7 +1,6 @@
"""
Account API module.
CRUD endpoints for user account profile (first name, last name, phone numbers).
Profile update endpoint returns UpdateProfileResponse (code, msg, data: AuthUser).
CRUD endpoints for user account profile.
"""
from rest_framework import status
@@ -16,21 +15,13 @@ def _auth_user_to_data(user):
"""Build AuthUser-shaped dict from Django User."""
if user is None or not getattr(user, "pk", None):
return None
# return {
# "id": user.id,
# "username": getattr(user, "username", "") or "",
# "email": getattr(user, "email", "") or "",
# "first_name": getattr(user, "first_name", "") or "",
# "last_name": getattr(user, "last_name", "") or "",
# "phone_number": getattr(user, "phone_number", "") or "",
# }
return {
"id": 1,
"username": "testuser",
"email": "testuser@example.com",
"first_name": "Test",
"last_name": "User",
"phone_number": "09123456789",
"id": user.id,
"username": getattr(user, "username", "") or "",
"email": getattr(user, "email", "") or "",
"first_name": getattr(user, "first_name", "") or "",
"last_name": getattr(user, "last_name", "") or "",
"phone_number": getattr(user, "phone_number", "") or "",
}
@@ -46,8 +37,16 @@ class ProfileView(APIView):
def patch(self, request):
serializer = UpdateProfileSerializer(data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
# TODO: persist first_name, last_name, email via service layer
user = request.user
for field in ("first_name", "last_name", "email"):
if field in serializer.validated_data:
setattr(user, field, serializer.validated_data[field])
user.save(update_fields=[
f for f in ("first_name", "last_name", "email")
if f in serializer.validated_data
])
data = _auth_user_to_data(user)
if data is None:
data = {