This commit is contained in:
Errormacr
2023-11-18 19:04:09 +03:00
21 changed files with 232 additions and 61 deletions

6
.gitignore vendored
View File

@@ -4,4 +4,8 @@
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
node_modules
# Env files
**/.env
**/.env.*
!**/.env.example

View File

@@ -4,6 +4,5 @@
"semi": true,
"tabWidth": 4,
"printWidth": 150,
"bracketSpacing": true,
"endOfLine": "auto"
"bracketSpacing": true
}

View File

@@ -10,5 +10,5 @@
"**/node_modules": true
},
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "esbenp.prettier-vscode",
}

7
backend/.env.example Normal file
View File

@@ -0,0 +1,7 @@
DATABASE_PASSWORD=postgres
DATABASE_NAME=bot_db
DATABASE_USER=postgres
DATABASE_HOST=localhost
DATABASE_PORT=5432
SERVER_PORT=3000

20
backend/config/index.ts Normal file
View File

@@ -0,0 +1,20 @@
import { config as configInit } from 'dotenv';
configInit();
export const config = {
database: {
type: 'postgres',
host: process.env.DATABASE_HOST || 'localhost',
port: +process.env.DATABASE_PORT || 5432,
username: process.env.DATABASE_USERNAME || 'postgres',
password: process.env.DATABASE_PASSWORD || '',
database: process.env.DATABASE_DB || 'bot_db',
synchronize: true,
logging: false,
autoLoadEntities: true,
},
server: {
port: +process.env.SERVER_PORT || 8080,
},
};

View File

@@ -0,0 +1,14 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity()
export class User {
constructor(props?: Partial<User>) {
Object.assign(this, props);
}
@PrimaryColumn()
public id!: string;
@Column({ nullable: true })
public user_name: string;
}

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './database/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
exports: [TypeOrmModule],
})
export class LibsModule {}

View File

@@ -23,7 +23,9 @@
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"nestjs": "^0.0.1",
"@nestjs/swagger": "^7.1.16",
"@nestjs/typeorm": "^10.0.1",
"dotenv": "^16.3.1",
"pg": "^8.11.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",

80
backend/pnpm-lock.yaml generated
View File

@@ -14,9 +14,15 @@ dependencies:
'@nestjs/platform-express':
specifier: ^10.0.0
version: 10.2.8(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)
nestjs:
specifier: ^0.0.1
version: 0.0.1
'@nestjs/swagger':
specifier: ^7.1.16
version: 7.1.16(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(reflect-metadata@0.1.13)
'@nestjs/typeorm':
specifier: ^10.0.1
version: 10.0.1(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17)
dotenv:
specifier: ^16.3.1
version: 16.3.1
pg:
specifier: ^8.11.3
version: 8.11.3
@@ -941,6 +947,23 @@ packages:
transitivePeerDependencies:
- encoding
/@nestjs/mapped-types@2.0.3(@nestjs/common@10.2.8)(reflect-metadata@0.1.13):
resolution: {integrity: sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==}
peerDependencies:
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
class-transformer: ^0.4.0 || ^0.5.0
class-validator: ^0.13.0 || ^0.14.0
reflect-metadata: ^0.1.12
peerDependenciesMeta:
class-transformer:
optional: true
class-validator:
optional: true
dependencies:
'@nestjs/common': 10.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1)
reflect-metadata: 0.1.13
dev: false
/@nestjs/platform-express@10.2.8(@nestjs/common@10.2.8)(@nestjs/core@10.2.8):
resolution: {integrity: sha512-WoSSVtwIRc5AdGMHWVzWZK4JZLT0f4o2xW8P9gQvcX+omL8W1kXCfY8GQYXNBG84XmBNYH8r0FtC8oMe/lH5NQ==}
peerDependencies:
@@ -972,6 +995,33 @@ packages:
- chokidar
dev: true
/@nestjs/swagger@7.1.16(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(reflect-metadata@0.1.13):
resolution: {integrity: sha512-f9KBk/BX9MUKPTj7tQNYJ124wV/jP5W2lwWHLGwe/4qQXixuDOo39zP55HIJ44LE7S04B7BOeUOo9GBJD/vRcw==}
peerDependencies:
'@fastify/static': ^6.0.0
'@nestjs/common': ^9.0.0 || ^10.0.0
'@nestjs/core': ^9.0.0 || ^10.0.0
class-transformer: '*'
class-validator: '*'
reflect-metadata: ^0.1.12
peerDependenciesMeta:
'@fastify/static':
optional: true
class-transformer:
optional: true
class-validator:
optional: true
dependencies:
'@nestjs/common': 10.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.2.8(@nestjs/common@10.2.8)(@nestjs/platform-express@10.2.8)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/mapped-types': 2.0.3(@nestjs/common@10.2.8)(reflect-metadata@0.1.13)
js-yaml: 4.1.0
lodash: 4.17.21
path-to-regexp: 3.2.0
reflect-metadata: 0.1.13
swagger-ui-dist: 5.9.1
dev: false
/@nestjs/testing@10.2.8(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(@nestjs/platform-express@10.2.8):
resolution: {integrity: sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==}
peerDependencies:
@@ -991,6 +1041,23 @@ packages:
tslib: 2.6.2
dev: true
/@nestjs/typeorm@10.0.1(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17):
resolution: {integrity: sha512-YVFYL7D25VAVp5/G+KLXIgsRfYomA+VaFZBpm2rtwrrBOmkXNrxr7kuI2bBBO/Xy4kKBDe6wbvIVVFeEA7/ngA==}
peerDependencies:
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
'@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0
reflect-metadata: ^0.1.13
rxjs: ^7.2.0
typeorm: ^0.3.0
dependencies:
'@nestjs/common': 10.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.2.8(@nestjs/common@10.2.8)(@nestjs/platform-express@10.2.8)(reflect-metadata@0.1.13)(rxjs@7.8.1)
reflect-metadata: 0.1.13
rxjs: 7.8.1
typeorm: 0.3.17(pg@8.11.3)(ts-node@10.9.1)
uuid: 9.0.1
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -1653,7 +1720,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/array-flatten@1.1.1:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
@@ -3764,7 +3830,6 @@ packages:
hasBin: true
dependencies:
argparse: 2.0.1
dev: true
/jsesc@2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
@@ -3867,7 +3932,6 @@ packages:
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: true
/log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
@@ -5006,6 +5070,10 @@ packages:
engines: {node: '>= 0.4'}
dev: true
/swagger-ui-dist@5.9.1:
resolution: {integrity: sha512-5zAx+hUwJb9T3EAntc7TqYkV716CMqG6sZpNlAAMOMWkNXRYxGkN8ADIvD55dQZ10LxN90ZM/TQmN7y1gpICnw==}
dev: false
/symbol-observable@4.0.0:
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
engines: {node: '>=0.10'}

View File

@@ -1,22 +0,0 @@
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!');
});
});
});

View File

@@ -1,12 +0,0 @@
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();
}
}

View File

@@ -1,10 +1,13 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { config } from 'config';
import { LibsModule } from 'libs/libs.module';
import { AppInitService } from './modules/initialization/app.init.service';
import { UserModule } from './modules/user/user.module';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
imports: [LibsModule, UserModule, TypeOrmModule.forRoot(<TypeOrmModuleOptions>config.database)],
controllers: [],
providers: [AppInitService],
})
export class AppModule {}

View File

@@ -1,8 +0,0 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}

View File

@@ -1,8 +1,14 @@
import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { config } from 'config';
import { AppModule } from './app.module';
import { swagger } from './swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
const app = await NestFactory.create(AppModule, {
logger: ['log', 'debug', 'error', 'warn', 'verbose'],
});
swagger(app);
await app.listen(config.server.port, () => Logger.log(`Server started on port ${config.server.port}`));
}
bootstrap();

View File

@@ -0,0 +1,11 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from 'libs/database/user.entity';
import { Repository } from 'typeorm';
@Injectable()
export class AppInitService implements OnModuleInit {
constructor(@InjectRepository(User) private userRepository: Repository<User>) {}
async onModuleInit() {}
}

View File

@@ -0,0 +1,18 @@
import { Body, Controller, Post } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { IGetUser } from './user.dto';
import { UserService } from './user.service';
@ApiTags('User')
@Controller('user')
export class UserController {
constructor(private adminService: UserService) {}
@ApiOperation({
description: 'Create or get user from db',
})
@Post('get')
async getUser(@Body() data: IGetUser) {
return await this.adminService.getUser(data);
}
}

View File

@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class IGetUser {
@ApiProperty({ description: 'telegram id', example: '123456' }) readonly id: string;
@ApiProperty({ description: 'telegram username', example: 'durov' }) readonly username?: string;
}

View File

@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { LibsModule } from 'libs/libs.module';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
imports: [LibsModule],
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}

View File

@@ -0,0 +1,27 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from 'libs/database/user.entity';
import { Repository } from 'typeorm';
import { IGetUser } from './user.dto';
@Injectable()
export class UserService {
private readonly logger: Logger = new Logger(UserService.name);
constructor(@InjectRepository(User) private userRepository: Repository<User>) {}
async getUser(data: IGetUser) {
try {
this.logger.debug(`[admin.getUser] data: ${JSON.stringify(data)}`);
let user = await this.userRepository.findOne({
where: { id: data.id },
});
if (!user) {
user = await this.userRepository.save({ id: data.id, user_name: data.username });
this.logger.log(`User ${data.id} created`);
}
return user;
} catch (error) {
this.logger.log(`[getUser] ${JSON.stringify({ error })}`);
}
}
}

9
backend/src/swagger.ts Normal file
View File

@@ -0,0 +1,9 @@
import { INestApplication } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
export function swagger(app: INestApplication): INestApplication {
const config = new DocumentBuilder().setTitle('Neuro website').setDescription('Some description').setVersion('0.1').build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
return app;
}