uchill/backend/apps/users/services.py

185 lines
8.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Сервисы для работы с пользователями.
"""
import json
import logging
from django.utils import timezone
from django.db.models import Q
from django.http import HttpResponse
logger = logging.getLogger(__name__)
class DataExportService:
"""Сервис для экспорта данных пользователя (GDPR compliance)."""
@staticmethod
def export_user_data(user):
"""
Экспортировать все данные пользователя.
Args:
user: Объект User
Returns:
dict: Данные пользователя в формате JSON
"""
try:
data = {
'export_date': timezone.now().isoformat(),
'user': {
'id': user.id,
'email': user.email,
'first_name': user.first_name,
'last_name': user.last_name,
'phone': str(user.phone) if hasattr(user, 'phone') and user.phone else None,
'telegram_id': user.telegram_id,
'telegram_username': user.telegram_username,
'birth_date': user.birth_date.isoformat() if hasattr(user, 'birth_date') and user.birth_date else None,
'date_joined': user.date_joined.isoformat(),
'last_login': user.last_login.isoformat() if user.last_login else None,
'role': user.role,
'is_active': user.is_active,
},
'lessons': [],
'homework': [],
'materials': [],
'subscriptions': [],
'payments': [],
'notifications': [],
}
# Занятия
from apps.schedule.models import Lesson
lessons = Lesson.objects.filter(
Q(mentor=user) | Q(client__user=user)
).select_related('mentor', 'client', 'subject')
for lesson in lessons:
lesson_data = {
'id': lesson.id,
'title': lesson.title,
'start_time': lesson.start_time.isoformat() if lesson.start_time else None,
'end_time': lesson.end_time.isoformat() if lesson.end_time else None,
'status': lesson.status,
'subject': lesson.subject.name if lesson.subject else None,
'price': float(lesson.price) if lesson.price else None,
'description': lesson.description,
'created_at': lesson.created_at.isoformat() if lesson.created_at else None,
}
data['lessons'].append(lesson_data)
# Домашние задания
from apps.homework.models import Homework, HomeworkSubmission
if user.role == 'mentor':
homeworks = Homework.objects.filter(mentor=user)
else:
homeworks = Homework.objects.filter(assigned_to=user)
for homework in homeworks:
homework_data = {
'id': homework.id,
'title': homework.title,
'description': homework.description,
'deadline': homework.deadline.isoformat() if homework.deadline else None,
'max_score': homework.max_score,
'status': homework.status,
'created_at': homework.created_at.isoformat() if homework.created_at else None,
}
data['homework'].append(homework_data)
# Решения ДЗ
# Оптимизация: используем select_related для избежания N+1 запросов
submissions = HomeworkSubmission.objects.filter(student=user).select_related('homework')
for submission in submissions:
submission_data = {
'id': submission.id,
'homework_id': submission.homework.id,
'homework_title': submission.homework.title,
'content': submission.content,
'score': submission.score,
'feedback': submission.feedback,
'status': submission.status,
'submitted_at': submission.submitted_at.isoformat() if submission.submitted_at else None,
}
data['homework'].append({
'type': 'submission',
**submission_data
})
# Подписки
from apps.subscriptions.models import Subscription
# Оптимизация: используем select_related для избежания N+1 запросов
subscriptions = Subscription.objects.filter(user=user).select_related('plan')
for subscription in subscriptions:
subscription_data = {
'id': subscription.id,
'plan_name': subscription.plan.name if subscription.plan else None,
'status': subscription.status,
'start_date': subscription.start_date.isoformat() if subscription.start_date else None,
'end_date': subscription.end_date.isoformat() if subscription.end_date else None,
'created_at': subscription.created_at.isoformat() if subscription.created_at else None,
}
data['subscriptions'].append(subscription_data)
# Платежи
from apps.subscriptions.models import Payment
payments = Payment.objects.filter(user=user)
for payment in payments:
payment_data = {
'id': payment.id,
'amount': float(payment.amount),
'currency': payment.currency,
'status': payment.status,
'payment_method': payment.payment_method,
'created_at': payment.created_at.isoformat() if payment.created_at else None,
}
data['payments'].append(payment_data)
# Уведомления (последние 100)
from apps.notifications.models import Notification
notifications = Notification.objects.filter(recipient=user).order_by('-created_at')[:100]
for notification in notifications:
notification_data = {
'id': notification.id,
'title': notification.title,
'message': notification.message,
'notification_type': notification.notification_type,
'is_read': notification.is_read,
'created_at': notification.created_at.isoformat() if notification.created_at else None,
}
data['notifications'].append(notification_data)
return data
except Exception as e:
logger.error(f"Ошибка экспорта данных пользователя {user.id}: {str(e)}", exc_info=True)
return None
@staticmethod
def generate_export_file(user, format='json'):
"""
Сгенерировать файл экспорта.
Args:
user: Объект User
format: Формат экспорта ('json')
Returns:
HttpResponse или None
"""
data = DataExportService.export_user_data(user)
if not data:
return None
if format == 'json':
json_data = json.dumps(data, indent=2, ensure_ascii=False)
response = HttpResponse(json_data, content_type='application/json; charset=utf-8')
filename = f"user_data_{user.id}_{timezone.now().strftime('%Y%m%d')}.json"
response['Content-Disposition'] = f'attachment; filename="{filename}"'
return response
return None