feat: implement CI/CD pipeline with Gitea Actions
- Add Gitea Actions workflow with 4 stages: lint, test, build, push - Configure ruff linting and formatting checks - Set up Django tests with PostgreSQL and Redis services - Implement Docker image building for web and celery services - Add requirements.txt and requirements-dev.txt generation - Fix ipdb compatibility issues in test runner - Update ruff configuration for Django compatibility - Add comprehensive CI/CD documentation
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from typing import Dict, Any, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import transaction
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
@@ -12,28 +13,27 @@ class UserService:
|
||||
"""Сервисный слой для работы с пользователями"""
|
||||
|
||||
@classmethod
|
||||
def create_user(cls, *, email: str, username: str, password: str, **extra_fields) -> User:
|
||||
def create_user(
|
||||
cls, *, email: str, username: str, password: str, **extra_fields
|
||||
) -> User:
|
||||
"""
|
||||
Создает нового пользователя
|
||||
|
||||
|
||||
Args:
|
||||
email: Email пользователя
|
||||
username: Username пользователя
|
||||
password: Пароль
|
||||
**extra_fields: Дополнительные поля
|
||||
|
||||
|
||||
Returns:
|
||||
User: Созданный пользователь
|
||||
|
||||
|
||||
Raises:
|
||||
ValidationError: При некорректных данных
|
||||
"""
|
||||
with transaction.atomic():
|
||||
user = User.objects.create_user(
|
||||
email=email,
|
||||
username=username,
|
||||
password=password,
|
||||
**extra_fields
|
||||
email=email, username=username, password=password, **extra_fields
|
||||
)
|
||||
return user
|
||||
|
||||
@@ -57,11 +57,11 @@ class UserService:
|
||||
def update_user(cls, user_id: int, **fields) -> Optional[User]:
|
||||
"""
|
||||
Обновляет данные пользователя
|
||||
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
**fields: Поля для обновления
|
||||
|
||||
|
||||
Returns:
|
||||
User: Обновленный пользователь или None
|
||||
"""
|
||||
@@ -71,7 +71,7 @@ class UserService:
|
||||
|
||||
for field, value in fields.items():
|
||||
setattr(user, field, value)
|
||||
|
||||
|
||||
user.save()
|
||||
return user
|
||||
|
||||
@@ -79,10 +79,10 @@ class UserService:
|
||||
def delete_user(cls, user_id: int) -> bool:
|
||||
"""
|
||||
Удаляет пользователя
|
||||
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
|
||||
|
||||
Returns:
|
||||
bool: True если успешно удален
|
||||
"""
|
||||
@@ -96,27 +96,27 @@ class UserService:
|
||||
def get_tokens_for_user(cls, user: User) -> Dict[str, str]:
|
||||
"""
|
||||
Генерирует JWT токены для пользователя
|
||||
|
||||
|
||||
Args:
|
||||
user: Пользователь
|
||||
|
||||
|
||||
Returns:
|
||||
Dict[str, str]: refresh и access токены
|
||||
"""
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return {
|
||||
'refresh': str(refresh),
|
||||
'access': str(refresh.access_token),
|
||||
"refresh": str(refresh),
|
||||
"access": str(refresh.access_token),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def verify_email(cls, user_id: int) -> bool:
|
||||
"""
|
||||
Подтверждает email пользователя
|
||||
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
|
||||
|
||||
Returns:
|
||||
bool: True если успешно подтвержден
|
||||
"""
|
||||
@@ -135,7 +135,7 @@ class ProfileService:
|
||||
def get_profile_by_user_id(cls, user_id: int) -> Optional[Profile]:
|
||||
"""Получает профиль по ID пользователя"""
|
||||
try:
|
||||
return Profile.objects.select_related('user').get(user_id=user_id)
|
||||
return Profile.objects.select_related("user").get(user_id=user_id)
|
||||
except Profile.DoesNotExist:
|
||||
return None
|
||||
|
||||
@@ -143,11 +143,11 @@ class ProfileService:
|
||||
def update_profile(cls, user_id: int, **fields) -> Optional[Profile]:
|
||||
"""
|
||||
Обновляет профиль пользователя
|
||||
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
**fields: Поля для обновления
|
||||
|
||||
|
||||
Returns:
|
||||
Profile: Обновленный профиль или None
|
||||
"""
|
||||
@@ -157,7 +157,7 @@ class ProfileService:
|
||||
|
||||
for field, value in fields.items():
|
||||
setattr(profile, field, value)
|
||||
|
||||
|
||||
profile.save()
|
||||
return profile
|
||||
|
||||
@@ -165,10 +165,10 @@ class ProfileService:
|
||||
def get_full_profile_data(cls, user_id: int) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Получает полные данные пользователя и профиля
|
||||
|
||||
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
|
||||
|
||||
Returns:
|
||||
Dict: Полные данные или None
|
||||
"""
|
||||
@@ -178,17 +178,17 @@ class ProfileService:
|
||||
|
||||
user = profile.user
|
||||
return {
|
||||
'id': user.id,
|
||||
'email': user.email,
|
||||
'username': user.username,
|
||||
'is_verified': user.is_verified,
|
||||
'phone': user.phone,
|
||||
'first_name': profile.first_name,
|
||||
'last_name': profile.last_name,
|
||||
'full_name': profile.full_name,
|
||||
'bio': profile.bio,
|
||||
'avatar': profile.avatar.url if profile.avatar else None,
|
||||
'date_of_birth': profile.date_of_birth,
|
||||
'created_at': user.created_at,
|
||||
'updated_at': user.updated_at,
|
||||
}
|
||||
"id": user.id,
|
||||
"email": user.email,
|
||||
"username": user.username,
|
||||
"is_verified": user.is_verified,
|
||||
"phone": user.phone,
|
||||
"first_name": profile.first_name,
|
||||
"last_name": profile.last_name,
|
||||
"full_name": profile.full_name,
|
||||
"bio": profile.bio,
|
||||
"avatar": profile.avatar.url if profile.avatar else None,
|
||||
"date_of_birth": profile.date_of_birth,
|
||||
"created_at": user.created_at,
|
||||
"updated_at": user.updated_at,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user