Добавление поддержки телеграм
This commit is contained in:
parent
392b030140
commit
908b927bca
10 changed files with 5872 additions and 2654 deletions
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"editor.tabSize": 2
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"couchDb": {
|
||||
"dbs": {
|
||||
"changes": ""
|
||||
}
|
||||
"changes": "",
|
||||
"userMetaInfo": "",
|
||||
}
|
||||
},
|
||||
"telegramBotToken": ""
|
||||
}
|
||||
8361
package-lock.json
generated
8361
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,7 @@
|
|||
"@nestjs/serve-static": "^2.2.2",
|
||||
"@nestjs/websockets": "^8.4.4",
|
||||
"axios": "^0.27.2",
|
||||
"cache-manager": "^4.1.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"imap-simple": "^5.1.0",
|
||||
"nano": "^10.0.0",
|
||||
|
|
@ -37,12 +38,14 @@
|
|||
"rimraf": "^3.0.2",
|
||||
"rss-parser": "^3.12.0",
|
||||
"rxjs": "^7.2.0",
|
||||
"socket.io": "^4.4.1"
|
||||
"socket.io": "^4.4.1",
|
||||
"telegraf": "^4.8.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.0.0",
|
||||
"@nestjs/schematics": "^8.0.0",
|
||||
"@nestjs/testing": "^8.0.0",
|
||||
"@types/cache-manager": "^4.0.1",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "27.4.0",
|
||||
"@types/node": "^16.0.0",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { RedmineIssuesCacheWriterService } from '@app/event-emitter/issue-cache-
|
|||
import { EnhancerService } from '@app/event-emitter/issue-enhancers/enhancer.service';
|
||||
import { TimestampEnhancer } from '@app/event-emitter/issue-enhancers/timestamps-enhancer';
|
||||
import { MainController } from '@app/event-emitter/main/main.controller';
|
||||
import { Logger, Module, OnModuleInit } from '@nestjs/common';
|
||||
import { CacheModule, Logger, Module, OnModuleInit } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { switchMap, tap } from 'rxjs';
|
||||
import { AppController } from './app.controller';
|
||||
|
|
@ -18,6 +18,10 @@ import { StatusChangeNotificationsService } from './notifications/status-change-
|
|||
import { ChangesCacheWriterService } from './changes-cache-writer/changes-cache-writer.service';
|
||||
import { Issues } from '@app/event-emitter/couchdb-datasources/issues';
|
||||
import { Users } from '@app/event-emitter/couchdb-datasources/users';
|
||||
import { TelegramBotService } from './telegram-bot/telegram-bot.service';
|
||||
import { TelegrafModule } from 'nestjs-telegraf';
|
||||
import { UserMetaInfoService } from './user-meta-info/user-meta-info.service';
|
||||
import { UserMetaInfo } from './couchdb-datasources/user-meta-info';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -25,6 +29,12 @@ import { Users } from '@app/event-emitter/couchdb-datasources/users';
|
|||
config: configuration().redmineIssueEventEmitterConfig,
|
||||
}),
|
||||
ConfigModule.forRoot({ load: [configuration] }),
|
||||
TelegrafModule.forRoot({
|
||||
token: configuration().telegramBotToken,
|
||||
}),
|
||||
CacheModule.register({
|
||||
isGlobal: true,
|
||||
}),
|
||||
],
|
||||
controllers: [AppController, MainController],
|
||||
providers: [
|
||||
|
|
@ -36,6 +46,9 @@ import { Users } from '@app/event-emitter/couchdb-datasources/users';
|
|||
Changes,
|
||||
RedminePublicUrlConverter,
|
||||
ChangesCacheWriterService,
|
||||
TelegramBotService,
|
||||
UserMetaInfoService,
|
||||
UserMetaInfo,
|
||||
],
|
||||
})
|
||||
export class AppModule implements OnModuleInit {
|
||||
|
|
@ -56,6 +69,7 @@ export class AppModule implements OnModuleInit {
|
|||
Issues.getDatasource();
|
||||
Users.getDatasource();
|
||||
Changes.getDatasource();
|
||||
UserMetaInfo.getDatasource();
|
||||
|
||||
this.enhancerService.addEnhancer([
|
||||
this.timestampEnhancer,
|
||||
|
|
|
|||
35
src/couchdb-datasources/user-meta-info.ts
Normal file
35
src/couchdb-datasources/user-meta-info.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { CouchDb } from '@app/event-emitter/couchdb-datasources/couchdb';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import nano from 'nano';
|
||||
import { UserMetaInfoModel } from 'src/models/user-meta-info.model';
|
||||
import configuration from '../configs/app';
|
||||
|
||||
const config = configuration();
|
||||
|
||||
@Injectable()
|
||||
export class UserMetaInfo {
|
||||
private static logger = new Logger(UserMetaInfo.name);
|
||||
private static db = null;
|
||||
|
||||
static async getDatasource(): Promise<nano.DocumentScope<UserMetaInfoModel>> {
|
||||
if (UserMetaInfo.db) {
|
||||
return UserMetaInfo.db;
|
||||
}
|
||||
const n = CouchDb.getCouchDb();
|
||||
const userMetaInfoDbName =
|
||||
config.couchDb.dbs.userMetaInfo || 'user_meta_info';
|
||||
const dbs = await n.db.list();
|
||||
if (!dbs.includes(userMetaInfoDbName)) {
|
||||
await n.db.create(userMetaInfoDbName);
|
||||
}
|
||||
UserMetaInfo.db = await n.db.use(userMetaInfoDbName);
|
||||
UserMetaInfo.logger.log(
|
||||
`Connected to user_meta_info db - ${userMetaInfoDbName}`,
|
||||
);
|
||||
return UserMetaInfo.db;
|
||||
}
|
||||
|
||||
async getDatasource(): Promise<nano.DocumentScope<UserMetaInfoModel>> {
|
||||
return await UserMetaInfo.getDatasource();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,8 @@ export type AppConfig = {
|
|||
couchDb: {
|
||||
dbs: {
|
||||
changes: string;
|
||||
userMetaInfo: string;
|
||||
};
|
||||
};
|
||||
telegramBotToken: string;
|
||||
};
|
||||
|
|
|
|||
4
src/models/user-meta-info.model.ts
Normal file
4
src/models/user-meta-info.model.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export type UserMetaInfoModel = {
|
||||
user_id: number;
|
||||
telegram_chat_id: number;
|
||||
};
|
||||
44
src/telegram-bot/telegram-bot.service.ts
Normal file
44
src/telegram-bot/telegram-bot.service.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { UsersService } from '@app/event-emitter/users/users.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Update, Ctx, Start, Help, On, Hears } from 'nestjs-telegraf';
|
||||
import { UserMetaInfoService } from 'src/user-meta-info/user-meta-info.service';
|
||||
import { Context } from 'telegraf';
|
||||
|
||||
@Update()
|
||||
@Injectable()
|
||||
export class TelegramBotService {
|
||||
constructor(
|
||||
private userMetaInfoService: UserMetaInfoService,
|
||||
private usersService: UsersService,
|
||||
) {}
|
||||
|
||||
@Start()
|
||||
async start(@Ctx() ctx: Context): Promise<void> {
|
||||
const chat = await ctx.getChat();
|
||||
const chatId = chat.id;
|
||||
const userMetaInfo = await this.userMetaInfoService.findByTelegramId(
|
||||
chatId,
|
||||
);
|
||||
if (!userMetaInfo) {
|
||||
await ctx.reply('Привет, незнакомец!');
|
||||
} else {
|
||||
const user = await this.usersService.getUser(userMetaInfo.user_id);
|
||||
await ctx.reply(`Привет, ${user.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
@Help()
|
||||
async help(@Ctx() ctx: Context): Promise<void> {
|
||||
await ctx.reply('Send me a sticker');
|
||||
}
|
||||
|
||||
@On('sticker')
|
||||
async on(@Ctx() ctx: Context): Promise<void> {
|
||||
await ctx.reply('👍');
|
||||
}
|
||||
|
||||
@Hears('мои задачи')
|
||||
async hears(@Ctx() ctx: Context): Promise<void> {
|
||||
await ctx.reply('В разработке');
|
||||
}
|
||||
}
|
||||
48
src/user-meta-info/user-meta-info.service.ts
Normal file
48
src/user-meta-info/user-meta-info.service.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { CacheTTL, Injectable } from '@nestjs/common';
|
||||
import { UserMetaInfo } from 'src/couchdb-datasources/user-meta-info';
|
||||
import { UserMetaInfoModel } from 'src/models/user-meta-info.model';
|
||||
import nano from 'nano';
|
||||
|
||||
@Injectable()
|
||||
export class UserMetaInfoService {
|
||||
constructor(private userMetaInfo: UserMetaInfo) {}
|
||||
|
||||
@CacheTTL(60)
|
||||
async findById(id: number): Promise<UserMetaInfoModel | null> {
|
||||
const db = await this.userMetaInfo.getDatasource();
|
||||
try {
|
||||
return await db.get(String(id));
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@CacheTTL(60)
|
||||
async findByTelegramId(id: number): Promise<UserMetaInfoModel | null> {
|
||||
const db = await this.userMetaInfo.getDatasource();
|
||||
try {
|
||||
const resp = await db.find({
|
||||
selector: { telegram_chat_id: id },
|
||||
limit: 1,
|
||||
});
|
||||
return resp.docs && resp.docs[0] ? resp.docs[0] : null;
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async save(data: UserMetaInfoModel): Promise<void> {
|
||||
const id = String(data.user_id);
|
||||
const db = await this.userMetaInfo.getDatasource();
|
||||
let item: (nano.MaybeDocument & UserMetaInfoModel) | null = null;
|
||||
const newItem: nano.MaybeDocument & UserMetaInfoModel = { ...data };
|
||||
try {
|
||||
item = await db.get(id);
|
||||
} catch (ex) {}
|
||||
if (item) {
|
||||
newItem._id = item._id;
|
||||
newItem._rev = item._rev;
|
||||
}
|
||||
await db.insert(newItem);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue