178 lines
6.1 KiB
TypeScript
178 lines
6.1 KiB
TypeScript
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 { CurrentIssuesEccmBotHandlerService } from './handlers/current-issues-eccm.bot-handler.service';
|
||
import { TelegramBotHandlerInterface } from './telegram.bot-handler.interface';
|
||
import { SetDailyEccmUserCommentBotHandlerService } from './handlers/set-daily-eccm-user-comment.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+) (.+)/;
|
||
|
||
private handlers: TelegramBotHandlerInterface[] = [];
|
||
|
||
constructor(
|
||
private userMetaInfoService: UserMetaInfoService,
|
||
private usersService: UsersService,
|
||
private configService: ConfigService,
|
||
private currentIssuesBotHandlerService: CurrentIssuesEccmBotHandlerService,
|
||
private setDailyEccmUserCommentBotHandlerService: SetDailyEccmUserCommentBotHandlerService,
|
||
) {
|
||
this.telegramBotToken = this.configService.get<string>('telegramBotToken');
|
||
this.redminePublicUrlPrefix =
|
||
this.configService.get<string>('redmineUrlPublic');
|
||
this.initTelegramBot();
|
||
this.handlers.push(this.currentIssuesBotHandlerService);
|
||
this.handlers.push(this.setDailyEccmUserCommentBotHandlerService);
|
||
}
|
||
|
||
private async initTelegramBot(): Promise<void> {
|
||
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);
|
||
});
|
||
for (let i = 0; i < this.handlers.length; i++) {
|
||
const handler = this.handlers[i];
|
||
await handler.init(this, this.bot);
|
||
}
|
||
}
|
||
|
||
private async showHelpMessage(msg: TelegramBot.Message): Promise<void> {
|
||
const userMetaInfo = await this.userMetaInfoService.findByTelegramId(
|
||
msg.chat.id,
|
||
);
|
||
let helpMessage: string;
|
||
/* eslint-disable */
|
||
if (userMetaInfo) {
|
||
const handlersMessages = this.handlers
|
||
.map((handler) => handler.getHelpMsg())
|
||
.join('\n');
|
||
helpMessage = [
|
||
handlersMessages,
|
||
`/help`
|
||
].join('\n');
|
||
} else {
|
||
helpMessage = [
|
||
`/register <redmine_id> <redmine_token>`,
|
||
`/help`,
|
||
].join('\n');
|
||
}
|
||
/* eslint-enable */
|
||
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<boolean> {
|
||
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<boolean> {
|
||
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<void> {
|
||
const telegramChatId = msg.chat.id;
|
||
const userMetaInfo = await this.userMetaInfoService.findByTelegramId(
|
||
telegramChatId,
|
||
);
|
||
if (userMetaInfo) {
|
||
await this.userMetaInfoService.delete(userMetaInfo);
|
||
}
|
||
}
|
||
}
|