initial
This commit is contained in:
commit
8ea10bafc3
36 changed files with 17026 additions and 0 deletions
6
.dockerignore
Normal file
6
.dockerignore
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Dockerfile
|
||||
.dockerignore
|
||||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
||||
.env
|
||||
25
.eslintrc.js
Normal file
25
.eslintrc.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
4
.prettierrc
Normal file
4
.prettierrc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
63
Dockerfile
Normal file
63
Dockerfile
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
###################
|
||||
# BUILD FOR LOCAL DEVELOPMENT
|
||||
###################
|
||||
|
||||
FROM --platform=linux/amd64 node:18-alpine As development
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy application dependency manifests to the container image.
|
||||
# A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
|
||||
# Copying this first prevents re-running npm install on every code change.
|
||||
COPY --chown=node:node package*.json ./
|
||||
|
||||
# Install app dependencies using the `npm ci` command instead of `npm install`
|
||||
RUN npm ci
|
||||
|
||||
# Bundle app source
|
||||
COPY --chown=node:node . .
|
||||
|
||||
# Use the node user from the image (instead of the root user)
|
||||
USER node
|
||||
|
||||
###################
|
||||
# BUILD FOR PRODUCTION
|
||||
###################
|
||||
|
||||
FROM --platform=linux/amd64 node:18-alpine As build
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY --chown=node:node package*.json ./
|
||||
|
||||
# In order to run `npm run build` we need access to the Nest CLI which is a dev dependency. In the previous development stage we ran `npm ci` which installed all dependencies, so we can copy over the node_modules directory from the development image
|
||||
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules
|
||||
|
||||
COPY --chown=node:node . .
|
||||
|
||||
# Run the build command which creates the production bundle
|
||||
RUN npm run build
|
||||
|
||||
# Set NODE_ENV environment variable
|
||||
ENV NODE_ENV production
|
||||
|
||||
# Running `npm ci` removes the existing node_modules directory and passing in --only=production ensures that only the production dependencies are installed. This ensures that the node_modules directory is as optimized as possible
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
USER node
|
||||
|
||||
###################
|
||||
# PRODUCTION
|
||||
###################
|
||||
|
||||
FROM --platform=linux/amd64 node:18-alpine As production
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy the bundled code from the build stage to the production image
|
||||
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
|
||||
COPY --chown=node:node --from=build /usr/src/app/dist ./dist
|
||||
|
||||
# Start the server using the production build
|
||||
CMD [ "node", "dist/main.js" ]
|
||||
73
README.md
Normal file
73
README.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Running the app
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](LICENSE).
|
||||
8
nest-cli.json
Normal file
8
nest-cli.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
15857
package-lock.json
generated
Normal file
15857
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
76
package.json
Normal file
76
package.json
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"name": "tgd-telegram-service",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.1.1",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/cqrs": "^10.2.6",
|
||||
"@nestjs/microservices": "^10.2.8",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"amqp-connection-manager": "^4.1.14",
|
||||
"amqplib": "^0.10.3",
|
||||
"nestjs-telegraf": "^2.7.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.1",
|
||||
"telegraf": "^4.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
22
src/app.controller.spec.ts
Normal file
22
src/app.controller.spec.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
12
src/app.controller.ts
Normal file
12
src/app.controller.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { Controller, Get } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
getHello(): string {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
}
|
||||
25
src/app.module.ts
Normal file
25
src/app.module.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import {ConfigModule, ConfigService} from "@nestjs/config";
|
||||
import {TelegrafModule} from "nestjs-telegraf";
|
||||
import {BotModule} from "./bot/bot.module";
|
||||
import {sessionMiddleware} from "./middleware/session.middleware";
|
||||
import {MessageController} from "./message.controller";
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule.forRoot(),
|
||||
BotModule,
|
||||
TelegrafModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
token: configService.get<string>('TELEGRAM_TOKEN'),
|
||||
include: [BotModule],
|
||||
middlewares: [sessionMiddleware],
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
})],
|
||||
controllers: [AppController, MessageController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
8
src/app.service.ts
Normal file
8
src/app.service.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return 'TGH Game Server!';
|
||||
}
|
||||
}
|
||||
25
src/bot/EchoService.ts
Normal file
25
src/bot/EchoService.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectBot } from 'nestjs-telegraf';
|
||||
import { Telegraf } from 'telegraf';
|
||||
import { ExtraPoll, ExtraReplyMessage } from 'telegraf/typings/telegram-types';
|
||||
import { Messages } from './tg.text';
|
||||
|
||||
@Injectable()
|
||||
export class EchoService {
|
||||
constructor(
|
||||
@InjectBot() private bot: Telegraf,
|
||||
) {}
|
||||
|
||||
public async test(chatId: number) {
|
||||
await this.bot.telegram.sendMessage(chatId, 'test');
|
||||
}
|
||||
|
||||
public async enterQuiz(chatId: number) {
|
||||
const extra: ExtraReplyMessage = {};
|
||||
await this.bot.telegram.sendMessage(chatId, '🥇 Да начнется битва!\n', {
|
||||
reply_markup: {
|
||||
keyboard: [[{ text: Messages.GO }]],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
65
src/bot/bot.module.ts
Normal file
65
src/bot/bot.module.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import {BotUpdate} from './bot.update';
|
||||
import {Module} from '@nestjs/common';
|
||||
import {RegisterScene} from './scenes/register.scene';
|
||||
import {RegisterNamePrompt} from './scenes/register.name.prompt';
|
||||
import {EchoService} from './EchoService';
|
||||
import {QuizScene} from './scenes/quiz.scene';
|
||||
import {RegisterPhotoScene} from './scenes/register.photo.scene';
|
||||
import {GlobalCommands} from './global-commands';
|
||||
import {ClientProxyFactory, Transport} from '@nestjs/microservices';
|
||||
import * as process from "process";
|
||||
import {ConfigModule} from "@nestjs/config";
|
||||
import AppConsts from "../constants";
|
||||
|
||||
const cmdHandles = [
|
||||
//TgPostCardsToUserCommandHandler,
|
||||
//TgCardSelectionSceneCommandHandler,
|
||||
//RemoveCardFromUserCommandHandler,
|
||||
];
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule,
|
||||
],
|
||||
providers: [
|
||||
BotUpdate,
|
||||
RegisterScene,
|
||||
RegisterNamePrompt,
|
||||
EchoService,
|
||||
QuizScene,
|
||||
RegisterPhotoScene,
|
||||
GlobalCommands,
|
||||
{
|
||||
provide: AppConsts.GameServiceName,
|
||||
useFactory: () =>
|
||||
ClientProxyFactory.create({
|
||||
transport: Transport.RMQ,
|
||||
options: {
|
||||
urls: [process.env.RMQ_URL],
|
||||
queue: process.env.RMQ_OUTBOX_Q,
|
||||
queueOptions: {
|
||||
durable: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
provide: AppConsts.PhotoServiceName,
|
||||
useFactory: () =>
|
||||
ClientProxyFactory.create({
|
||||
transport: Transport.RMQ,
|
||||
options: {
|
||||
urls: [process.env.RMQ_URL],
|
||||
queue: process.env.RMQ_PHOTOS_Q,
|
||||
queueOptions: {
|
||||
durable: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
...cmdHandles,
|
||||
],
|
||||
exports: [EchoService],
|
||||
})
|
||||
export class BotModule {}
|
||||
130
src/bot/bot.update.ts
Normal file
130
src/bot/bot.update.ts
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import {
|
||||
Command,
|
||||
Ctx,
|
||||
Hears,
|
||||
Start,
|
||||
Update,
|
||||
Sender,
|
||||
Help,
|
||||
On, Message,
|
||||
} from 'nestjs-telegraf';
|
||||
import { UpdateType as TelegrafUpdateType } from 'telegraf/typings/telegram-types';
|
||||
import { Context } from './context.interface';
|
||||
import { ExtraReplyMessage } from 'telegraf/typings/telegram-types';
|
||||
import { Markup } from 'telegraf';
|
||||
import {
|
||||
QUIZ_SCENE,
|
||||
REGISTER_PHOTO_SCENE,
|
||||
REGISTER_SCENE_ID,
|
||||
} from './scenes/scenes.const';
|
||||
import { Messages } from './tg.text';
|
||||
import { GlobalCommands } from './global-commands';
|
||||
import {Inject, Logger} from "@nestjs/common";
|
||||
import AppConsts from "../constants";
|
||||
import {ClientProxy} from "@nestjs/microservices";
|
||||
import {catchError} from "rxjs";
|
||||
|
||||
@Update()
|
||||
export class BotUpdate {
|
||||
readonly numbers = Messages.answerNumbers;
|
||||
private readonly logger = new Logger(BotUpdate.name);
|
||||
constructor(
|
||||
@Inject(AppConsts.GameServiceName) private gameService: ClientProxy,
|
||||
private globalCmd: GlobalCommands,
|
||||
) {
|
||||
}
|
||||
|
||||
@Start()
|
||||
async startCommand(@Ctx() ctx: Context) {
|
||||
this.logger.verbose(`Sending GuestInfo to MQTT for ${ctx.message.from.first_name} / ${ctx.message.from.id}`);
|
||||
this.gameService.send({cmd: 'GuestInfo'}, {user: ctx.from.id})
|
||||
.pipe(catchError((val) => {
|
||||
console.log(val);
|
||||
return 'Error';
|
||||
}),)
|
||||
.subscribe(async (result) => {
|
||||
if (result) {
|
||||
await ctx.reply(
|
||||
`🤟 Все путем, ты уже зарегистрирован, расслабься и жди указаний\r\nМожет быть`,
|
||||
);
|
||||
this.globalCmd.printCommands(ctx);
|
||||
} else {
|
||||
let reply = `👋 Привет, ${ctx.message.from.first_name}\\!\r\n`;
|
||||
reply +=
|
||||
'Я не вижу тебя в списке зарегистрированных участников, пройдем регистрацию?';
|
||||
await ctx.replyWithMarkdownV2(reply, {
|
||||
reply_markup: {
|
||||
keyboard: [[{text: Messages.IM_IN}]],
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@Hears(Messages.IM_IN)
|
||||
async onRegisterCommand(@Ctx() ctx: Context): Promise<void> {
|
||||
await ctx.scene.enter(REGISTER_SCENE_ID);
|
||||
}
|
||||
|
||||
@Hears(Messages.GO)
|
||||
async onGoCommand(@Ctx() ctx: Context) {
|
||||
await ctx.scene.enter(QUIZ_SCENE);
|
||||
|
||||
}
|
||||
|
||||
@Command('photo')
|
||||
async onPhotoCommand(@Ctx() ctx: Context) {
|
||||
await ctx.scene.enter(REGISTER_PHOTO_SCENE);
|
||||
}
|
||||
|
||||
@Command('cards')
|
||||
async onCardCommand(@Ctx() ctx: Context) {
|
||||
this.gameService.emit({ cmd: 'GetCards'}, { user: ctx.from.id, inline: false});
|
||||
}
|
||||
|
||||
@Command('next')
|
||||
async onNextCommand(@Ctx() ctx: Context) {
|
||||
if(ctx.from.id === 11178819) {
|
||||
this.gameService.emit({ cmd: 'CompleteQueue'}, { user: ctx.from.id })
|
||||
}
|
||||
}
|
||||
|
||||
@On('callback_query')
|
||||
async onInlineQuery(@Ctx() ctx: Context) {
|
||||
console.log('callback query');
|
||||
console.log(ctx.callbackQuery);
|
||||
}
|
||||
|
||||
@Hears(Messages.CHANGE_PHOTO)
|
||||
onChangePhoto(@Ctx() ctx: Context) {
|
||||
ctx.scene.enter(REGISTER_PHOTO_SCENE);
|
||||
}
|
||||
|
||||
@On('text')
|
||||
async onMsg(@Message('text') msg: string, @Ctx() ctx: Context) {
|
||||
const chars = [...msg];
|
||||
if (['1', '2', '3', '4'].includes(chars[0])) {
|
||||
ctx.scene.enter(QUIZ_SCENE, { answering: true }, false);
|
||||
}
|
||||
if (msg.includes(Messages.EMOJI_CARD)) {
|
||||
ctx.scene.enter(QUIZ_SCENE, { answering: true}, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
|
||||
@Help()
|
||||
async helpCommand(@Ctx() ctx: Context) {
|
||||
await ctx.reply('ты пидор');
|
||||
}
|
||||
|
||||
@On('sticker')
|
||||
async onSticker(@Ctx() ctx: Context) {
|
||||
console.log(ctx.message.from);
|
||||
await ctx.reply('👍');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/* import { CommandBus, CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { RemoveCardFromUserCommand } from '../../game/commands/remove-card-from-user.command';
|
||||
import { GuestsService } from '../../guests/guests.service';
|
||||
import { SharedService } from '../../shared/shared.service';
|
||||
import { PostCardsToUserCommand } from '../../game/commands/post-cards-to-user.command';
|
||||
import { InjectBot } from 'nestjs-telegraf';
|
||||
import { Telegraf } from 'telegraf';
|
||||
import { Messages } from '../tg.text';
|
||||
|
||||
@CommandHandler(RemoveCardFromUserCommand)
|
||||
export class RemoveCardFromUserCommandHandler implements ICommandHandler<RemoveCardFromUserCommand> {
|
||||
constructor(
|
||||
@InjectBot() private bot: Telegraf,
|
||||
private guestService: GuestsService,
|
||||
private sharedService: SharedService,
|
||||
private cmdBus: CommandBus,
|
||||
) {
|
||||
}
|
||||
|
||||
async execute(command: RemoveCardFromUserCommand): Promise<any> {
|
||||
const guest = await this.guestService.findById(command.telegramId);
|
||||
const data = await this.sharedService.getConfig(`buttons_${command.telegramId}`);
|
||||
const extra = {
|
||||
reply_markup: {
|
||||
remove_keyboard: false,
|
||||
keyboard: [],
|
||||
},
|
||||
};
|
||||
const buttons = JSON.parse(data.value);
|
||||
let found = false;
|
||||
buttons.reply_markup.keyboard.forEach((item) => {
|
||||
if (item[0].text.includes(command.card.description) && !found) {
|
||||
found = true;
|
||||
} else {
|
||||
extra.reply_markup.keyboard.push(
|
||||
[ { ...item[0] } ]
|
||||
)
|
||||
}
|
||||
});
|
||||
if (extra.reply_markup.keyboard.length === 0) {
|
||||
extra.reply_markup.remove_keyboard = true;
|
||||
}
|
||||
await this.sharedService.setConfig(`buttons_${command.telegramId}`, JSON.stringify(extra));
|
||||
await this.bot.telegram.sendMessage(
|
||||
guest.chatId,
|
||||
Messages.SELECT_CARD,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/* import { CommandBus, CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { CardSelectionTimeExceedCommand } from '../../game/commands/card-selection-time-exceed.command';
|
||||
import { Timeout } from '@nestjs/schedule';
|
||||
import { TGD_Config } from '../../../app.config';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { HideKeyboardCommand } from '../../game/commands/hide-keyboard.command';
|
||||
|
||||
@CommandHandler(CardSelectionTimeExceedCommand)
|
||||
export class TgCardSelectionSceneCommandHandler implements ICommandHandler<CardSelectionTimeExceedCommand> {
|
||||
private logger = new Logger(TgCardSelectionSceneCommandHandler.name);
|
||||
constructor(private cmdBus: CommandBus) {
|
||||
}
|
||||
execute(command: CardSelectionTimeExceedCommand): Promise<any> {
|
||||
this.logger.verbose(`Timeout of selecting cards`);
|
||||
return this.cmdBus.execute(
|
||||
new HideKeyboardCommand('Время выбора карты истекло'),
|
||||
);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { InjectBot } from 'nestjs-telegraf';
|
||||
import { Telegraf } from 'telegraf';
|
||||
import { Messages } from '../tg.text';
|
||||
/*
|
||||
@CommandHandler(PostCardsToUserCommand)
|
||||
export class TgPostCardsToUserCommandHandler implements ICommandHandler<PostCardsToUserCommand> {
|
||||
constructor(
|
||||
@InjectBot() private bot: Telegraf,
|
||||
private sharedService: SharedService,
|
||||
) {}
|
||||
|
||||
|
||||
async execute(command: PostCardsToUserCommand): Promise<any> {
|
||||
const extra = {
|
||||
reply_markup: {
|
||||
keyboard: [],
|
||||
},
|
||||
};
|
||||
if (command.cards.length === 0) {
|
||||
return;
|
||||
}
|
||||
command.cards.forEach((card) => {
|
||||
extra.reply_markup.keyboard.push([
|
||||
{ text: Messages.EMOJI_CARD + ' ' + card },
|
||||
]);
|
||||
});
|
||||
await this.sharedService.setConfig(`buttons_${command.chatId}`,
|
||||
JSON.stringify(extra),
|
||||
);
|
||||
return this.bot.telegram.sendMessage(
|
||||
command.chatId,
|
||||
Messages.SELECT_CARD,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
4
src/bot/context.interface.ts
Normal file
4
src/bot/context.interface.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { Scenes } from 'telegraf';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface Context extends Scenes.SceneContext {}
|
||||
23
src/bot/global-commands.ts
Normal file
23
src/bot/global-commands.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { Context } from './context.interface';
|
||||
import { Messages } from './tg.text';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
@Injectable()
|
||||
export class GlobalCommands {
|
||||
public printCommands(ctx: Context) {
|
||||
ctx.replyWithMarkdown('ты хочешь:', {
|
||||
reply_markup: {
|
||||
keyboard: [
|
||||
[{ text: Messages.CHANGE_PHOTO }],
|
||||
[{ text: Messages.NOTHING_THANKS }],
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
public hideKeyboard(ctx: Context) {
|
||||
ctx.replyWithMarkdown('-', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
98
src/bot/scenes/quiz.scene.ts
Normal file
98
src/bot/scenes/quiz.scene.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import { Command, Ctx, Message, On, Scene, SceneEnter } from 'nestjs-telegraf';
|
||||
import { QUIZ_SCENE } from './scenes.const';
|
||||
import { GlobalCommands } from '../global-commands';
|
||||
import {Inject, Logger} from '@nestjs/common';
|
||||
import { Messages } from '../tg.text';
|
||||
import {Context} from "../context.interface";
|
||||
import AppConsts from "../../constants";
|
||||
import {ClientProxy} from "@nestjs/microservices";
|
||||
|
||||
@Scene(QUIZ_SCENE)
|
||||
export class QuizScene {
|
||||
private readonly logger = new Logger(QuizScene.name);
|
||||
constructor(
|
||||
private globalCmd: GlobalCommands,
|
||||
@Inject(AppConsts.GameServiceName) private gameService: ClientProxy,
|
||||
) {}
|
||||
@SceneEnter()
|
||||
async onSceneEnter(@Ctx() ctx: Context, @Message('text') text: string) {
|
||||
if (ctx.session.__scenes.state.hasOwnProperty('answering')) {
|
||||
return this.onText(text, ctx);
|
||||
}
|
||||
await ctx.reply(
|
||||
'Ответы на вопросы будут появляться туть, кто первый тот победил',
|
||||
);
|
||||
}
|
||||
|
||||
@Command('leave')
|
||||
async onLeaveScene(@Ctx() ctx: Context) {
|
||||
await ctx.scene.leave();
|
||||
}
|
||||
|
||||
@Command('cards')
|
||||
async onCardCommand(@Ctx() ctx: Context) {
|
||||
this.logger.verbose(`cards command (quiz)`);
|
||||
this.gameService.emit({ cmd: 'GetCards'}, { user: ctx.from.id, inline: false});
|
||||
}
|
||||
|
||||
@Command('next')
|
||||
async onNextCommand(@Ctx() ctx: Context) {
|
||||
if(ctx.from.id === 11178819) {
|
||||
this.gameService.emit({ cmd: 'CompleteQueue'}, { user: ctx.from.id })
|
||||
}
|
||||
}
|
||||
|
||||
@Command('start')
|
||||
async onCommandStart(@Ctx() ctx: Context) {
|
||||
await ctx.scene.leave();
|
||||
this.globalCmd.printCommands(ctx);
|
||||
}
|
||||
|
||||
@On('callback_query')
|
||||
async onInlineQuery(@Ctx() ctx: Context) {
|
||||
this.gameService.emit({ cmd: 'ApplyDebuff'}, { ...ctx.callbackQuery, from: ctx.from.id });
|
||||
this.logger.verbose(`emit callback for ${ctx.callbackQuery}`);
|
||||
}
|
||||
@On('text')
|
||||
async onText(@Message('text') text: string, @Ctx() ctx: Context) {
|
||||
console.log(text);
|
||||
//console.log(JSON.stringify(ctx));
|
||||
if(text.startsWith('/')) {
|
||||
await ctx.scene.leave();
|
||||
return;
|
||||
}
|
||||
if (text.includes(Messages.EMOJI_CARD)) {
|
||||
this.gameService.emit({ cmd: 'CardPlayed'}, { text, user: ctx.message.from.id })
|
||||
return;
|
||||
}
|
||||
if (text.includes(Messages.EMOJI_PLAYER)) {
|
||||
this.gameService.emit({
|
||||
cmd: 'PLayerSelected'
|
||||
}, {
|
||||
text, user: ctx.message.from.id
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.logger.verbose(`Answer from: ${ctx.message.from.first_name}, validating`);
|
||||
this.gameService.send(
|
||||
{ cmd: 'ValidateAnswer'},
|
||||
{ answer: text, user: ctx.message.from.id, name: ctx.message.from.first_name })
|
||||
.subscribe(
|
||||
(res) => {
|
||||
if(res.valid) {
|
||||
ctx.replyWithMarkdownV2('Верно', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
ctx.replyWithMarkdownV2('Ответ неверный', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
40
src/bot/scenes/register.name.prompt.ts
Normal file
40
src/bot/scenes/register.name.prompt.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { REGISTER_NAME_PROMPT_SCENE, REGISTER_PHOTO_SCENE } from "./scenes.const";
|
||||
import { Command, Ctx, Hears, On, Scene, SceneEnter, SceneLeave } from "nestjs-telegraf";
|
||||
import {Context} from "../context.interface";
|
||||
import {Inject, Logger} from "@nestjs/common";
|
||||
import AppConsts from "../../constants";
|
||||
import {ClientProxy} from "@nestjs/microservices";
|
||||
@Scene(REGISTER_NAME_PROMPT_SCENE)
|
||||
export class RegisterNamePrompt {
|
||||
private logger = new Logger(RegisterNamePrompt.name);
|
||||
constructor(@Inject(AppConsts.GameServiceName) private gameService: ClientProxy) {
|
||||
}
|
||||
@On('message')
|
||||
async onMessage(@Ctx() ctx: Context) {
|
||||
const name = (<any>ctx.message).text;
|
||||
this.logger.verbose(`Message from ${ctx.message.from.first_name} [Scene register]`);
|
||||
this.gameService.send(
|
||||
{ cmd: 'RegisterUser'},
|
||||
{
|
||||
name: name,
|
||||
telegramId: ctx.message.from.id,
|
||||
chatId: ctx.chat.id
|
||||
}).subscribe(async (result) => {
|
||||
this.logger.verbose(`${ctx.message.from.first_name} User registered`);
|
||||
await ctx.replyWithMarkdownV2('Охуенчик, добро пожаловать\\!', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
}
|
||||
});
|
||||
await ctx.scene.enter(REGISTER_PHOTO_SCENE);
|
||||
await ctx.reply(`Приятно познакомиться, ${name}!`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@SceneLeave()
|
||||
async sceneLeave(@Ctx() ctx: Context)
|
||||
{
|
||||
await ctx.scene.leave();
|
||||
}
|
||||
}
|
||||
93
src/bot/scenes/register.photo.scene.ts
Normal file
93
src/bot/scenes/register.photo.scene.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import {
|
||||
Command,
|
||||
Ctx,
|
||||
InjectBot,
|
||||
Message,
|
||||
On,
|
||||
Scene,
|
||||
SceneEnter,
|
||||
SceneLeave,
|
||||
} from 'nestjs-telegraf';
|
||||
import { REGISTER_PHOTO_SCENE } from './scenes.const';
|
||||
import { Telegraf } from 'telegraf';
|
||||
import { GlobalCommands } from '../global-commands';
|
||||
import { Inject, Logger } from '@nestjs/common';
|
||||
import { ClientProxy } from '@nestjs/microservices';
|
||||
import { catchError } from 'rxjs';
|
||||
import {Context} from "../context.interface";
|
||||
import AppConsts from "../../constants";
|
||||
|
||||
|
||||
@Scene(REGISTER_PHOTO_SCENE)
|
||||
export class RegisterPhotoScene {
|
||||
readonly logger = new Logger(RegisterPhotoScene.name);
|
||||
constructor(
|
||||
@InjectBot() private bot: Telegraf,
|
||||
// private guestService: GuestsService,
|
||||
// private sharedService: SharedService,
|
||||
private globalCmd: GlobalCommands,
|
||||
@Inject(AppConsts.PhotoServiceName) private photoQueue: ClientProxy,
|
||||
@Inject(AppConsts.GameServiceName) private gameService: ClientProxy,
|
||||
) {}
|
||||
|
||||
@SceneEnter()
|
||||
async onSceneEnter(@Ctx() ctx: Context) {
|
||||
await ctx.reply('давай, шли свою фотографию сучка');
|
||||
this.globalCmd.hideKeyboard(ctx);
|
||||
}
|
||||
|
||||
@On('document')
|
||||
async onDocument(@Ctx() ctx: Context) {
|
||||
this.logger.warn(
|
||||
`${ctx.message.from.first_name} tried to use invalid photo`,
|
||||
);
|
||||
ctx.replyWithMarkdown(
|
||||
'[](https://i.ytimg.com/vi/pd342TR6PCM/hqdefault.jpg) Неправильно, попробуй еще раз',
|
||||
);
|
||||
}
|
||||
|
||||
@On('photo')
|
||||
async onPhoto(@Message('photo') photo, @Ctx() ctx: Context) {
|
||||
const link = await this.bot.telegram.getFileLink(
|
||||
photo[photo.length - 1].file_id,
|
||||
);
|
||||
const regexp = new RegExp(/\.(gif|jpe?g|tiff?|png|webp|bmp)$/i);
|
||||
if (!regexp.test(link.toString())) {
|
||||
await ctx.reply('не тот формат, давай жипег');
|
||||
return;
|
||||
}
|
||||
await ctx.reply(`Ожидай, наша нейросеточка находит твою мородчку 😼`);
|
||||
|
||||
this.photoQueue
|
||||
.send('parse-photo', {
|
||||
user: ctx.message.from.id,
|
||||
url: link.toString(),
|
||||
})
|
||||
.pipe(
|
||||
catchError((val) => {
|
||||
console.log(val);
|
||||
return 'Error';
|
||||
}),
|
||||
)
|
||||
.subscribe(async (r) => {
|
||||
//throw new Error('not implemented');
|
||||
// TODO: Send to GameService for updating image
|
||||
// this.sharedService.sendSocketNotificationToAllClients(
|
||||
// SocketEvents.PHOTOS_UPDATED_EVENT,
|
||||
// {
|
||||
// id: ctx.message.from.id,
|
||||
// },
|
||||
// );
|
||||
this.gameService.emit({ cmd: 'PhotoUpdated' }, { id: ctx.message.from.id })
|
||||
await ctx.reply('Кажись все получилось, чекни на экране что все ок');
|
||||
await this.onLeaveCommand(ctx);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Command('leave')
|
||||
async onLeaveCommand(@Ctx() ctx: Context) {
|
||||
await ctx.scene.leave();
|
||||
}
|
||||
}
|
||||
65
src/bot/scenes/register.scene.ts
Normal file
65
src/bot/scenes/register.scene.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { REGISTER_NAME_PROMPT_SCENE, REGISTER_PHOTO_SCENE, REGISTER_SCENE_ID } from "./scenes.const";
|
||||
import {
|
||||
Command,
|
||||
Ctx,
|
||||
Hears,
|
||||
Scene,
|
||||
SceneEnter,
|
||||
SceneLeave,
|
||||
} from 'nestjs-telegraf';
|
||||
import { Context } from '../context.interface';
|
||||
import { Markup } from 'telegraf';
|
||||
import { Messages } from '../tg.text';
|
||||
import AppConsts from "../../constants";
|
||||
import {Inject} from "@nestjs/common";
|
||||
import {ClientProxy} from "@nestjs/microservices";
|
||||
@Scene(REGISTER_SCENE_ID)
|
||||
export class RegisterScene {
|
||||
constructor(@Inject(AppConsts.GameServiceName) private gameService: ClientProxy) {}
|
||||
@SceneEnter()
|
||||
onSceneEnter(@Ctx() ctx: Context) {
|
||||
const reply = `Шалом-шалом ✋\r\n
|
||||
Я могу тебя звать ${ctx.message.from.first_name}?
|
||||
`;
|
||||
ctx.reply(
|
||||
reply,
|
||||
Markup.keyboard([
|
||||
Markup.button.text(Messages.THATS_ME),
|
||||
Markup.button.text(Messages.NOT_ME),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
@Hears(Messages.THATS_ME)
|
||||
async onAgree(@Ctx() ctx: Context) {
|
||||
this.gameService.send(
|
||||
{ cmd: 'RegisterUser'},
|
||||
{
|
||||
name: ctx.message.from.first_name,
|
||||
telegramId: ctx.message.from.id,
|
||||
chatId: ctx.chat.id
|
||||
}).subscribe(async (result) => {
|
||||
await ctx.replyWithMarkdownV2('Охуенчик, добро пожаловать\\!', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
},
|
||||
});
|
||||
await ctx.scene.enter(REGISTER_PHOTO_SCENE);
|
||||
})
|
||||
}
|
||||
|
||||
@Hears(Messages.NOT_ME)
|
||||
async onDisagree(@Ctx() ctx: Context) {
|
||||
await ctx.replyWithMarkdownV2('Тогда назови себя', {
|
||||
reply_markup: {
|
||||
remove_keyboard: true,
|
||||
},
|
||||
});
|
||||
await ctx.scene.enter(REGISTER_NAME_PROMPT_SCENE);
|
||||
}
|
||||
|
||||
@Command('leave')
|
||||
async onLeaveCommand(ctx: Context): Promise<void> {
|
||||
await ctx.scene.leave();
|
||||
}
|
||||
}
|
||||
4
src/bot/scenes/scenes.const.ts
Normal file
4
src/bot/scenes/scenes.const.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export const REGISTER_SCENE_ID = 'REGISTER_SCENE';
|
||||
export const REGISTER_NAME_PROMPT_SCENE = 'REGISTER_NAME_PROMPT_SCENE';
|
||||
export const QUIZ_SCENE = 'QUIZ_SCENE';
|
||||
export const REGISTER_PHOTO_SCENE = 'REGISTER_PHOTO_SCENE';
|
||||
7
src/bot/send-message.interface.ts
Normal file
7
src/bot/send-message.interface.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import {ExtraReplyMessage} from "telegraf/typings/telegram-types";
|
||||
|
||||
export interface SendMessageInterface {
|
||||
chatId: number;
|
||||
message: string;
|
||||
extra: ExtraReplyMessage | undefined;
|
||||
}
|
||||
13
src/bot/tg.text.ts
Normal file
13
src/bot/tg.text.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export class Messages {
|
||||
static IM_IN = 'Я в деле 😎';
|
||||
static THATS_ME = '🥸 Да, енто я';
|
||||
static NOT_ME = '🙅 Нет, зови меня иначе';
|
||||
static GO = 'Поехали';
|
||||
static CHANGE_PHOTO = 'Залить фоточку новую';
|
||||
static NOTHING_THANKS = 'Не, спасибо, ничего не надо';
|
||||
static answerNumbers: string[] = ['1. ', '2. ', '3. ', '4. '];
|
||||
static SELECT_CARD = 'Сыграть карту?';
|
||||
static EMOJI_CARD = '🃏';
|
||||
static EMOJI_PLAYER = '👤';
|
||||
}
|
||||
|
||||
4
src/constants.ts
Normal file
4
src/constants.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export default class AppConsts {
|
||||
static GameServiceName = 'GameService';
|
||||
static PhotoServiceName = 'tgd_photos';
|
||||
}
|
||||
31
src/main.ts
Normal file
31
src/main.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import {NestFactory} from '@nestjs/core';
|
||||
import {AppModule} from './app.module';
|
||||
import {MicroserviceOptions, Transport} from "@nestjs/microservices";
|
||||
import * as process from "process";
|
||||
import {Logger} from "@nestjs/common";
|
||||
import {ConfigService} from "@nestjs/config";
|
||||
|
||||
|
||||
async function bootstrap() {
|
||||
//const nestApp = await NestFactory.create(AppModule, {
|
||||
// logger: new Logger(),
|
||||
//});
|
||||
//const configService = nestApp.get<ConfigService>(ConfigService);
|
||||
//const rmq_url = configService.get<string>('RMQ_URL');
|
||||
//const rmq_outbox_q = configService.get<string>('RMQ_OUTBOX_Q');
|
||||
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
|
||||
AppModule,
|
||||
{
|
||||
transport: Transport.RMQ,
|
||||
options: {
|
||||
urls: [process.env.RMQ_URL],
|
||||
queue: process.env.RMQ_COMMANDS_OUTPUT_Q,
|
||||
queueOptions: {
|
||||
durable: false,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
await app.listen();
|
||||
}
|
||||
bootstrap();
|
||||
37
src/message.controller.ts
Normal file
37
src/message.controller.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import {Controller, Inject, Logger} from "@nestjs/common";
|
||||
import {MessagePattern, Payload} from "@nestjs/microservices";
|
||||
import {SendMessageInterface} from "./bot/send-message.interface";
|
||||
import {InjectBot} from "nestjs-telegraf";
|
||||
import {Telegraf} from "telegraf";
|
||||
import { BotCommand } from "telegraf/typings/core/types/typegram";
|
||||
|
||||
@Controller()
|
||||
export class MessageController {
|
||||
private readonly logger = new Logger(MessageController.name);
|
||||
constructor(@InjectBot() private bot: Telegraf) {
|
||||
}
|
||||
@MessagePattern({ cmd: 'SendMessage' } )
|
||||
async sendMessage(@Payload() data: SendMessageInterface) {
|
||||
this.logger.verbose(`SendMessage action ${JSON.stringify(data)}`);
|
||||
await this.bot.telegram.sendMessage(data.chatId, data.message, data.extra);
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'SetCommands'})
|
||||
async setCommands(@Payload() data: BotCommand[]) {
|
||||
this.logger.log('update commands enter')
|
||||
await this.bot.telegram.setMyCommands(data);
|
||||
console.log(await this.bot.telegram.getMyCommands());
|
||||
}
|
||||
|
||||
@MessagePattern({ cmd: 'ResetCommands'})
|
||||
async resetCommands(@Payload() data: null) {
|
||||
this.logger.log('reset commands enter')
|
||||
await this.bot.telegram.deleteMyCommands();
|
||||
await this.bot.telegram.setMyCommands([{
|
||||
command: 'start',
|
||||
description: 'главное меню'
|
||||
}]);
|
||||
console.log(await this.bot.telegram.getMyCommands());
|
||||
}
|
||||
|
||||
}
|
||||
3
src/middleware/session.middleware.ts
Normal file
3
src/middleware/session.middleware.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { session } from 'telegraf';
|
||||
|
||||
export const sessionMiddleware = session();
|
||||
24
test/app.e2e-spec.ts
Normal file
24
test/app.e2e-spec.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
9
test/jest-e2e.json
Normal file
9
test/jest-e2e.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
4
tsconfig.build.json
Normal file
4
tsconfig.build.json
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue