Отедельные таблицы User и TelegramUser
This commit is contained in:
@@ -65,6 +65,16 @@ class Database(typing.Protocol):
|
||||
|
||||
async def create_user(self, user: domain.User) -> None: ...
|
||||
|
||||
async def get_telegram_user(
|
||||
self,
|
||||
telegram_user_id: UUID | None = None,
|
||||
telegram_id: int | None = None,
|
||||
) -> domain.TelegramUser | None: ...
|
||||
|
||||
async def create_telegram_user(self, telegram_user: domain.TelegramUser) -> None: ...
|
||||
|
||||
async def update_telegram_user(self, telegram_user: domain.TelegramUser) -> None: ...
|
||||
|
||||
async def create_workspace(self, workspace: domain.Workspace) -> None: ...
|
||||
|
||||
async def update_workspace(self, workspace: domain.Workspace) -> None: ...
|
||||
@@ -222,7 +232,7 @@ class Database(typing.Protocol):
|
||||
async def create_subscription(self, subscription: domain.Subscription) -> None: ...
|
||||
|
||||
async def get_subscription_by_subscriber_and_placement(
|
||||
self, subscriber_id: UUID, placement_id: UUID
|
||||
self, telegram_user_id: UUID, placement_id: UUID
|
||||
) -> domain.Subscription | None: ...
|
||||
|
||||
async def update_subscription(self, subscription: domain.Subscription) -> None: ...
|
||||
@@ -236,11 +246,11 @@ class Database(typing.Protocol):
|
||||
) -> list[domain.Subscription]: ...
|
||||
|
||||
async def get_active_subscriptions_by_subscriber_and_project(
|
||||
self, subscriber_id: UUID, project_id: UUID
|
||||
self, telegram_user_id: UUID, project_id: UUID
|
||||
) -> list[domain.Subscription]: ...
|
||||
|
||||
async def get_active_subscription_by_subscriber_and_project(
|
||||
self, subscriber_id: UUID, project_id: UUID
|
||||
self, telegram_user_id: UUID, project_id: UUID
|
||||
) -> domain.Subscription | None: ...
|
||||
|
||||
# Count methods
|
||||
@@ -365,7 +375,11 @@ class Usecase:
|
||||
if workspace:
|
||||
return workspace
|
||||
|
||||
workspace_name = user.username or f'Workspace {user.telegram_id}'
|
||||
if not user.telegram_user:
|
||||
raise domain.UserNotFound(user.id)
|
||||
|
||||
telegram_user = user.telegram_user
|
||||
workspace_name = telegram_user.username or f'Workspace {telegram_user.telegram_id}'
|
||||
workspace = domain.Workspace(name=workspace_name)
|
||||
|
||||
async with self.database.transaction():
|
||||
|
||||
@@ -11,12 +11,17 @@ if typing.TYPE_CHECKING:
|
||||
|
||||
|
||||
async def create_telegram_login_token(self: 'Usecase', telegram_id: int, username: str | None) -> str:
|
||||
telegram_user = await self.database.get_telegram_user(telegram_id=telegram_id)
|
||||
if not telegram_user:
|
||||
telegram_user = domain.TelegramUser(telegram_id=telegram_id, username=username)
|
||||
await self.database.create_telegram_user(telegram_user)
|
||||
elif username and telegram_user.username != username:
|
||||
telegram_user.username = username
|
||||
await self.database.update_telegram_user(telegram_user)
|
||||
|
||||
user = await self.database.get_user(telegram_id=telegram_id)
|
||||
if not user:
|
||||
user = domain.User(
|
||||
telegram_id=telegram_id,
|
||||
username=username,
|
||||
)
|
||||
user = domain.User(telegram_user=telegram_user)
|
||||
await self.database.create_user(user)
|
||||
|
||||
token = secrets.token_urlsafe(32)
|
||||
|
||||
@@ -13,33 +13,38 @@ async def get_jwt_by_telegram_id(
|
||||
first_name: str | None = None,
|
||||
last_name: str | None = None,
|
||||
) -> dto.ValidateLoginTokenOutput:
|
||||
user = await self.database.get_user(telegram_id=telegram_id)
|
||||
if not user:
|
||||
user = domain.User(
|
||||
telegram_user = await self.database.get_telegram_user(telegram_id=telegram_id)
|
||||
if not telegram_user:
|
||||
telegram_user = domain.TelegramUser(
|
||||
telegram_id=telegram_id,
|
||||
username=username,
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
)
|
||||
await self.database.create_user(user)
|
||||
await self.database.create_telegram_user(telegram_user)
|
||||
else:
|
||||
updated = False
|
||||
if username is not None and user.username != username:
|
||||
user.username = username
|
||||
if username is not None and telegram_user.username != username:
|
||||
telegram_user.username = username
|
||||
updated = True
|
||||
if first_name is not None and user.first_name != first_name:
|
||||
user.first_name = first_name
|
||||
if first_name is not None and telegram_user.first_name != first_name:
|
||||
telegram_user.first_name = first_name
|
||||
updated = True
|
||||
if last_name is not None and user.last_name != last_name:
|
||||
user.last_name = last_name
|
||||
if last_name is not None and telegram_user.last_name != last_name:
|
||||
telegram_user.last_name = last_name
|
||||
updated = True
|
||||
if updated:
|
||||
await self.database.update_user(user)
|
||||
await self.database.update_telegram_user(telegram_user)
|
||||
|
||||
user = await self.database.get_user(telegram_id=telegram_id)
|
||||
if not user:
|
||||
user = domain.User(telegram_user=telegram_user)
|
||||
await self.database.create_user(user)
|
||||
|
||||
access_token = self.jwt_encoder.encode_access_token(
|
||||
user_id=user.id,
|
||||
telegram_id=user.telegram_id,
|
||||
username=user.username,
|
||||
telegram_id=telegram_user.telegram_id,
|
||||
username=telegram_user.username,
|
||||
)
|
||||
|
||||
return dto.ValidateLoginTokenOutput(
|
||||
|
||||
@@ -13,10 +13,15 @@ async def get_me(self: 'Usecase', user_id: uuid.UUID) -> dto.UserOutput:
|
||||
if not user:
|
||||
raise domain.UserNotFound(user_id)
|
||||
|
||||
if not user.telegram_user:
|
||||
raise domain.UserNotFound(user_id)
|
||||
|
||||
telegram_user = user.telegram_user
|
||||
|
||||
return dto.UserOutput(
|
||||
id=user.id,
|
||||
telegram_id=user.telegram_id,
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
telegram_id=telegram_user.telegram_id,
|
||||
username=telegram_user.username,
|
||||
first_name=telegram_user.first_name,
|
||||
last_name=telegram_user.last_name,
|
||||
)
|
||||
|
||||
@@ -26,10 +26,14 @@ async def validate_login_token(self: 'Usecase', input: dto.ValidateLoginTokenInp
|
||||
|
||||
await self.database.mark_token_as_used(input.token)
|
||||
|
||||
telegram_user = user.telegram_user
|
||||
if telegram_user is None:
|
||||
raise domain.UserNotFound(login_token.user_id)
|
||||
|
||||
access_token = self.jwt_encoder.encode_access_token(
|
||||
user_id=user.id,
|
||||
telegram_id=user.telegram_id,
|
||||
username=user.username,
|
||||
telegram_id=telegram_user.telegram_id,
|
||||
username=telegram_user.username,
|
||||
)
|
||||
|
||||
return dto.ValidateLoginTokenOutput(
|
||||
|
||||
@@ -14,6 +14,9 @@ async def disconnect_project_by_tg_id(self: 'Usecase', input: dto.DisconnectProj
|
||||
if not user:
|
||||
log.warning(f'User with telegram_id {input.user_telegram_id} not found when disconnecting channel')
|
||||
return
|
||||
if user.telegram_user is None:
|
||||
log.warning('User %s missing telegram profile when disconnecting channel', user.id)
|
||||
return
|
||||
|
||||
project = await self.database.get_project_for_user_by_telegram(user.id, input.telegram_id)
|
||||
if not project:
|
||||
|
||||
@@ -52,6 +52,18 @@ async def tg_add_project(self: 'Usecase', input: dto.ConnectProjectInput) -> dto
|
||||
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] = []
|
||||
@@ -154,10 +166,10 @@ async def tg_add_project(self: 'Usecase', input: dto.ConnectProjectInput) -> dto
|
||||
f'Бот добавлен в канал "{input.title}".\n\n'
|
||||
f'У вас {len(workspaces)} рабочих пространств. '
|
||||
'Нажмите кнопку ниже чтобы выбрать, где создать проект.',
|
||||
user.telegram_id,
|
||||
telegram_user.telegram_id,
|
||||
buttons,
|
||||
)
|
||||
|
||||
log.info('Pending channel notification sent to user %s for channel %s', user.telegram_id, channel.id)
|
||||
log.info('Pending channel notification sent to user %s for channel %s', telegram_user.telegram_id, channel.id)
|
||||
|
||||
return None
|
||||
|
||||
@@ -21,6 +21,9 @@ async def update_project_permissions(self: 'Usecase', input: dto.UpdateProjectPe
|
||||
if not user:
|
||||
log.warning(f'User with telegram_id {input.user_telegram_id} not found when updating channel permissions')
|
||||
return
|
||||
if user.telegram_user is None:
|
||||
log.warning(f'User %s missing telegram profile when updating permissions', user.id)
|
||||
return
|
||||
|
||||
project = await self.database.get_project_for_user_by_telegram(user.id, input.telegram_id)
|
||||
if not project:
|
||||
@@ -34,7 +37,7 @@ async def update_project_permissions(self: 'Usecase', input: dto.UpdateProjectPe
|
||||
|
||||
await self.telegram_bot.send_message(
|
||||
f'✅ Канал "{input.chat_title}" был активирован.\n\nВсе необходимые права боту предоставлены!',
|
||||
input.user_telegram_id,
|
||||
user.telegram_user.telegram_id,
|
||||
)
|
||||
log.info(f'Project channel {input.telegram_id} reactivated - all permissions granted')
|
||||
return
|
||||
@@ -49,7 +52,7 @@ async def update_project_permissions(self: 'Usecase', input: dto.UpdateProjectPe
|
||||
f'⚠️ Канал "{input.chat_title}" был деактивирован.\n\n'
|
||||
f'Боту убрали необходимые права:\n{missed_permissions}'
|
||||
),
|
||||
input.user_telegram_id,
|
||||
user.telegram_user.telegram_id,
|
||||
)
|
||||
log.warning(
|
||||
'Project channel %s deactivated due to missing permissions: %s',
|
||||
|
||||
@@ -22,20 +22,20 @@ async def handle_subscription(
|
||||
log.warning('Placement not found for invite_link: %s', invite_link)
|
||||
return
|
||||
|
||||
subscriber = await self.database.get_user(telegram_id=user_telegram_id)
|
||||
subscriber = await self.database.get_telegram_user(telegram_id=user_telegram_id)
|
||||
if not subscriber:
|
||||
subscriber = domain.User(
|
||||
subscriber = domain.TelegramUser(
|
||||
telegram_id=user_telegram_id,
|
||||
username=username,
|
||||
first_name=first_name,
|
||||
last_name=last_name,
|
||||
)
|
||||
await self.database.create_user(subscriber)
|
||||
await self.database.create_telegram_user(subscriber)
|
||||
else:
|
||||
subscriber.username = username or subscriber.username
|
||||
subscriber.first_name = first_name or subscriber.first_name
|
||||
subscriber.last_name = last_name or subscriber.last_name
|
||||
await self.database.update_user(subscriber)
|
||||
await self.database.update_telegram_user(subscriber)
|
||||
|
||||
active_subscription = await self.database.get_active_subscription_by_subscriber_and_project(
|
||||
subscriber.id, placement.project_id
|
||||
@@ -74,7 +74,7 @@ async def handle_subscription(
|
||||
|
||||
subscription = domain.Subscription(
|
||||
placement_id=placement.id,
|
||||
subscriber_id=subscriber.id,
|
||||
telegram_user_id=subscriber.id,
|
||||
invite_link=invite_link,
|
||||
)
|
||||
await self.database.create_subscription(subscription)
|
||||
|
||||
@@ -12,7 +12,7 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def handle_unsubscription(self: 'Usecase', user_telegram_id: int, channel_telegram_id: int) -> None:
|
||||
subscriber = await self.database.get_user(telegram_id=user_telegram_id)
|
||||
subscriber = await self.database.get_telegram_user(telegram_id=user_telegram_id)
|
||||
if not subscriber:
|
||||
log.warning('Subscriber not found for telegram_id: %s', user_telegram_id)
|
||||
return
|
||||
|
||||
@@ -54,6 +54,11 @@ async def create_workspace_invite(
|
||||
if invited_by_user is None:
|
||||
raise domain.UserNotFound(user_id)
|
||||
|
||||
if invited_user.telegram_user is None:
|
||||
raise domain.UserNotFound(invited_user.id)
|
||||
if invited_by_user.telegram_user is None:
|
||||
raise domain.UserNotFound(invited_by_user.id)
|
||||
|
||||
invite.user = invited_user
|
||||
invite.invited_by = invited_by_user
|
||||
|
||||
@@ -68,7 +73,7 @@ async def create_workspace_invite(
|
||||
)
|
||||
await self.telegram_bot.send_message_with_inline_keyboard(
|
||||
invite_message,
|
||||
chat_id=invited_user.telegram_id,
|
||||
chat_id=invited_user.telegram_user.telegram_id,
|
||||
buttons=[[accept_button]],
|
||||
)
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ async def tg_accept_workspace_invite(
|
||||
if not user:
|
||||
await self.telegram_bot.send_message('❌ Вы не авторизованы. Используйте /start для входа.', chat_id)
|
||||
return
|
||||
if user.telegram_user is None:
|
||||
await self.telegram_bot.send_message('❌ Ваш Telegram профиль не найден. Авторизуйтесь заново.', chat_id)
|
||||
return
|
||||
|
||||
parts = callback_data.split(':', 1)
|
||||
if len(parts) != 2 or parts[0] != INVITE_ACCEPT_CALLBACK_PREFIX:
|
||||
@@ -67,7 +70,7 @@ async def tg_accept_workspace_invite(
|
||||
await self.telegram_bot.send_message(
|
||||
f'✅ Вы присоединились к рабочему пространству «{workspace_name}».\n\n'
|
||||
'Администратор сможет выдать вам необходимые права в веб-интерфейсе.',
|
||||
chat_id,
|
||||
user.telegram_user.telegram_id,
|
||||
)
|
||||
|
||||
if message_id:
|
||||
|
||||
Reference in New Issue
Block a user