NestJS의 Telegram 봇에 대한 관리자 모드 및 사용자 모드에서 메시지 디버깅을 위한 모듈 추가
107968 단어 telegramdebugnestjskaufmanbot
연결
https://github.com/EndyKaufman/kaufman-bot - 봇의 소스 코드
https://telegram.me/DevelopKaufmanBot - 전보의 현재 봇
디버그 모드 상태 저장을 위해 사용자에게 새 필드 추가
새 사용자 필드를 추가하기 위한 마이그레이션 만들기
마이그레이션/V202203310937AddDebugFieldToUserTable.pgsql
DO $$
BEGIN
ALTER TABLE "User"
ADD "debugMode" boolean DEFAULT FALSE;
EXCEPTION
WHEN duplicate_column THEN
NULL;
END
$$;
마이그레이션 적용
npm run migrate:local
endy@endy-virtual-machine:~/Projects/current/kaufman-bot$ npm run migrate:local
> [email protected] migrate:local
> export $(xargs < ./.env.local) > /dev/null 2>&1 && export DATABASE_URL=$SERVER_POSTGRES_URL && npm run migrate
> [email protected] migrate
> npm run flyway -- migrate
> [email protected] flyway
> flyway -c .flyway.js "migrate"
Flyway Community Edition 6.3.2 by Redgate
Database: jdbc:postgresql://localhost:5432/kaufman_bot_develop (PostgreSQL 13.3)
WARNING: Flyway upgrade recommended: PostgreSQL 13.3 is newer than this version of Flyway and support has not been tested. The latest supported version of PostgreSQL is 12.
Successfully validated 3 migrations (execution time 00:00.018s)
Current version of schema "public": 202203252144
Migrating schema "public" to version 202203310937 - AddDebugFieldToUserTable
Successfully applied 1 migration to schema "public" (execution time 00:00.032s)

prisma 스키마 및 SDK 업데이트
npm run prisma:pull:local
endy@endy-virtual-machine:~/Projects/current/kaufman-bot$ npm run prisma:pull:local
> [email protected] prisma:pull:local
> export $(xargs < ./.env.local) > /dev/null 2>&1 && export DATABASE_URL=$SERVER_POSTGRES_URL && npm run -- prisma db pull && npm run prisma:generate
> [email protected] prisma
> prisma "db" "pull"
Prisma schema loaded from prisma/schema.prisma
Datasource "db": PostgreSQL database "kaufman_bot_develop", schema "public" at "localhost:5432"
Introspecting based on datasource defined in prisma/schema.prisma …
✔ Introspected 2 models and wrote them into prisma/schema.prisma in 303ms
Run prisma generate to generate Prisma Client.
> [email protected] prisma:generate
> npm run -- prisma generate
> [email protected] prisma
> prisma "generate"
Prisma schema loaded from prisma/schema.prisma
✔ Generated Prisma Client (3.11.1 | library) to ./node_modules/@prisma/client in 165ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

프리즈마 스키마 확인
프리즈마/스키마.프리즈마
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id(map: "PK_USERS") @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
telegramId String @unique(map: "UQ_USERS__TELEGRAM_ID") @db.VarChar(64)
langCode String @default("en") @db.VarChar(64)
debugMode Boolean @default(false)
}
model migrations {
installed_rank Int @id(map: "__migrations_pk")
version String? @db.VarChar(50)
description String @db.VarChar(200)
type String @db.VarChar(20)
script String @db.VarChar(1000)
checksum Int?
installed_by String @db.VarChar(100)
installed_on DateTime @default(now()) @db.Timestamp(6)
execution_time Int
success Boolean
@@index([success], map: "__migrations_s_idx")
@@map("__migrations")
}
디버그 명령에 필요한 모든 로직이 올바르게 작동하도록 핵심 로직 업데이트
모든 인터페이스 업데이트
후크 전
libs/core/server/src/lib/bot-commands/bot-commands-types/on-before-bot-commands.interface.ts
import { BotCommandsProviderActionMsg } from './bot-commands-provider.interface';
export interface OnBeforeBotCommands {
onBeforeBotCommands<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(
msg: TMsg,
ctx?
): Promise<TMsg>;
}
애프터 훅
libs/core/server/src/lib/bot-commands/bot-commands-types/on-after-bot-commands.interface.ts
import { BotCommandsProviderActionResultType } from './bot-commands-provider-action-result-type';
import { BotCommandsProviderActionMsg } from './bot-commands-provider.interface';
export interface OnAfterBotCommands {
onAfterBotCommands<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg,
TResult extends BotCommandsProviderActionResultType<TMsg> = BotCommandsProviderActionResultType<TMsg>
>(
result: TResult,
msg: TMsg,
ctx?
): Promise<{ result: TResult; msg: TMsg }>;
}
공급자 인터페이스 업데이트
libs/core/server/src/lib/bot-commands/bot-commands-types/bot-commands-provider.interface.ts
import { Context } from 'telegraf';
import { Update } from 'telegraf/typings/core/types/typegram';
import { BotCommandsProviderActionResultType } from './bot-commands-provider-action-result-type';
export const BOT_COMMANDS_PROVIDER = Symbol('BOT_COMMANDS_PROVIDER');
export type BotCommandsProviderActionMsg = Update.MessageUpdate['message'] & {
text: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
botContext?: Record<string, any>;
};
export type BotCommandsProviderActionContext = Context<Update.MessageUpdate>;
export interface BotCommandsProvider {
onHelp<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(
msg: TMsg,
ctx
): Promise<BotCommandsProviderActionResultType<TMsg>>;
onMessage<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(
msg: TMsg,
ctx
): Promise<BotCommandsProviderActionResultType<TMsg>>;
}
핵심 서비스 업데이트
서비스에 텔레그램 작업의 주요 로직 추가
libs/core/server/src/lib/bot-commands/bot-commands-services/bot-commands.service.ts
import { Injectable } from '@nestjs/common';
import { CustomInject } from 'nestjs-custom-injector';
import { BotCommandsEnum } from '../bot-commands-types/bot-commands-enum';
import { BotCommandsProviderActionResultType } from '../bot-commands-types/bot-commands-provider-action-result-type';
import {
BotCommandsProvider,
BotCommandsProviderActionContext,
BotCommandsProviderActionMsg,
BOT_COMMANDS_PROVIDER,
} from '../bot-commands-types/bot-commands-provider.interface';
import { OnAfterBotCommands } from '../bot-commands-types/on-after-bot-commands.interface';
import { OnBeforeBotCommands } from '../bot-commands-types/on-before-bot-commands.interface';
import { BotСommandsToolsService } from './bot-commands-tools.service';
@Injectable()
export class BotСommandsService implements BotCommandsProvider {
@CustomInject(BOT_COMMANDS_PROVIDER, { multi: true })
private botCommandsProviders!: (BotCommandsProvider &
Partial<OnBeforeBotCommands> &
Partial<OnAfterBotCommands>)[];
constructor(
private readonly botСommandsToolsService: BotСommandsToolsService
) {}
async process(ctx, defaultHandler?: () => Promise<unknown>) {
let msg: BotCommandsProviderActionMsg = ctx.update.message;
const result = await this.onMessage(msg, ctx, defaultHandler);
if (result?.type === 'message') {
msg = result.message;
}
if (result?.type === 'markdown') {
await ctx.reply(result.markdown, { parse_mode: 'MarkdownV2' });
return;
}
if (result?.type === 'text') {
await ctx.reply(result.text);
return;
}
}
async onHelp<TMsg extends BotCommandsProviderActionMsg>(
msg: TMsg,
ctx: BotCommandsProviderActionContext
): Promise<BotCommandsProviderActionResultType<TMsg>> {
const allResults: string[] = [];
const len = this.botCommandsProviders.length;
for (let i = 0; i < len; i++) {
const botCommandsProvider = this.botCommandsProviders[i];
const result = await botCommandsProvider.onHelp(msg, ctx);
if (result !== null && result.type === 'text') {
allResults.push(result.text);
}
if (result !== null && result.type === 'markdown') {
allResults.push(result.markdown);
}
}
return {
type: 'markdown',
markdown: allResults.join('\n\n'),
};
}
async onMessage<TMsg extends BotCommandsProviderActionMsg>(
msg: TMsg,
ctx: BotCommandsProviderActionContext,
defaultHandler?: () => Promise<unknown>
): Promise<BotCommandsProviderActionResultType<TMsg>> {
msg = await this.processOnBeforeBotCommands(msg, ctx);
const len = this.botCommandsProviders.length;
let result: BotCommandsProviderActionResultType<TMsg> = null;
for (let i = 0; i < len; i++) {
if (!result) {
const botCommandsProvider = this.botCommandsProviders[i];
result = await botCommandsProvider.onMessage(msg, ctx);
}
}
if (
result === null &&
this.botСommandsToolsService.checkCommands(
msg.text,
[BotCommandsEnum.help],
msg.from.language_code
)
) {
return this.onHelp(msg, ctx);
}
const afterBotCommand = await this.processOnAfterBotCommands(
result,
msg,
ctx
);
if (defaultHandler) {
await defaultHandler();
}
return afterBotCommand.result;
}
async processOnBeforeBotCommands<TMsg extends BotCommandsProviderActionMsg>(
msg: TMsg,
ctx?: BotCommandsProviderActionContext
): Promise<TMsg> {
const len = this.botCommandsProviders.length;
for (let i = 0; i < len; i++) {
const botCommandsProvider = this.botCommandsProviders[i];
if (botCommandsProvider.onBeforeBotCommands)
msg = await botCommandsProvider.onBeforeBotCommands(msg, ctx);
}
return msg;
}
async processOnAfterBotCommands<
TMsg extends BotCommandsProviderActionMsg,
TResult extends BotCommandsProviderActionResultType<TMsg> = BotCommandsProviderActionResultType<TMsg>
>(
result: TResult,
msg: TMsg,
ctx?: BotCommandsProviderActionContext
): Promise<{ result: TResult; msg: TMsg }> {
const len = this.botCommandsProviders.length;
for (let i = 0; i < len; i++) {
const botCommandsProvider = this.botCommandsProviders[i];
if (botCommandsProvider.onAfterBotCommands) {
const afterBotCommand = await botCommandsProvider.onAfterBotCommands<
TMsg,
TResult
>(result, msg, ctx);
result = afterBotCommand.result;
msg = afterBotCommand.msg;
}
}
return { result, msg };
}
}
DebugMessagesModule 생성
새 nx lib 디버그 메시지 생성
npm run -- nx g @nrwl/nest:lib debug-messages/server
endy@endy-virtual-machine:~/Projects/current/kaufman-bot$ npm run -- nx g @nrwl/nest:lib debug-messages/server
> [email protected] nx
> nx "g" "@nrwl/nest:lib" "debug-messages/server"
CREATE libs/debug-messages/server/README.md
CREATE libs/debug-messages/server/.babelrc
CREATE libs/debug-messages/server/src/index.ts
CREATE libs/debug-messages/server/tsconfig.json
CREATE libs/debug-messages/server/tsconfig.lib.json
UPDATE tsconfig.base.json
CREATE libs/debug-messages/server/project.json
UPDATE workspace.json
CREATE libs/debug-messages/server/.eslintrc.json
CREATE libs/debug-messages/server/jest.config.js
CREATE libs/debug-messages/server/tsconfig.spec.json
CREATE libs/debug-messages/server/src/lib/debug-messages-server.module.ts

구성 파일 만들기
libs/debug-messages/server/src/lib/debug-messages-config/debug-messages.config.ts
export const DEBUG_MESSAGES_CONFIG = 'DEBUG_MESSAGES_CONFIG';
export interface DebugMessagesConfig {
name: string;
descriptions: string;
usage: string[];
spyWords: string[];
}
명령 열거형 만들기
libs/debug-messages/server/src/lib/debug-messages-types/debug-messages-commands.ts
import { getText } from 'class-validator-multi-lang';
export const DebugMessagesCommandsEnum = {
on: getText('on'),
off: getText('off'),
current: getText('state'),
};
스토어 사용자 설정을 위한 스토리지 서비스 생성
libs/debug-messages/server/src/lib/debug-messages-services/debug-messages.storage.ts
import { PrismaClientService } from '@kaufman-bot/core/server';
import { Injectable } from '@nestjs/common';
@Injectable()
export class DebugMessagesStorage {
private readonly debugModeOfUsers: Record<number, boolean> = {};
constructor(private readonly prismaClientService: PrismaClientService) {}
async getDebugModeOfUser(telegramUserId: number): Promise<boolean> {
const currentDebugMode = this.debugModeOfUsers[telegramUserId];
if (currentDebugMode) {
return currentDebugMode;
}
try {
const currentDebugModeFromDatabase =
await this.prismaClientService.user.findFirst({
where: { telegramId: telegramUserId.toString() },
rejectOnNotFound: true,
});
this.debugModeOfUsers[telegramUserId] =
currentDebugModeFromDatabase.debugMode;
return this.debugModeOfUsers[telegramUserId];
} catch (error) {
return false;
}
}
async setDebugModeOfUser(userId: number, debugMode: boolean): Promise<void> {
await this.prismaClientService.user.upsert({
create: { telegramId: userId.toString(), debugMode },
update: { debugMode },
where: { telegramId: userId.toString() },
});
this.debugModeOfUsers[userId] = debugMode;
}
}
봇 명령어의 메인 로직으로 서비스 생성
libs/debug-messages/server/src/lib/debug-messages-services/debug-messages.service.ts
import {
BotCommandsEnum,
BotCommandsProvider,
BotCommandsProviderActionMsg,
BotCommandsProviderActionResultType,
BotСommandsToolsService,
OnAfterBotCommands,
OnBeforeBotCommands,
} from '@kaufman-bot/core/server';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { getText } from 'class-validator-multi-lang';
import { TranslatesService } from 'nestjs-translates';
import {
DebugMessagesConfig,
DEBUG_MESSAGES_CONFIG,
} from '../debug-messages-config/debug-messages.config';
import { DebugMessagesCommandsEnum } from '../debug-messages-types/debug-messages-commands';
import { DebugMessagesStorage } from './debug-messages.storage';
const DEBUG_MODE = 'debugMode';
@Injectable()
export class DebugMessagesService
implements BotCommandsProvider, OnBeforeBotCommands, OnAfterBotCommands
{
private readonly logger = new Logger(DebugMessagesService.name);
constructor(
@Inject(DEBUG_MESSAGES_CONFIG)
private readonly debugMessagesConfig: DebugMessagesConfig,
private readonly translatesService: TranslatesService,
private readonly debugMessagesStorage: DebugMessagesStorage,
private readonly commandToolsService: BotСommandsToolsService
) {}
async onAfterBotCommands<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg,
TResult extends BotCommandsProviderActionResultType<TMsg> = BotCommandsProviderActionResultType<TMsg>
>(result: TResult, msg: TMsg, ctx): Promise<{ result: TResult; msg: TMsg }> {
const { botContext, ...debugData } = msg;
if (botContext?.[DEBUG_MODE] && ctx) {
ctx.reply(
['```
', JSON.stringify(debugData, undefined, 4), '
```'].join('\n'),
{
parse_mode: 'MarkdownV2',
}
);
}
return {
msg,
result,
};
}
async onBeforeBotCommands<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(msg: TMsg): Promise<TMsg> {
const debugMode = await this.debugMessagesStorage.getDebugModeOfUser(
msg.from?.id
);
if (!msg.botContext) {
msg.botContext = {};
}
msg.botContext[DEBUG_MODE] = debugMode;
return msg;
}
async onHelp<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(msg: TMsg): Promise<BotCommandsProviderActionResultType<TMsg>> {
return await this.onMessage({
...msg,
text: `${this.debugMessagesConfig.name} ${BotCommandsEnum.help}`,
});
}
async onMessage<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(msg: TMsg): Promise<BotCommandsProviderActionResultType<TMsg>> {
const locale = msg.from?.language_code || 'en';
const spyWord = this.debugMessagesConfig.spyWords.find((spyWord) =>
this.commandToolsService.checkCommands(msg.text, [spyWord], locale)
);
if (spyWord) {
if (
this.commandToolsService.checkCommands(
msg.text,
[BotCommandsEnum.help],
locale
)
) {
return {
type: 'markdown',
markdown: this.commandToolsService.generateHelpMessage(
locale,
this.debugMessagesConfig.name,
this.debugMessagesConfig.descriptions,
this.debugMessagesConfig.usage
),
};
}
const processedMsg = await this.process(msg, locale);
if (typeof processedMsg === 'string') {
return {
type: 'text',
text: processedMsg,
};
}
if (processedMsg) {
return { type: 'message', message: processedMsg };
}
this.logger.warn(`Unhandled commands for text: "${msg.text}"`);
this.logger.debug(msg);
}
return null;
}
private async process<
TMsg extends BotCommandsProviderActionMsg = BotCommandsProviderActionMsg
>(msg: TMsg, locale: string) {
const debugMode = await this.debugMessagesStorage.getDebugModeOfUser(
msg.from?.id
);
if (
this.commandToolsService.checkCommands(
msg.text,
[DebugMessagesCommandsEnum.on],
locale
)
) {
if (!debugMode) {
await this.debugMessagesStorage.setDebugModeOfUser(msg.from?.id, true);
return this.translatesService.translate(
getText(`debug enabled`),
locale,
{
locale,
}
);
} else {
return this.translatesService.translate(
getText(`debug already enabled`),
locale,
{
locale,
}
);
}
}
if (
this.commandToolsService.checkCommands(
msg.text,
[DebugMessagesCommandsEnum.off],
locale
)
) {
if (debugMode) {
await this.debugMessagesStorage.setDebugModeOfUser(msg.from?.id, false);
return this.translatesService.translate(
getText(`debug disabled`),
locale,
{
locale,
}
);
} else {
return this.translatesService.translate(
getText(`debug already disabled`),
locale,
{
locale,
}
);
}
}
if (
this.commandToolsService.checkCommands(
msg.text,
[DebugMessagesCommandsEnum.current],
locale
)
) {
return this.translatesService.translate(
getText(`debug: {{debugMode}}`),
locale,
{ debugMode: debugMode ? 'enable' : 'disable' }
);
}
return msg;
}
}
모듈 만들기
libs/debug-messages/server/src/lib/debug-messages.module.ts
import {
BotCommandsModule,
BOT_COMMANDS_PROVIDER,
PrismaClientModule,
} from '@kaufman-bot/core/server';
import { DynamicModule, Module } from '@nestjs/common';
import { getText } from 'class-validator-multi-lang';
import { CustomInjectorModule } from 'nestjs-custom-injector';
import { TranslatesModule } from 'nestjs-translates';
import {
DebugMessagesConfig,
DEBUG_MESSAGES_CONFIG,
} from './debug-messages-config/debug-messages.config';
import { DebugMessagesService } from './debug-messages-services/debug-messages.service';
import { DebugMessagesStorage } from './debug-messages-services/debug-messages.storage';
@Module({
imports: [TranslatesModule, PrismaClientModule, BotCommandsModule],
providers: [DebugMessagesStorage],
exports: [
TranslatesModule,
PrismaClientModule,
BotCommandsModule,
DebugMessagesStorage,
],
})
export class DebugMessagesModule {
static forRoot(): DynamicModule {
return {
module: DebugMessagesModule,
imports: [
CustomInjectorModule.forFeature({
imports: [DebugMessagesModule],
providers: [
{
provide: DEBUG_MESSAGES_CONFIG,
useValue: <DebugMessagesConfig>{
name: getText('Debug messages'),
usage: [
getText('debug on'),
getText('debug off'),
getText('debug state'),
],
descriptions: getText(
'Commands for enable and disable debug mode'
),
spyWords: [getText('debug')],
},
},
{
provide: BOT_COMMANDS_PROVIDER,
useClass: DebugMessagesService,
},
],
exports: [DEBUG_MESSAGES_CONFIG],
}),
],
};
}
}
애플리케이션 업데이트
앱 서비스 업데이트
앱/서버/src/app/app.service.ts
import {
BotCommandsProviderActionMsg,
BotСommandsService,
} from '@kaufman-bot/core/server';
import { Injectable, Logger } from '@nestjs/common';
import { Hears, On, Start, Update } from 'nestjs-telegraf';
import { Context } from 'telegraf';
@Update()
@Injectable()
export class AppService {
private readonly logger = new Logger(AppService.name);
constructor(private readonly botСommandsService: BotСommandsService) {}
getData(): { message: string } {
return { message: 'Welcome to server!' };
}
@Start()
async startCommand(ctx: Context) {
await this.botСommandsService.process(ctx, () => ctx.reply('Welcome'));
}
@On('sticker')
async onSticker(ctx) {
await this.botСommandsService.process(ctx, () => ctx.reply('👍'));
}
@Hears('hi')
async hearsHi(ctx: Context) {
await this.botСommandsService.process(ctx, () => ctx.reply('Hey there'));
}
@On('text')
async onMessage(ctx) {
let msg: BotCommandsProviderActionMsg = ctx.update.message;
const result = await this.botСommandsService.onMessage(msg, ctx);
if (result?.type === 'message') {
msg = result.message;
}
if (result?.type === 'markdown') {
await ctx.reply(result.markdown, { parse_mode: 'MarkdownV2' });
return;
}
if (result?.type === 'text') {
await ctx.reply(result.text);
return;
}
}
}
앱 모듈 업데이트
앱/서버/src/app/app.module.ts
import {
BotCommandsModule,
PrismaClientModule,
} from '@kaufman-bot/core/server';
import { CurrencyConverterModule } from '@kaufman-bot/currency-converter/server';
import { DebugMessagesModule } from '@kaufman-bot/debug-messages/server';
import { FactsGeneratorModule } from '@kaufman-bot/facts-generator/server';
import {
DEFAULT_LANGUAGE,
LanguageSwitherModule,
} from '@kaufman-bot/language-swither/server';
import { Module } from '@nestjs/common';
import env from 'env-var';
import { TelegrafModule } from 'nestjs-telegraf';
import {
getDefaultTranslatesModuleOptions,
TranslatesModule,
} from 'nestjs-translates';
import { join } from 'path';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [
TelegrafModule.forRoot({
token: env.get('TELEGRAM_BOT_TOKEN').required().asString(),
}),
PrismaClientModule.forRoot({
databaseUrl: env.get('SERVER_POSTGRES_URL').required().asString(),
logging: 'long_queries',
maxQueryExecutionTime: 5000,
}),
TranslatesModule.forRoot(
getDefaultTranslatesModuleOptions({
localePaths: [
join(__dirname, 'assets', 'i18n'),
join(__dirname, 'assets', 'i18n', 'class-validator-messages'),
],
vendorLocalePaths: [join(__dirname, 'assets', 'i18n')],
locales: [DEFAULT_LANGUAGE, 'ru'],
})
),
BotCommandsModule,
LanguageSwitherModule.forRoot(),
DebugMessagesModule.forRoot(),
CurrencyConverterModule.forRoot(),
FactsGeneratorModule.forRoot(),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
모든 사전 번역
필요한 모든 파일 생성 실행
npm run generate
endy@endy-virtual-machine:~/Projects/current/kaufman-bot$ npm run generate
> [email protected] generate
> npm run prisma:generate && npm run rucken -- prepare --locales=en,ru && npm run lint:fix
> [email protected] prisma:generate
> npm run -- prisma generate
> [email protected] prisma
> prisma "generate"
Prisma schema loaded from prisma/schema.prisma
✔ Generated Prisma Client (3.11.1 | library) to ./node_modules/@prisma/client in 193ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client
'@prisma/client'에서 { PrismaClient } 가져오기
const prisma = 새로운 PrismaClient()
> [email protected] rucken
> rucken "prepare" "--locales=en,ru"
> [email protected] lint:fix
> npm run tsc:lint && nx workspace-lint --fix && nx run-many --target=lint --all --fix && nx format:write --all
> [email protected] tsc:lint
> tsc --noEmit -p tsconfig.base.json
✔ nx run currency-converter-server:lint [local cache]
✔ nx run language-swither-server:lint [local cache]
✔ nx run facts-generator-server:lint [local cache]
✔ nx run debug-messages-server:lint (1s)
✔ nx run html-scraper-server:lint [local cache]
✔ nx run core-server:lint (1s)
✔ nx run server:lint (1s)
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target lint for 7 projects (4s)
With additional flags:
--fix=true
Nx read the output from the cache instead of running the command for 4 out of 7 tasks.
> NX Running affected:* commands with --all can result in very slow builds.
--all is not meant to be used for any sizable project or to be used in CI.
Learn more about checking only what is affected: https://nx.dev/latest/angular/cli/affected#affected.
모든 빈 단어에 대한 번역 추가
번역용 사전 목록 보기

ru 언어로 번역 추가

po 파일에서 json 사전을 생성하기 위해 generate 실행
npm run generate
텔레그램 봇의 새로운 로직 확인
일반적인 도움말 메시지

디버그 명령에 대한 도움말 메시지

디버그 모드를 활성화하고 작동 확인

디버그 정보 표시로 사용자 로케일 변경

러시아 로케일에 대한 일반적인 도움말 메시지

디버그 이모티콘의 예
보내다

디버그
{
"message_id": 822,
"from": {
"id": 102375526,
"is_bot": false,
"first_name": "IL'shat",
"last_name": "Khamitov",
"username": "KaufmanEndy",
"language_code": "ru"
},
"chat": {
"id": 102375526,
"first_name": "IL'shat",
"last_name": "Khamitov",
"username": "KaufmanEndy",
"type": "private"
},
"date": 1648837576,
"sticker": {
"width": 512,
"height": 512,
"emoji": "😥",
"set_name": "PeopleMemes",
"is_animated": true,
"is_video": false,
"thumb": {
"file_id": "AAMCAgADGQEAAgM2YkdDyN-EhN0TaqqYga12aOy6N3EAApoUAALJ5JFJ6q9bB_WLS2YBAAdtAAMjBA",
"file_unique_id": "AQADmhQAAsnkkUly",
"file_size": 6304,
"width": 128,
"height": 128
},
"file_id": "CAACAgIAAxkBAAIDNmJHQ8jfhITdE2qqmIGtdmjsujdxAAKaFAACyeSRSeqvWwf1i0tmIwQ",
"file_unique_id": "AgADmhQAAsnkkUk",
"file_size": 29792
}
}

대답

이모티콘 사용 최고 앱 핸들러의 경우

다음 포스팅에서는 처리되지 않은 메시지를 처리하기 위한 모듈을 Dialogflow API로 추가할 예정입니다...
Reference
이 문제에 관하여(NestJS의 Telegram 봇에 대한 관리자 모드 및 사용자 모드에서 메시지 디버깅을 위한 모듈 추가), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/endykaufman/add-a-module-for-debugging-messages-in-admin-mode-and-user-mode-for-telegram-bot-on-nestjs-ebm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)