Files
IdP/apps/api-gateway/src/controllers/bot.controller.ts
2026-06-26 16:43:17 +03:00

160 lines
6.8 KiB
TypeScript
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 { Body, Controller, Delete, Get, Headers, Param, Patch, Post, Query } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiTags } from '@nestjs/swagger';
import { JwtService } from '@nestjs/jwt';
import { firstValueFrom } from 'rxjs';
import { CoreGrpcService } from '../core-grpc.service';
import { CreateBotDto, SetBotWebAppDto, SubmitBotCallbackDto, SubmitBotMessageDto, UpdateBotDto, UpdateBotProfileDto, ValidateWebAppInitDataDto } from '../dto/bot.dto';
import { getAuthorizedUserId } from '../document-access';
@ApiTags('BotFather')
@ApiBearerAuth()
@Controller('bots')
export class BotController {
constructor(
private readonly core: CoreGrpcService,
private readonly jwt: JwtService
) {}
private async auth(authorization?: string) {
return getAuthorizedUserId(this.jwt, this.core, authorization);
}
@Get()
@ApiOperation({ summary: 'Список моих ботов', description: 'Возвращает Telegram-ботов текущего пользователя.' })
listMyBots(@Headers('authorization') authorization?: string) {
return this.auth(authorization).then((userId) => firstValueFrom(this.core.bot.ListMyBots({ ownerId: userId })));
}
@Post()
@ApiOperation({ summary: 'Создать бота', description: 'Регистрирует нового бота и возвращает токен Bot API.' })
@ApiBody({ type: CreateBotDto })
createBot(@Headers('authorization') authorization: string | undefined, @Body() dto: CreateBotDto) {
return this.auth(authorization).then((ownerId) =>
firstValueFrom(this.core.bot.CreateBot({ ownerId, name: dto.name, username: dto.username }))
);
}
@Get('by-username/:botRef/messages')
@ApiOperation({ summary: 'История чата с ботом', description: 'Возвращает сообщения пользователя с ботом в хронологическом порядке.' })
listBotMessages(@Headers('authorization') authorization: string | undefined, @Param('botRef') botRef: string, @Query('roomId') roomId?: string) {
return this.auth(authorization).then((userId) =>
firstValueFrom(this.core.bot.ListBotChatMessages({ userId, botRef, roomId }))
);
}
@Post('by-username/:botRef/messages')
@ApiOperation({
summary: 'Написать боту',
description: 'Публикует inbound-событие в RabbitMQ для доставки боту через webhook или getUpdates.'
})
@ApiBody({ type: SubmitBotMessageDto })
submitMessage(
@Headers('authorization') authorization: string | undefined,
@Param('botRef') botRef: string,
@Body() dto: SubmitBotMessageDto
) {
return this.auth(authorization).then((senderUserId) =>
firstValueFrom(this.core.bot.SubmitBotInboundMessage({ senderUserId, botRef, text: dto.text, roomId: dto.roomId }))
);
}
@Post('by-username/:botRef/callback')
@ApiOperation({
summary: 'Нажатие inline-кнопки',
description: 'Публикует callback_query Update для webhook или getUpdates.'
})
@ApiBody({ type: SubmitBotCallbackDto })
submitCallback(
@Headers('authorization') authorization: string | undefined,
@Param('botRef') botRef: string,
@Body() dto: SubmitBotCallbackDto
) {
return this.auth(authorization).then((senderUserId) =>
firstValueFrom(
this.core.bot.SubmitBotCallbackQuery({
senderUserId,
botRef,
messageId: dto.messageId,
callbackData: dto.callbackData
})
)
);
}
@Post('web-app/validate')
@ApiOperation({
summary: 'Проверить initData Mini App',
description: 'Валидирует Telegram Web App initData по HMAC-SHA256, как в официальном Bot API.'
})
@ApiBody({ type: ValidateWebAppInitDataDto })
validateWebApp(@Body() dto: ValidateWebAppInitDataDto) {
return firstValueFrom(this.core.bot.ValidateWebAppInitData(dto));
}
@Get(':botId')
@ApiOperation({ summary: 'Получить бота', description: 'Возвращает настройки бота, принадлежащего пользователю.' })
getBot(@Headers('authorization') authorization: string | undefined, @Param('botId') botId: string) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.GetBot({ requesterId, botId, isSuperAdmin: false }))
);
}
@Patch(':botId')
@ApiOperation({ summary: 'Обновить бота', description: 'Изменяет имя или username бота.' })
@ApiBody({ type: UpdateBotDto })
updateBot(
@Headers('authorization') authorization: string | undefined,
@Param('botId') botId: string,
@Body() dto: UpdateBotDto
) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.UpdateBot({ requesterId, botId, ...dto, isSuperAdmin: false }))
);
}
@Delete(':botId')
@ApiOperation({ summary: 'Удалить бота', description: 'Удаляет бота и все связанные чаты/сообщения.' })
deleteBot(@Headers('authorization') authorization: string | undefined, @Param('botId') botId: string) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.DeleteBot({ requesterId, botId, isSuperAdmin: false }))
);
}
@Post(':botId/revoke-token')
@ApiOperation({ summary: 'Перевыпустить токен', description: 'Инвалидирует старый токен и возвращает новый.' })
revokeToken(@Headers('authorization') authorization: string | undefined, @Param('botId') botId: string) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.RevokeBotToken({ requesterId, botId, isSuperAdmin: false }))
);
}
@Patch(':botId/profile')
@ApiOperation({
summary: 'Профиль бота',
description: 'Обновляет description, aboutText, botPicUrl и глобальную кнопку меню (Web App).'
})
@ApiBody({ type: UpdateBotProfileDto })
updateBotProfile(
@Headers('authorization') authorization: string | undefined,
@Param('botId') botId: string,
@Body() dto: UpdateBotProfileDto
) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.UpdateBotProfile({ requesterId, botId, ...dto, isSuperAdmin: false }))
);
}
@Patch(':botId/web-app')
@ApiOperation({ summary: 'Настроить Mini App', description: 'Привязывает URL Web App к боту.' })
@ApiBody({ type: SetBotWebAppDto })
setWebApp(
@Headers('authorization') authorization: string | undefined,
@Param('botId') botId: string,
@Body() dto: SetBotWebAppDto
) {
return this.auth(authorization).then((requesterId) =>
firstValueFrom(this.core.bot.SetBotWebApp({ requesterId, botId, webAppUrl: dto.webAppUrl, isSuperAdmin: false }))
);
}
}