import { UsersService } from '@app/event-emitter/users/users.service'; import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import TelegramBot from 'node-telegram-bot-api'; import { UserMetaInfoService } from 'src/user-meta-info/user-meta-info.service'; import axios from 'axios'; import { UserMetaInfoModel } from 'src/models/user-meta-info.model'; import { CurrentIssuesBotHandlerService } from './handlers/current-issues.bot-handler.service'; @Injectable() export class TelegramBotService { private logger = new Logger(TelegramBotService.name); private bot: TelegramBot; private telegramBotToken: string; private redminePublicUrlPrefix: string; private registerRe = /\/register (\d+) (.+)/; constructor( private userMetaInfoService: UserMetaInfoService, private usersService: UsersService, private configService: ConfigService, private currentIssuesBotHandlerService: CurrentIssuesBotHandlerService, ) { this.telegramBotToken = this.configService.get('telegramBotToken'); this.redminePublicUrlPrefix = this.configService.get('redmineUrlPublic'); this.initTelegramBot(); } private async initTelegramBot(): Promise { const Telegram = await require('node-telegram-bot-api'); this.bot = new Telegram(this.telegramBotToken, { polling: true }); this.bot.onText(/\/start/, async (msg) => { await this.showHelpMessage(msg); }); this.bot.onText(/\/help/, async (msg) => { await this.showHelpMessage(msg); }); this.bot.onText(this.registerRe, async (msg) => { await this.register(msg); }); this.bot.onText(/\/leave/, async (msg) => { await this.leave(msg); }); this.currentIssuesBotHandlerService.init(this, this.bot); } private async showHelpMessage(msg: TelegramBot.Message): Promise { const userMetaInfo = await this.userMetaInfoService.findByTelegramId( msg.chat.id, ); let helpMessage: string; if (userMetaInfo) { // eslint-disable-next-line prettier/prettier helpMessage = [ `/current_issues - мои текущие задачи`, `/help` ].join('\n'); } else { // eslint-disable-next-line prettier/prettier helpMessage = [ `/register `, `/help` ].join('\n'); } this.logger.debug( `Sent help message for telegramChatId = ${msg.chat.id}, ` + `message = ${helpMessage}`, ); this.bot.sendMessage(msg.chat.id, helpMessage); } async sendMessageByRedmineId( redmineId: number, msg: string, options?: TelegramBot.SendMessageOptions, ): Promise { const userMetaInfo = await this.userMetaInfoService.findByRedmineId( redmineId, ); if (!userMetaInfo) return false; const chatId = userMetaInfo.telegram_chat_id; await this.bot.sendMessage(chatId, msg, options); this.logger.debug( `Sent message for redmineUserId = ${redmineId}, ` + `telegramChatId = ${chatId}, ` + `message = ${msg}, ` + `options = ${JSON.stringify(options)}`, ); return true; } async sendMessageByName( firstname: string, lastname: string, msg: string, options?: TelegramBot.SendMessageOptions, ): Promise { const user = await this.usersService.findUserByName(firstname, lastname); if (!user) return false; return await this.sendMessageByRedmineId(user.id, msg, options); } private async register( msg: TelegramBot.Message, ): Promise<{ result: boolean; message: string }> { const items = (msg.text || '').match(this.registerRe); const result = (result: boolean, message: string, logData?: any) => { const logMsg = `Telegram registration ${result ? 'successed' : 'failed'} ` + `with message ${message}, ` + `log data = ${JSON.stringify(logData || null)}`; this.logger.log(logMsg); this.bot.sendMessage(msg.chat.id, message); return { result: result, message: message }; }; if (!items || !items[1] || !items[2]) { return result(false, 'Не указаны необходимые данные'); } let redmineId: number, redmineToken: string; try { redmineId = Number(items[1]); redmineToken = items[2]; } catch (ex) { return result(false, 'Введены неверные значения', {}); } const url = `${this.redminePublicUrlPrefix}/users/current.json`; const resp = await axios.get(url, { headers: { 'X-Redmine-API-Key': redmineToken }, }); if (resp && resp.data && resp.statusText == 'OK') { const data = resp.data; if (data.user.id == redmineId) { const userData = await this.usersService.getUser(redmineId); const userMetaInfo: UserMetaInfoModel = { telegram_chat_id: msg.chat.id, user_id: userData.id, }; await this.userMetaInfoService.save(userMetaInfo); return result(true, `Данные для ${userData.name} подтверждены`, { redmineId: redmineId, }); } } return result(false, 'Не удалось проверить подлинность указанных данных'); } private async leave(msg: TelegramBot.Message): Promise { const telegramChatId = msg.chat.id; const userMetaInfo = await this.userMetaInfoService.findByTelegramId( telegramChatId, ); if (userMetaInfo) { await this.userMetaInfoService.delete(userMetaInfo); } } }