160 lines
6.8 KiB
TypeScript
160 lines
6.8 KiB
TypeScript
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 }))
|
||
);
|
||
}
|
||
}
|