Add initial implementations for forms and organization apps with serializers, factories, and admin configurations
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Failing after 5m5s
CI/CD Pipeline / Run Tests (push) Failing after 5m5s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
CI/CD Pipeline / Deploy to Server (push) Has been skipped

This commit is contained in:
2026-02-17 09:26:08 +01:00
parent fd2adf9ab4
commit 8ed3e1175c
119 changed files with 9091 additions and 0 deletions

181
src/apps/user/admin.py Normal file
View File

@@ -0,0 +1,181 @@
"""
Admin configuration for user app.
"""
from apps.user.models import Profile, User
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
class ProfileInline(admin.StackedInline):
"""Inline для профиля пользователя."""
model = Profile
can_delete = False
verbose_name_plural = "Профиль"
fk_name = "user"
fields = ["first_name", "last_name", "bio", "avatar", "date_of_birth"]
@admin.register(User)
class UserAdmin(BaseUserAdmin):
"""Admin для пользователей."""
inlines = [ProfileInline]
list_display = [
"username",
"email",
"phone",
"is_verified_badge",
"is_active_badge",
"is_staff",
"created_at",
]
list_filter = ["is_staff", "is_superuser", "is_active", "is_verified", "created_at"]
search_fields = ["username", "email", "phone"]
ordering = ["-created_at"]
list_per_page = 50
date_hierarchy = "created_at"
fieldsets = (
(None, {"fields": ("username", "password")}),
(
_("Personal info"),
{"fields": ("email", "phone")},
),
(
_("Permissions"),
{
"fields": (
"is_active",
"is_staff",
"is_superuser",
"is_verified",
"groups",
"user_permissions",
),
"classes": ("collapse",),
},
),
(
_("Important dates"),
{"fields": ("last_login", "date_joined", "created_at", "updated_at")},
),
)
add_fieldsets = (
(
None,
{
"classes": ("wide",),
"fields": (
"username",
"email",
"password1",
"password2",
"is_staff",
"is_active",
),
},
),
)
readonly_fields = ["created_at", "updated_at", "last_login", "date_joined"]
def is_verified_badge(self, obj):
"""Бейдж верификации."""
if obj.is_verified:
return format_html(
'<span style="color: white; background: #28a745; padding: 3px 10px; '
'border-radius: 3px;">✓</span>'
)
return format_html(
'<span style="color: white; background: #dc3545; padding: 3px 10px; '
'border-radius: 3px;">✗</span>'
)
is_verified_badge.short_description = "Верифицирован"
is_verified_badge.admin_order_field = "is_verified"
def is_active_badge(self, obj):
"""Бейдж активности."""
if obj.is_active:
return format_html(
'<span style="color: white; background: #28a745; padding: 3px 10px; '
'border-radius: 3px;">Активен</span>'
)
return format_html(
'<span style="color: white; background: #dc3545; padding: 3px 10px; '
'border-radius: 3px;">Неактивен</span>'
)
is_active_badge.short_description = "Статус"
is_active_badge.admin_order_field = "is_active"
actions = ["verify_users", "unverify_users", "activate_users", "deactivate_users"]
@admin.action(description="Верифицировать выбранных пользователей")
def verify_users(self, request, queryset):
updated = queryset.update(is_verified=True)
self.message_user(request, f"Верифицировано {updated} пользователей")
@admin.action(description="Снять верификацию")
def unverify_users(self, request, queryset):
updated = queryset.update(is_verified=False)
self.message_user(request, f"Снята верификация у {updated} пользователей")
@admin.action(description="Активировать пользователей")
def activate_users(self, request, queryset):
updated = queryset.update(is_active=True)
self.message_user(request, f"Активировано {updated} пользователей")
@admin.action(description="Деактивировать пользователей")
def deactivate_users(self, request, queryset):
updated = queryset.update(is_active=False)
self.message_user(request, f"Деактивировано {updated} пользователей")
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
"""Admin для профилей."""
list_display = [
"user",
"full_name",
"date_of_birth",
"has_avatar",
"created_at",
]
list_filter = ["created_at"]
search_fields = ["user__username", "user__email", "first_name", "last_name"]
readonly_fields = ["created_at", "updated_at"]
ordering = ["-created_at"]
list_per_page = 50
raw_id_fields = ["user"]
fieldsets = (
("Пользователь", {"fields": ("user",)}),
(
"Личная информация",
{"fields": ("first_name", "last_name", "bio", "date_of_birth")},
),
("Аватар", {"fields": ("avatar",)}),
("Даты", {"fields": ("created_at", "updated_at"), "classes": ("collapse",)}),
)
def has_avatar(self, obj):
"""Есть ли аватар."""
if obj.avatar:
return format_html(
'<span style="color: white; background: #28a745; padding: 3px 10px; '
'border-radius: 3px;">Да</span>'
)
return format_html(
'<span style="color: white; background: #6c757d; padding: 3px 10px; '
'border-radius: 3px;">Нет</span>'
)
has_avatar.short_description = "Аватар"

View File

@@ -0,0 +1,27 @@
# Generated by Django 3.2.25 on 2026-01-21 17:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('user', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='first_name',
),
migrations.RemoveField(
model_name='user',
name='last_name',
),
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='', related_name='custom_user_set', related_query_name='custom_user', to='auth.Group', verbose_name='groups'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.25 on 2026-02-05 11:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('user', '0002_remove_firstname_lastname'),
]
operations = [
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='', related_name='custom_user_set', related_query_name='custom_user', to='auth.Group', verbose_name='groups'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.25 on 2026-02-06 12:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('user', '0003_alter_user_groups'),
]
operations = [
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='', related_name='custom_user_set', related_query_name='custom_user', to='auth.Group', verbose_name='groups'),
),
]