From a98c4031161da30ecccd6c916e65e3913a3a3d7c Mon Sep 17 00:00:00 2001 From: lizerk Date: Thu, 12 Mar 2026 17:11:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=B8=D0=B3=D1=80=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D1=82=D1=8C=20=D1=83=D1=87=D0=B0=D1=81=D1=82=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA=D0=BE=D0=B2=20=D0=B8=D0=B7=20participants=20=D0=B2?= =?UTF-8?q?=20ChatMembership?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../management/commands/README.md | 17 +++++ .../management/commands/check_chats.py | 68 ++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/backend/communications/management/commands/README.md b/backend/communications/management/commands/README.md index 6e773b24..2d517d17 100644 --- a/backend/communications/management/commands/README.md +++ b/backend/communications/management/commands/README.md @@ -97,6 +97,21 @@ cd backend .venv/bin/python manage.py check_chats --stats ``` +#### Проверить видимость чатов для конкретного пользователя + +```bash +# Проверяет какие чаты увидит пользователь через API (эмулирует логику ChatViewSet) +.venv/bin/python manage.py check_chats --check-visibility 10 +``` + +#### Мигрировать участников из participants в ChatMembership + +```bash +# КРИТИЧНО: Создает ChatMembership для всех участников из participants +# Без этого чаты не будут видны в API! +.venv/bin/python manage.py check_chats --migrate-memberships +``` + #### Показать все личные чаты ```bash @@ -184,6 +199,8 @@ cd backend ### Опции - `--stats` - Показать статистику чатов по типам +- `--check-visibility USER_ID` - Проверить видимость чатов для конкретного пользователя (как в API) +- `--migrate-memberships` - Создать ChatMembership для всех участников из participants - `--list-type TYPE` - Показать все чаты указанного типа (например: private, group) - `--export TYPE` - Экспортировать чаты указанного типа в JSON файл - `--output PATH` - Путь к файлу для экспорта (по умолчанию: chats_export.json) diff --git a/backend/communications/management/commands/check_chats.py b/backend/communications/management/commands/check_chats.py index bf221b11..69c2d845 100644 --- a/backend/communications/management/commands/check_chats.py +++ b/backend/communications/management/commands/check_chats.py @@ -75,6 +75,11 @@ class Command(BaseCommand): metavar='USER_ID', help='Проверить видимость чатов для конкретного пользователя (как в API)', ) + parser.add_argument( + '--migrate-memberships', + action='store_true', + help='Создать ChatMembership для всех участников из participants', + ) parser.add_argument( '--export', type=str, @@ -105,6 +110,8 @@ class Command(BaseCommand): self.show_stats() elif options['check_visibility']: self.check_visibility(options['check_visibility']) + elif options['migrate_memberships']: + self.migrate_memberships(no_confirm=options['no_confirm']) elif options['export']: self.export_chats(options['export'], options['output']) elif options['list_type']: @@ -127,7 +134,7 @@ class Command(BaseCommand): elif options['delete']: self.delete_chat(options['delete'], no_confirm=options['no_confirm']) else: - self.stdout.write(self.style.ERROR('Укажите действие: --stats, --check-visibility, --export, --list-type, --find, --check, --fix, --change-type, --cleanup или --delete')) + self.stdout.write(self.style.ERROR('Укажите действие: --stats, --check-visibility, --migrate-memberships, --export, --list-type, --find, --check, --fix, --change-type, --cleanup или --delete')) self.stdout.write('Используйте --help для справки') def show_stats(self): @@ -270,6 +277,65 @@ class Command(BaseCommand): chat = membership.chat self.stdout.write(f' • ID:{chat.id} {chat.name or "[без названия]"} (тип: {chat.type}, роль: {membership.role})') + def migrate_memberships(self, no_confirm=False): + """Создает ChatMembership для всех участников из participants""" + from communications.models import ChatMembership + + self.stdout.write(self.style.SUCCESS('🔄 Миграция participants → ChatMembership\n')) + + # Находим все чаты с участниками + chats_with_participants = Chat.objects.prefetch_related('participants').all() + + total_chats = 0 + total_created = 0 + total_existing = 0 + total_participants = 0 + + for chat in chats_with_participants: + participants = chat.participants.all() + if not participants.exists(): + continue + + total_chats += 1 + chat_created = 0 + + for participant in participants: + total_participants += 1 + + # Проверяем, есть ли уже membership + membership, created = ChatMembership.objects.get_or_create( + chat=chat, + user=participant, + defaults={ + 'role': 'admin' if chat.created_by_id == participant.id else 'member', + 'is_active': True, + 'invited_by': chat.created_by, + } + ) + + if created: + total_created += 1 + chat_created += 1 + else: + total_existing += 1 + # Если membership существует, но неактивный - активируем + if not membership.is_active: + membership.is_active = True + membership.save(update_fields=['is_active']) + self.stdout.write(f' ✅ Активирован ID:{chat.id} для пользователя {participant.email}') + + if chat_created > 0: + self.stdout.write(f' 📁 Чат ID:{chat.id} "{chat.name or "[без названия]"}" → создано {chat_created} memberships') + + self.stdout.write(self.style.SUCCESS(f'\n✅ Миграция завершена:')) + self.stdout.write(f' Обработано чатов: {total_chats}') + self.stdout.write(f' Обработано участников: {total_participants}') + self.stdout.write(f' Создано memberships: {total_created}') + self.stdout.write(f' Уже существовали: {total_existing}') + + if total_created > 0: + self.stdout.write(self.style.NOTICE(f'\n💡 Теперь эти чаты будут видны в API')) + def export_chats(self, chat_type, output_file): """Экспортирует чаты указанного типа в JSON файл""" import json