185 lines
8.3 KiB
Python
185 lines
8.3 KiB
Python
"""
|
||
Сервисы для работы с пользователями.
|
||
"""
|
||
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
|
||
|