Files
tgex-backend/src/usecase/project/tg_add_project.py
2026-01-07 14:00:35 +03:00

176 lines
7.5 KiB
Python
Raw 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 logging
from typing import TYPE_CHECKING
from aiogram.types import InlineKeyboardButton
from src import domain, dto
if TYPE_CHECKING:
from .. import Usecase
log = logging.getLogger(__name__)
async def tg_add_project(self: 'Usecase', input: dto.ConnectProjectInput) -> dto.ProjectOutput | None:
permissions = input.bot_permissions
if not permissions.is_admin:
log.warning(f'Bot is not admin in channel {input.telegram_id}. Attempted by user {input.user_telegram_id}')
await self.telegram_bot.send_message(
f'⚠️ Бот был добавлен в канал "{input.title}", но не является админом.\n\n'
'Пожалуйста, сделайте бота администратором канала.',
input.user_telegram_id,
)
raise domain.ChannelNoAdminRights()
missing_permissions = []
if not permissions.can_invite_users:
missing_permissions.append('Создание инвайт-ссылок')
if not permissions.can_restrict_members:
missing_permissions.append('Управление пользователями (видеть вступления)')
if missing_permissions:
log.warning(
f'Bot lacks required permissions in channel {input.telegram_id}: {missing_permissions}. '
f'Attempted by user {input.user_telegram_id}'
)
permissions_text = '\n'.join(f'{p}' for p in missing_permissions)
await self.telegram_bot.send_message(
f'⚠️ Бот был добавлен в канал "{input.title}", но не имеет необходимых прав.\n\n'
f'Отсутствующие права:\n{permissions_text}\n\n'
'Пожалуйста, предоставьте эти права боту в настройках канала.',
input.user_telegram_id,
)
raise domain.ChannelNoAdminRights()
user = await self.database.get_user(telegram_id=input.user_telegram_id)
if not user:
log.warning(f'User {input.user_telegram_id} not found when trying to connect channel {input.telegram_id}')
await self.telegram_bot.send_message(
f'⚠️ Канал "{input.title}" не может быть подключен.\n\n'
'Вы должны сначала авторизоваться в веб-панели перед подключением каналов.',
input.user_telegram_id,
)
raise domain.UserNotFound()
if user.telegram_user is None:
log.warning('User %s missing telegram profile when connecting channel', user.id)
await self.telegram_bot.send_message(
'⚠️ Произошла ошибка при обработке вашего профиля. Пожалуйста, повторите авторизацию.',
input.user_telegram_id,
)
raise domain.UserNotFound()
if user.telegram_user is None:
raise domain.UserNotFound(user.id)
telegram_user = user.telegram_user
memberships = await self.database.get_user_workspaces(user.id)
workspaces: list[domain.Workspace] = []
for membership in memberships:
workspace: domain.Workspace | None = membership.workspace
if not workspace:
workspace = await self.database.get_workspace(membership.workspace_id)
if workspace:
workspaces.append(workspace)
if not workspaces:
workspace = await self.get_or_create_personal_workspace(user)
workspaces = [workspace]
if len(workspaces) == 1:
workspace = workspaces[0]
channel = await self.database.get_channel(telegram_id=input.telegram_id)
if channel:
channel.title = input.title
if input.username is not None:
channel.username = input.username
await self.database.update_channel(channel)
else:
if input.username is None:
log.warning('Cannot create channel %s without username', input.telegram_id)
await self.telegram_bot.send_message(
f'⚠️ Канал "{input.title}" не может быть подключен.\n\nУ канала отсутствует публичный username.',
input.user_telegram_id,
)
return None
channel = domain.Channel(
telegram_id=input.telegram_id,
title=input.title,
username=input.username,
)
await self.database.create_channel(channel)
project = await self.database.get_project(workspace.id, channel_id=channel.id)
if project:
project.status = domain.ProjectStatus.ACTIVE
await self.database.update_project(project)
else:
project = domain.Project(
workspace_id=workspace.id,
channel_id=channel.id,
status=domain.ProjectStatus.ACTIVE,
)
await self.database.create_project(project)
log.info(
'Project for channel %s connected/updated successfully in workspace %s by user %s',
input.telegram_id,
workspace.id,
input.user_telegram_id,
)
await self.telegram_bot.send_message(
f'✅ Канал "{input.title}" добавлен в рабочее пространство "{workspace.name}".', input.user_telegram_id
)
return dto.ProjectOutput(
id=project.id,
telegram_id=channel.telegram_id,
title=channel.title,
username=channel.username,
status=project.status,
purchase_invite_type_default=project.purchase_invite_type_default,
)
# Если >1 workspace - создаем/обновляем канал и отправляем уведомление
channel = await self.database.get_channel(telegram_id=input.telegram_id)
if channel:
channel.title = input.title
if input.username is not None:
channel.username = input.username
await self.database.update_channel(channel)
else:
if input.username is None:
log.warning('Cannot create channel %s without username', input.telegram_id)
await self.telegram_bot.send_message(
f'⚠️ Канал "{input.title}" не может быть подключен.\n\nУ канала отсутствует публичный username.',
input.user_telegram_id,
)
return None
channel = domain.Channel(
telegram_id=input.telegram_id,
title=input.title,
username=input.username,
)
await self.database.create_channel(channel)
# Callback будет обработан Golang ботом который покажет экран выбора workspace
buttons = [[InlineKeyboardButton(text='Выбрать workspace', callback_data=f'pending_channel:{channel.id}')]]
await self.telegram_bot.send_message_with_inline_keyboard(
f'Бот добавлен в канал "{input.title}".\n\n'
f'У вас {len(workspaces)} рабочих пространств. '
'Нажмите кнопку ниже чтобы выбрать, где создать проект.',
telegram_user.telegram_id,
buttons,
)
log.info('Pending channel notification sent to user %s for channel %s', telegram_user.telegram_id, channel.id)
return None