pinkmine/src/telegram-bot/telegram-bot.service.ts

178 lines
6.1 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 { 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);
}
}
}