Мигрировать участников из participants в ChatMembership

This commit is contained in:
lizerk 2026-03-12 17:11:49 +03:00
parent 2d818b6064
commit a98c403116
2 changed files with 84 additions and 1 deletions

View File

@ -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)

View File

@ -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