fix: prettier)

This commit is contained in:
2024-07-03 23:49:05 +03:00
parent a865789efa
commit 5e570a4f60
47 changed files with 5152 additions and 2835 deletions

View File

@@ -6,6 +6,9 @@ DATABASE_PORT=5432
SERVER_PORT=3000 SERVER_PORT=3000
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=123 REDIS_PASSWORD=123
REDIS_DB=1
JWT_SECRET=secret JWT_SECRET=secret

View File

@@ -1,25 +1,22 @@
module.exports = { module.exports = {
parser: '@typescript-eslint/parser', parser: "@typescript-eslint/parser",
parserOptions: { parserOptions: {
project: 'tsconfig.json', project: "tsconfig.json",
tsconfigRootDir: __dirname, tsconfigRootDir: __dirname,
sourceType: 'module', sourceType: "module",
}, },
plugins: ['@typescript-eslint/eslint-plugin'], plugins: ["@typescript-eslint/eslint-plugin"],
extends: [ extends: ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"],
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true, root: true,
env: { env: {
node: true, node: true,
jest: true, jest: true,
}, },
ignorePatterns: ['.eslintrc.js'], ignorePatterns: [".eslintrc.js"],
rules: { rules: {
'@typescript-eslint/interface-name-prefix': 'off', "@typescript-eslint/interface-name-prefix": "off",
'@typescript-eslint/explicit-function-return-type': 'off', "@typescript-eslint/explicit-function-return-type": "off",
'@typescript-eslint/explicit-module-boundary-types': 'off', "@typescript-eslint/explicit-module-boundary-types": "off",
'@typescript-eslint/no-explicit-any': 'off', "@typescript-eslint/no-explicit-any": "off",
}, },
}; };

Binary file not shown.

View File

@@ -1,22 +1,22 @@
import { CacheModuleAsyncOptions } from '@nestjs/cache-manager'; import { CacheModuleAsyncOptions } from "@nestjs/cache-manager";
import { redisStore } from 'cache-manager-redis-store'; import { redisStore } from "cache-manager-redis-store";
import { config } from 'config'; import { config } from "config";
export const RedisOptions: CacheModuleAsyncOptions = { export const RedisOptions: CacheModuleAsyncOptions = {
isGlobal: true, isGlobal: true,
useFactory: async () => { useFactory: async () => {
const store = await redisStore({ const store = await redisStore({
socket: { socket: {
host: config.redis.redis_host, host: config.redis.redis_host,
port: config.redis.redis_port, port: config.redis.redis_port,
}, },
database: config.redis.redis_database, database: config.redis.redis_database,
password: config.redis.redis_password, password: config.redis.redis_password,
ttl: 30, ttl: 30,
}); });
return { return {
store: () => store, store: () => store,
isGlobal: true, isGlobal: true,
}; };
}, },
}; };

View File

@@ -1,19 +1,19 @@
import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm";
import { User } from './user.entity'; import { User } from "./user.entity";
@Entity() @Entity()
export class Admin { export class Admin {
constructor(props?: Partial<Admin>) { constructor(props?: Partial<Admin>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id!: number; public id!: number;
@Column({ nullable: false }) @Column({ nullable: false })
public user_id!: string; public user_id!: string;
@OneToOne(() => User, (user) => user.id, { onDelete: 'CASCADE', onUpdate: 'CASCADE' }) @OneToOne(() => User, (user) => user.id, { onDelete: "CASCADE", onUpdate: "CASCADE" })
@JoinColumn({ name: 'user_id' }) @JoinColumn({ name: "user_id" })
public user!: User; public user!: User;
} }

View File

@@ -1,25 +1,25 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
import { Post } from './post.entity'; import { Post } from "./post.entity";
@Entity() @Entity()
export class Image { export class Image {
constructor(props?: Partial<Image>) { constructor(props?: Partial<Image>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryColumn() @PrimaryColumn()
public message_id!: number; public message_id!: number;
@Column({ nullable: false }) @Column({ nullable: false })
public file_id!: string; public file_id!: string;
@Column({ default: false }) @Column({ default: false })
public has_spoiler!: boolean; public has_spoiler!: boolean;
@Column({ nullable: false }) @Column({ nullable: false })
public post_uuid!: string; public post_uuid!: string;
@ManyToOne(() => Post, (post) => post.uuid, { onDelete: 'CASCADE' }) @ManyToOne(() => Post, (post) => post.uuid, { onDelete: "CASCADE" })
@JoinColumn({ name: 'post_uuid' }) @JoinColumn({ name: "post_uuid" })
public post!: Post; public post!: Post;
} }

View File

@@ -1,22 +1,22 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { ProxyUser } from './proxy_user.entity'; import { ProxyUser } from "./proxy_user.entity";
@Entity() @Entity()
export class Payment { export class Payment {
constructor(props?: Partial<Payment>) { constructor(props?: Partial<Payment>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryGeneratedColumn('increment') @PrimaryGeneratedColumn("increment")
public id!: number; public id!: number;
@Column() @Column()
public user_uuid!: string; public user_uuid!: string;
@Column({ type: 'timestamptz' }) @Column({ type: "timestamptz" })
public payTime!: Date; public payTime!: Date;
@ManyToOne(() => ProxyUser, { onDelete: 'CASCADE' }) @ManyToOne(() => ProxyUser, { onDelete: "CASCADE" })
@JoinColumn({ name: 'user_uuid' }) @JoinColumn({ name: "user_uuid" })
user: ProxyUser; user: ProxyUser;
} }

View File

@@ -1,43 +1,43 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { Admin } from './admin.entity'; import { Admin } from "./admin.entity";
import { Image } from './image.entity'; import { Image } from "./image.entity";
@Entity() @Entity()
export class Post { export class Post {
constructor(props?: Partial<Post>) { constructor(props?: Partial<Post>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn("uuid")
public uuid!: string; public uuid!: string;
@Column({ default: false }) @Column({ default: false })
public posted!: boolean; public posted!: boolean;
@Column({ nullable: true }) @Column({ nullable: true })
public text?: string; public text?: string;
@Column({ nullable: true }) @Column({ nullable: true })
public media_group_id: string; public media_group_id: string;
@Column({ type: 'timestamptz' }) @Column({ type: "timestamptz" })
public timestamp!: Date; public timestamp!: Date;
@Column({ type: 'timestamptz', nullable: true }) @Column({ type: "timestamptz", nullable: true })
public edit_timestamp?: Date; public edit_timestamp?: Date;
@Column({ nullable: false }) @Column({ nullable: false })
public from_user_id!: string; public from_user_id!: string;
@ManyToOne(() => Admin, (admin) => admin.user.id) @ManyToOne(() => Admin, (admin) => admin.user.id)
@JoinColumn({ name: 'from_user_id', referencedColumnName: 'user_id' }) @JoinColumn({ name: "from_user_id", referencedColumnName: "user_id" })
public from_user!: Admin; public from_user!: Admin;
@OneToMany(() => Image, (image) => image.post) @OneToMany(() => Image, (image) => image.post)
public images: Image[]; public images: Image[];
@Column({ nullable: true }) @Column({ nullable: true })
public message_entities?: string; public message_entities?: string;
@Column({ default: false }) @Column({ default: false })
public deleted: boolean; public deleted: boolean;
} }

View File

@@ -1,35 +1,39 @@
import { Column, Entity, JoinColumn, OneToMany, OneToOne, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, JoinColumn, OneToMany, OneToOne, PrimaryGeneratedColumn } from "typeorm";
import { Payment } from './payment.entity'; import { Payment } from "./payment.entity";
import { User } from './user.entity'; import { User } from "./user.entity";
@Entity() @Entity()
export class ProxyUser { export class ProxyUser {
constructor(props?: Partial<ProxyUser>) { constructor(props?: Partial<ProxyUser>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn("uuid")
public uuid!: string; public uuid!: string;
@Column({ nullable: false, unique: true }) @Column({ nullable: false, unique: true })
public userName!: string; public userName!: string;
@Column({ nullable: true }) @Column({ nullable: true })
public description?: string; public description?: string;
@Column({ nullable: false }) @Column({ nullable: false })
public link!: string; public link!: string;
@Column({ nullable: false, type: 'timestamptz' }) @Column({ nullable: false, type: "timestamptz" })
public connectDate!: Date; public connectDate!: Date;
@Column({ nullable: true }) @Column({ nullable: true })
public user_id!: string; public user_id!: string;
@OneToOne(() => User, (user) => user.id, { onDelete: 'CASCADE', onUpdate: 'CASCADE', nullable: true }) @OneToOne(() => User, (user) => user.id, {
@JoinColumn({ name: 'user_id' }) onDelete: "CASCADE",
public user?: User; onUpdate: "CASCADE",
nullable: true,
})
@JoinColumn({ name: "user_id" })
public user?: User;
@OneToMany(() => Payment, (payment) => payment.user) @OneToMany(() => Payment, (payment) => payment.user)
public payments: Payment[]; public payments: Payment[];
} }

View File

@@ -1,20 +1,20 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity() @Entity()
export class BotSettings { export class BotSettings {
constructor(props?: Partial<BotSettings>) { constructor(props?: Partial<BotSettings>) {
Object.assign(this, props); Object.assign(this, props);
} }
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn("uuid")
public uuid!: string; public uuid!: string;
@Column({ type: 'text', array: true }) @Column({ type: "text", array: true })
public messageTimes!: string[]; public messageTimes!: string[];
@Column() @Column()
public channel!: string; public channel!: string;
@Column({ default: false }) @Column({ default: false })
public isActive!: boolean; public isActive!: boolean;
} }

View File

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

View File

@@ -1,5 +1,5 @@
export enum EGetAll { export enum EGetAll {
all = 'all', all = "all",
will_post = 'will-post', will_post = "will-post",
posted = 'posted', posted = "posted",
} }

View File

@@ -23,11 +23,12 @@
"@nestjs/cache-manager": "2.2.1", "@nestjs/cache-manager": "2.2.1",
"@nestjs/common": "^10.0.0", "@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0", "@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.3", "@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0", "@nestjs/platform-express": "^10.0.0",
"@nestjs/swagger": "^7.1.16", "@nestjs/swagger": "^7.1.16",
"@nestjs/typeorm": "^10.0.1", "@nestjs/typeorm": "^10.0.1",
"bcrypt": "^5.1.1", "bcryptjs": "^2.4.3",
"cache-manager": "^5.4.0", "cache-manager": "^5.4.0",
"cache-manager-redis-store": "^3.0.1", "cache-manager-redis-store": "^3.0.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
@@ -42,6 +43,8 @@
"@nestjs/cli": "^10.0.0", "@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0", "@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0", "@nestjs/testing": "^10.0.0",
"@types/bcryptjs": "^2.4.6",
"@types/bun": "latest",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/jest": "^29.5.2", "@types/jest": "^29.5.2",
"@types/node": "^20.3.1", "@types/node": "^20.3.1",
@@ -60,8 +63,7 @@
"ts-loader": "^9.4.3", "ts-loader": "^9.4.3",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3", "typescript": "^5.1.3"
"@types/bun": "latest"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [

5756
backend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
@ApiTags('App') @ApiTags("App")
@Controller() @Controller()
export class AppController { export class AppController {
@ApiOperation({ description: 'check site availability' }) @ApiOperation({ description: "check site availability" })
@Get('ping') @Get("ping")
pingpong() { pingpong() {
return 'pong'; return "pong";
} }
} }

View File

@@ -1,36 +1,33 @@
import { CacheModule } from '@nestjs/cache-manager'; import { CacheModule } from "@nestjs/cache-manager";
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; import { TypeOrmModule, TypeOrmModuleOptions } from "@nestjs/typeorm";
import { config } from 'config'; import { config } from "config";
import { RedisOptions } from 'config/redis-options'; import { RedisOptions } from "config/redis-options";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { AppController } from './app.controller'; import { AppController } from "./app.controller";
import { AdminModule } from './modules/admin/admin.module'; import { AdminModule } from "./modules/admin/admin.module";
import { AuthModule } from './modules/auth/auth.module'; import { AuthModule } from "./modules/auth/auth.module";
import { ImageModule } from './modules/image/image.module'; import { ImageModule } from "./modules/image/image.module";
import { AppInitService } from './modules/initialization/app.init.service'; import { AppInitService } from "./modules/initialization/app.init.service";
import { PostModule } from './modules/post/post.module'; import { PostModule } from "./modules/post/post.module";
import { ProxyModule } from './modules/proxy/proxy.module'; import { ProxyModule } from "./modules/proxy/proxy.module";
import { SettingsModule } from './modules/settings/settings.module'; import { SettingsModule } from "./modules/settings/settings.module";
import { UserModule } from './modules/user/user.module'; import { UserModule } from "./modules/user/user.module";
@Module({ @Module({
imports: [ imports: [
AuthModule, AuthModule,
CacheModule.registerAsync(RedisOptions), CacheModule.registerAsync(RedisOptions),
LibsModule, LibsModule,
PostModule, PostModule,
AdminModule, AdminModule,
UserModule, UserModule,
ImageModule, ImageModule,
ProxyModule, ProxyModule,
SettingsModule, SettingsModule,
TypeOrmModule.forRoot(<TypeOrmModuleOptions>config.database), TypeOrmModule.forRoot(<TypeOrmModuleOptions>config.database),
], ],
controllers: [AppController], controllers: [AppController],
providers: [ providers: [AppInitService],
AppInitService,
// { provide: APP_GUARD, useClass: AuthGuard }, // Если будет необходима авторизация
],
}) })
export class AppModule {} export class AppModule {}

View File

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

View File

@@ -1,26 +1,26 @@
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager'; import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager";
import { Controller, Get, Param, UseInterceptors } from '@nestjs/common'; import { Controller, Get, Param, UseInterceptors } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { AdminService } from './admin.service'; import { AdminService } from "./admin.service";
@ApiTags('Admin') @ApiTags("Admin")
@Controller('admin') @Controller("admin")
export class AdminController { export class AdminController {
constructor(private adminService: AdminService) {} constructor(private adminService: AdminService) {}
@ApiOperation({ @ApiOperation({
description: 'Get admins from db', description: "Get admins from db",
}) })
@CacheKey('admins') @CacheKey("admins")
@CacheTTL({ ttl: 5 } as any) @CacheTTL({ ttl: 5 } as any)
@UseInterceptors(CacheInterceptor) @UseInterceptors(CacheInterceptor)
@Get('get') @Get("get")
async getAdmin() { async getAdmin() {
return await this.adminService.getAdmins(); return await this.adminService.getAdmins();
} }
@ApiOperation({ description: 'Check admin is or not' }) @ApiOperation({ description: "Check admin is or not" })
@Get('is-admin/:id') @Get("is-admin/:id")
async isAdmin(@Param('id') id: string) { async isAdmin(@Param("id") id: string) {
return await this.adminService.checkIsAdmin(id); return await this.adminService.checkIsAdmin(id);
} }
} }

View File

@@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { AdminController } from './admin.controller'; import { AdminController } from "./admin.controller";
import { AdminService } from './admin.service'; import { AdminService } from "./admin.service";
@Module({ @Module({
imports: [LibsModule], imports: [LibsModule],
controllers: [AdminController], controllers: [AdminController],
providers: [AdminService], providers: [AdminService],
}) })
export class AdminModule {} export class AdminModule {}

View File

@@ -1,49 +1,52 @@
import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Cache } from 'cache-manager'; import { Cache } from "cache-manager";
import { Admin } from 'libs/database/admin.entity'; import { Admin } from "libs/database/admin.entity";
import { Repository } from 'typeorm'; import { Repository } from "typeorm";
@Injectable() @Injectable()
export class AdminService { export class AdminService {
private readonly logger: Logger = new Logger(AdminService.name); private readonly logger: Logger = new Logger(AdminService.name);
constructor( constructor(
@InjectRepository(Admin) private adminRepository: Repository<Admin>, @InjectRepository(Admin) private adminRepository: Repository<Admin>,
@Inject(CACHE_MANAGER) private cacheManager: Cache, @Inject(CACHE_MANAGER) private cacheManager: Cache,
) {} ) {}
async getAdmins() { async getAdmins() {
try { try {
this.logger.debug(`[admin.getAdmins]`); this.logger.debug(`[admin.getAdmins]`);
const admins = await this.adminRepository.find({ relations: { user: true }, select: { user_id: true, user: { user_name: true } } }); const admins = await this.adminRepository.find({
const result: { user_id: string; user_name: string }[] = admins.map((admin) => ({ relations: { user: true },
user_id: admin.user_id, select: { user_id: true, user: { user_name: true } },
user_name: admin.user.user_name, });
})); const result: { user_id: string; user_name: string }[] = admins.map((admin) => ({
return result; user_id: admin.user_id,
} catch (error) { user_name: admin.user.user_name,
this.logger.log(`[getAdmin] ${error}`); }));
return []; return result;
} } catch (error) {
this.logger.log(`[getAdmin] ${error}`);
return [];
} }
async checkIsAdmin(id: string) { }
try { async checkIsAdmin(id: string) {
this.logger.debug(`[admin.checkIsAdmin]`); try {
const is_admin = await this.cacheManager.get(`admin_${id}`); this.logger.debug(`[admin.checkIsAdmin]`);
if (is_admin) return is_admin; const is_admin = await this.cacheManager.get(`admin_${id}`);
const admins = await this.adminRepository.findOne({ if (is_admin) return is_admin;
relations: { user: true }, const admins = await this.adminRepository.findOne({
where: { user: { id: id } }, relations: { user: true },
}); where: { user: { id: id } },
if (!admins) { });
await this.cacheManager.set(`admin_${id}`, false, { ttl: 10 } as any); if (!admins) {
return false; await this.cacheManager.set(`admin_${id}`, false, { ttl: 10 } as any);
} return false;
await this.cacheManager.set(`admin_${id}`, true, { ttl: 10 } as any); }
return true; await this.cacheManager.set(`admin_${id}`, true, { ttl: 10 } as any);
} catch (error) { return true;
this.logger.debug(`[checkIsAdmin] ${JSON.stringify({ error })}`); } catch (error) {
return false; this.logger.debug(`[checkIsAdmin] ${JSON.stringify({ error })}`);
} return false;
} }
}
} }

View File

@@ -30,7 +30,6 @@ export class AuthController {
@ApiOperation({ @ApiOperation({
description: "Register into system", description: "Register into system",
}) })
@HttpCode(HttpStatus.CREATED)
@Post("register") @Post("register")
register(@Body() signInDto: LoginDto) { register(@Body() signInDto: LoginDto) {
return this.authService.register(signInDto.username, signInDto.password); return this.authService.register(signInDto.username, signInDto.password);

View File

@@ -2,30 +2,3 @@ import { Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport"; import { AuthGuard } from "@nestjs/passport";
@Injectable() @Injectable()
export class JwtGuard extends AuthGuard("jwt") {} export class JwtGuard extends AuthGuard("jwt") {}
// export class AuthGuard implements CanActivate {
// constructor(private jwtService: JwtService) {}
// async canActivate(context: ExecutionContext): Promise<boolean> {
// const request = context.switchToHttp().getRequest();
// const token = this.extractTokenFromHeader(request);
// if (!token) {
// throw new UnauthorizedException();
// }
// try {
// const payload = await this.jwtService.verifyAsync(token, {
// secret: config.auth.jwt_secret,
// });
// request["user"] = payload;
// } catch {
// throw new UnauthorizedException();
// }
// return true;
// }
// private extractTokenFromHeader(request: Request): string | undefined {
// const [type, token] = request.headers.authorization.split(" ") ?? [];
// return type === "Bearer" ? token : undefined;
// }
// }

View File

@@ -1,7 +1,7 @@
import { Injectable, Logger, UnauthorizedException } from "@nestjs/common"; import { ImATeapotException, Injectable, Logger, UnauthorizedException } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt"; import { JwtService } from "@nestjs/jwt";
import { InjectRepository } from "@nestjs/typeorm"; import { InjectRepository } from "@nestjs/typeorm";
import * as bcrypt from "bcrypt"; import * as bcrypt from "bcryptjs";
import { WebUser } from "libs/database/web_user.entity"; import { WebUser } from "libs/database/web_user.entity";
import { Repository } from "typeorm"; import { Repository } from "typeorm";
@@ -35,6 +35,7 @@ export class AuthService {
} }
async register(username: string, password: string): Promise<{ access_token: string }> { async register(username: string, password: string): Promise<{ access_token: string }> {
if (1) throw new ImATeapotException();
const user = await this.userRepository.findOne({ where: { login: username } }); const user = await this.userRepository.findOne({ where: { login: username } });
if (user) throw new UnauthorizedException("User already exists"); if (user) throw new UnauthorizedException("User already exists");
const salt = await bcrypt.genSalt(); const salt = await bcrypt.genSalt();

View File

@@ -1,16 +1,16 @@
import { Body, Controller, Post } from '@nestjs/common'; import { Body, Controller, Post } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { IAddImage } from './image.dto'; import { IAddImage } from "./image.dto";
import { ImageService } from './image.service'; import { ImageService } from "./image.service";
@ApiTags('Image') @ApiTags("Image")
@Controller('image') @Controller("image")
export class ImageController { export class ImageController {
constructor(private imageService: ImageService) {} constructor(private imageService: ImageService) {}
@ApiOperation({ description: 'A method to add photo to post' }) @ApiOperation({ description: "A method to add photo to post" })
@Post('add') @Post("add")
async addImage(@Body() data: IAddImage) { async addImage(@Body() data: IAddImage) {
return await this.imageService.add(data); return await this.imageService.add(data);
} }
} }

View File

@@ -1,12 +1,23 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from "@nestjs/swagger";
export class IAddImage { export class IAddImage {
// @ApiProperty({ description: 'A post that contains this photo', example: '1212-4324-asdf-23432' }) readonly post_id!: string; // @ApiProperty({ description: 'A post that contains this photo', example: '1212-4324-asdf-23432' }) readonly post_id!: string;
@ApiProperty({ description: 'A telegram file id of photo', example: '1214244' }) readonly file_id!: string; @ApiProperty({ description: "A telegram file id of photo", example: "1214244" })
@ApiProperty({ description: 'Has image the spoiler?', example: false }) readonly has_spoiler!: boolean; readonly file_id!: string;
@ApiProperty({ description: 'A photo message id', example: '123124' }) readonly message_id!: number; @ApiProperty({ description: "Has image the spoiler?", example: false })
@ApiProperty({ description: 'Post text', example: '#neurowaifu', required: false }) readonly post_text?: string; readonly has_spoiler!: boolean;
@ApiProperty({ description: 'A media group id of the photo', example: '1241244', required: false }) readonly media_group_id?: string; @ApiProperty({ description: "A photo message id", example: "123124" })
@ApiProperty({ description: 'Message entities of text', example: '[]' }) readonly message_entities?: string; readonly message_id!: number;
@ApiProperty({ description: 'The id of user that creating post', example: '1234' }) readonly from_user_id!: string; @ApiProperty({ description: "Post text", example: "#neurowaifu", required: false })
readonly post_text?: string;
@ApiProperty({
description: "A media group id of the photo",
example: "1241244",
required: false,
})
readonly media_group_id?: string;
@ApiProperty({ description: "Message entities of text", example: "[]" })
readonly message_entities?: string;
@ApiProperty({ description: "The id of user that creating post", example: "1234" })
readonly from_user_id!: string;
} }

View File

@@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { ImageController } from './image.controller'; import { ImageController } from "./image.controller";
import { ImageService } from './image.service'; import { ImageService } from "./image.service";
@Module({ @Module({
imports: [LibsModule], imports: [LibsModule],
controllers: [ImageController], controllers: [ImageController],
providers: [ImageService], providers: [ImageService],
}) })
export class ImageModule {} export class ImageModule {}

View File

@@ -1,70 +1,78 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
import { Admin } from 'libs/database/admin.entity'; import { Admin } from "libs/database/admin.entity";
import { Image } from 'libs/database/image.entity'; import { Image } from "libs/database/image.entity";
import { Post } from 'libs/database/post.entity'; import { Post } from "libs/database/post.entity";
import { DataSource, EntityManager } from 'typeorm'; import { DataSource, EntityManager } from "typeorm";
import { IAddImage } from './image.dto'; import { IAddImage } from "./image.dto";
@Injectable() @Injectable()
export class ImageService { export class ImageService {
private readonly logger: Logger = new Logger(ImageService.name); private readonly logger: Logger = new Logger(ImageService.name);
constructor(private dataSource: DataSource) {} constructor(private dataSource: DataSource) {}
async add(data: IAddImage) { async add(data: IAddImage) {
try { try {
let created_new = false; let created_new = false;
await this.dataSource.transaction(async (manager: EntityManager) => { await this.dataSource.transaction(async (manager: EntityManager) => {
this.logger.log(`[image.add] data: ${JSON.stringify(data)}`); this.logger.log(`[image.add] data: ${JSON.stringify(data)}`);
if (data.media_group_id) { if (data.media_group_id) {
let post = await manager.findOne(Post, { where: { media_group_id: data.media_group_id } }); let post = await manager.findOne(Post, {
if (post) { where: { media_group_id: data.media_group_id },
await manager.save(Image, { });
post: post, if (post) {
file_id: data.file_id, await manager.save(Image, {
has_spoiler: data.has_spoiler, post: post,
message_id: data.message_id, file_id: data.file_id,
}); has_spoiler: data.has_spoiler,
if (data.post_text) { message_id: data.message_id,
post.text = data.post_text;
post.message_entities = data.message_entities;
post = await manager.save(Post, post);
}
} else {
const user = await manager.findOne(Admin, { where: { user: { id: data.from_user_id } }, relations: { user: true } });
post = await manager.save(Post, {
media_group_id: data.media_group_id,
text: data.post_text,
message_entities: data.message_entities,
timestamp: new Date(),
from_user: user,
});
created_new = true;
await manager.save(Image, {
post: post,
file_id: data.file_id,
has_spoiler: data.has_spoiler,
message_id: data.message_id,
});
}
} else {
const user = await manager.findOne(Admin, { where: { user: { id: data.from_user_id } }, relations: { user: true } });
const post = await manager.save(Post, {
text: data.post_text,
message_entities: data.message_entities,
timestamp: new Date(),
from_user: user,
});
await manager.save(Image, {
post: post,
file_id: data.file_id,
has_spoiler: data.has_spoiler,
message_id: data.message_id,
});
}
}); });
return { status: 'ok', created: created_new }; if (data.post_text) {
} catch (error) { post.text = data.post_text;
this.logger.debug(`[image.add] error: ${JSON.stringify(error)}`); post.message_entities = data.message_entities;
throw new HttpException('No posts', HttpStatus.BAD_REQUEST); post = await manager.save(Post, post);
}
} else {
const user = await manager.findOne(Admin, {
where: { user: { id: data.from_user_id } },
relations: { user: true },
});
post = await manager.save(Post, {
media_group_id: data.media_group_id,
text: data.post_text,
message_entities: data.message_entities,
timestamp: new Date(),
from_user: user,
});
created_new = true;
await manager.save(Image, {
post: post,
file_id: data.file_id,
has_spoiler: data.has_spoiler,
message_id: data.message_id,
});
}
} else {
const user = await manager.findOne(Admin, {
where: { user: { id: data.from_user_id } },
relations: { user: true },
});
const post = await manager.save(Post, {
text: data.post_text,
message_entities: data.message_entities,
timestamp: new Date(),
from_user: user,
});
await manager.save(Image, {
post: post,
file_id: data.file_id,
has_spoiler: data.has_spoiler,
message_id: data.message_id,
});
} }
});
return { status: "ok", created: created_new };
} catch (error) {
this.logger.debug(`[image.add] error: ${JSON.stringify(error)}`);
throw new HttpException("No posts", HttpStatus.BAD_REQUEST);
} }
}
} }

View File

@@ -1,21 +1,23 @@
import { Injectable, OnModuleInit } from '@nestjs/common'; import { Injectable, OnModuleInit } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Admin } from 'libs/database/admin.entity'; import { Admin } from "libs/database/admin.entity";
import { Image } from 'libs/database/image.entity'; import { Image } from "libs/database/image.entity";
import { Post } from 'libs/database/post.entity'; import { Post } from "libs/database/post.entity";
import { BotSettings } from 'libs/database/settings.entity'; import { BotSettings } from "libs/database/settings.entity";
import { User } from 'libs/database/user.entity'; import { User } from "libs/database/user.entity";
import { Repository } from 'typeorm'; import { WebUser } from "libs/database/web_user.entity";
import { Repository } from "typeorm";
@Injectable() @Injectable()
export class AppInitService implements OnModuleInit { export class AppInitService implements OnModuleInit {
constructor( constructor(
@InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(User) private userRepository: Repository<User>,
@InjectRepository(Admin) private adminRepository: Repository<Admin>, @InjectRepository(Admin) private adminRepository: Repository<Admin>,
@InjectRepository(Post) private postRepository: Repository<Post>, @InjectRepository(Post) private postRepository: Repository<Post>,
@InjectRepository(Image) private ImageRepository: Repository<Image>, @InjectRepository(Image) private ImageRepository: Repository<Image>,
@InjectRepository(BotSettings) private BotSettingsRepository: Repository<BotSettings>, @InjectRepository(BotSettings) private BotSettingsRepository: Repository<BotSettings>,
) {} @InjectRepository(WebUser) private WebUserRepository: Repository<WebUser>,
) {}
async onModuleInit() {} async onModuleInit() {}
} }

View File

@@ -1,78 +1,78 @@
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Post, Put } from "@nestjs/common";
import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiParam, ApiTags } from "@nestjs/swagger";
import { EGetAll } from 'libs/enums/getAll.enum'; import { EGetAll } from "libs/enums/getAll.enum";
import { ICreatePost, IEditPost } from './post.dto'; import { ICreatePost, IEditPost } from "./post.dto";
import { PostService } from './post.service'; import { PostService } from "./post.service";
@ApiTags('Post') @ApiTags("Post")
@Controller('post') @Controller("post")
export class PostController { export class PostController {
constructor(private postService: PostService) {} constructor(private postService: PostService) {}
@ApiOperation({ description: 'Creates a new post' }) @ApiOperation({ description: "Creates a new post" })
@Post('new') @Post("new")
async newPost(@Body() data: ICreatePost) { async newPost(@Body() data: ICreatePost) {
return await this.postService.newPost(data); return await this.postService.newPost(data);
} }
@ApiOperation({ description: 'Getting all posts. By default - all' }) @ApiOperation({ description: "Getting all posts. By default - all" })
@Get('get-all/:status') @Get("get-all/:status")
@ApiParam({ name: 'status', required: false, enum: EGetAll }) @ApiParam({ name: "status", required: false, enum: EGetAll })
async getAllPosts(@Param('status') status?: EGetAll) { async getAllPosts(@Param("status") status?: EGetAll) {
return await this.postService.getAllPosts(status || EGetAll.all); return await this.postService.getAllPosts(status || EGetAll.all);
} }
@ApiOperation({ description: 'Getting a post by uuid' }) @ApiOperation({ description: "Getting a post by uuid" })
@Get('get/:postId') @Get("get/:postId")
async getPost(@Param('postId') postId: string) { async getPost(@Param("postId") postId: string) {
return await this.postService.getPost(postId); return await this.postService.getPost(postId);
} }
@ApiOperation({ description: 'Getting a post by its media group id' }) @ApiOperation({ description: "Getting a post by its media group id" })
@Get('get-by-media-group-id/:mediaGroupId') @Get("get-by-media-group-id/:mediaGroupId")
async getByMediaGroup(@Param('mediaGroupId') mediaGroupId: string) { async getByMediaGroup(@Param("mediaGroupId") mediaGroupId: string) {
return await this.postService.getByMediaGroup(mediaGroupId); return await this.postService.getByMediaGroup(mediaGroupId);
} }
@ApiOperation({ description: 'Editing a post by its uuid' }) @ApiOperation({ description: "Editing a post by its uuid" })
@Post('edit/:postId') @Post("edit/:postId")
async editPost(@Param('postId') postId: string, @Body() data: IEditPost) { async editPost(@Param("postId") postId: string, @Body() data: IEditPost) {
return await this.postService.editPost(postId, data); return await this.postService.editPost(postId, data);
} }
@ApiOperation({ description: 'Editing post text by its order num' }) @ApiOperation({ description: "Editing post text by its order num" })
@Post('edit-post-by-order-num/:order') @Post("edit-post-by-order-num/:order")
async editPostByOrderNum(@Param('order') order: string, @Body() data: IEditPost) { async editPostByOrderNum(@Param("order") order: string, @Body() data: IEditPost) {
return await this.postService.editPostByOrderNum(order, data); return await this.postService.editPostByOrderNum(order, data);
} }
@ApiOperation({ description: 'Get post to post' }) @ApiOperation({ description: "Get post to post" })
@Get('post') @Get("post")
async post() { async post() {
return await this.postService.post(); return await this.postService.post();
} }
@ApiOperation({ description: 'Get post by order' }) @ApiOperation({ description: "Get post by order" })
@Get('get-post-by-order/:order') @Get("get-post-by-order/:order")
async getPostByOrder(@Param('order') order: number) { async getPostByOrder(@Param("order") order: number) {
return await this.postService.getPostByOrder(order); return await this.postService.getPostByOrder(order);
} }
@ApiOperation({ description: 'Delete post by order' }) @ApiOperation({ description: "Delete post by order" })
@Delete('delete-post-by-order/:order') @Delete("delete-post-by-order/:order")
async deletePostByOrder(@Param('order') order: number) { async deletePostByOrder(@Param("order") order: number) {
return await this.postService.deletePostByOrder(order); return await this.postService.deletePostByOrder(order);
} }
@ApiOperation({ description: 'Get deleted posts' }) @ApiOperation({ description: "Get deleted posts" })
@Get('get-deleted') @Get("get-deleted")
async getDeletedPosts() { async getDeletedPosts() {
return await this.postService.getDeletedPosts(); return await this.postService.getDeletedPosts();
} }
@ApiOperation({ description: 'Restore post by order' }) @ApiOperation({ description: "Restore post by order" })
@Put('restore-post-by-order/:order') @Put("restore-post-by-order/:order")
async restorePostByOrder(@Param('order') order: string) { async restorePostByOrder(@Param("order") order: string) {
return await this.postService.restorePostByOrder(order); return await this.postService.restorePostByOrder(order);
} }
} }

View File

@@ -1,17 +1,21 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from "@nestjs/swagger";
export class ICreatePost { export class ICreatePost {
@ApiProperty({ description: 'Post text', example: 'Post text' }) readonly text!: string; @ApiProperty({ description: "Post text", example: "Post text" }) readonly text!: string;
@ApiProperty({ description: 'The id of user that creating post', example: '1234' }) readonly from_user_id!: string; @ApiProperty({ description: "The id of user that creating post", example: "1234" })
readonly from_user_id!: string;
@ApiProperty({ description: 'Post media group id', example: '123' }) readonly media_group_id?: string; @ApiProperty({ description: "Post media group id", example: "123" })
readonly media_group_id?: string;
@ApiProperty({ description: 'Message entities of text', example: '[]' }) readonly message_entities?: string; @ApiProperty({ description: "Message entities of text", example: "[]" })
readonly message_entities?: string;
} }
export class IEditPost { export class IEditPost {
@ApiProperty({ description: 'Post text', example: 'Post text' }) readonly text!: string; @ApiProperty({ description: "Post text", example: "Post text" }) readonly text!: string;
@ApiProperty({ description: 'Message entities of text', example: '[]' }) readonly message_entities?: string; @ApiProperty({ description: "Message entities of text", example: "[]" })
readonly message_entities?: string;
} }

View File

@@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { PostController } from './post.controller'; import { PostController } from "./post.controller";
import { PostService } from './post.service'; import { PostService } from "./post.service";
@Module({ @Module({
imports: [LibsModule], imports: [LibsModule],
controllers: [PostController], controllers: [PostController],
providers: [PostService], providers: [PostService],
}) })
export class PostModule {} export class PostModule {}

View File

@@ -1,223 +1,255 @@
import { HttpException, HttpStatus, Inject, Injectable, Logger } from '@nestjs/common'; import { HttpException, HttpStatus, Inject, Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Admin } from 'libs/database/admin.entity'; import { Admin } from "libs/database/admin.entity";
import { Post } from 'libs/database/post.entity'; import { Post } from "libs/database/post.entity";
import { EGetAll } from 'libs/enums/getAll.enum'; import { EGetAll } from "libs/enums/getAll.enum";
import { DataSource, EntityManager, Repository } from 'typeorm'; import { DataSource, EntityManager, Repository } from "typeorm";
import { ICreatePost, IEditPost } from './post.dto'; import { ICreatePost, IEditPost } from "./post.dto";
@Injectable() @Injectable()
export class PostService { export class PostService {
private readonly logger: Logger = new Logger(PostService.name); private readonly logger: Logger = new Logger(PostService.name);
constructor( constructor(
@InjectRepository(Post) private postRepository: Repository<Post>, @InjectRepository(Post) private postRepository: Repository<Post>,
@InjectRepository(Admin) private adminRepository: Repository<Admin>, @InjectRepository(Admin) private adminRepository: Repository<Admin>,
@Inject(DataSource) private dataSource: DataSource, @Inject(DataSource) private dataSource: DataSource,
) {} ) {}
async newPost(data: ICreatePost) { async newPost(data: ICreatePost) {
try { try {
this.logger.log(`[post.newPost] data: ${JSON.stringify(data)}`); this.logger.log(`[post.newPost] data: ${JSON.stringify(data)}`);
let result: Post = null; let result: Post = null;
const user = await this.adminRepository.findOne({ where: { user: { id: data.from_user_id } }, relations: { user: true } }); const user = await this.adminRepository.findOne({
await this.dataSource.transaction(async (manager: EntityManager) => { where: { user: { id: data.from_user_id } },
result = await manager.save(Post, { relations: { user: true },
text: data.text, });
media_group_id: data.media_group_id, await this.dataSource.transaction(async (manager: EntityManager) => {
from_user: user, result = await manager.save(Post, {
timestamp: new Date(), text: data.text,
message_entities: data.message_entities, media_group_id: data.media_group_id,
}); from_user: user,
}); timestamp: new Date(),
this.logger.log(`Created new post: ${result.uuid}`); message_entities: data.message_entities,
return result; });
} catch (error) { });
this.logger.debug(`[post.newPost] error: ${error}`); this.logger.log(`Created new post: ${result.uuid}`);
throw new HttpException('No user with this id', HttpStatus.BAD_REQUEST); return result;
} } catch (error) {
this.logger.debug(`[post.newPost] error: ${error}`);
throw new HttpException("No user with this id", HttpStatus.BAD_REQUEST);
} }
}
async editPost(postId: string, data: IEditPost) { async editPost(postId: string, data: IEditPost) {
try { try {
this.logger.log(`[post.editPost] data: ${JSON.stringify(data)}`); this.logger.log(`[post.editPost] data: ${JSON.stringify(data)}`);
const post = await this.postRepository.findOne({ where: { uuid: postId } }); const post = await this.postRepository.findOne({ where: { uuid: postId } });
if (!post) { if (!post) {
throw new HttpException('Post not found', HttpStatus.NOT_FOUND); throw new HttpException("Post not found", HttpStatus.NOT_FOUND);
} }
if (post.text !== data.text) { if (post.text !== data.text) {
post.text = data.text; post.text = data.text;
post.edit_timestamp = new Date(); post.edit_timestamp = new Date();
await this.postRepository.save(post); await this.postRepository.save(post);
} }
return post; return post;
} catch (error) { } catch (error) {
this.logger.debug(`[post.editPost] error: ${JSON.stringify(error)}`); this.logger.debug(`[post.editPost] error: ${JSON.stringify(error)}`);
throw new HttpException('Post not found', HttpStatus.NOT_FOUND); throw new HttpException("Post not found", HttpStatus.NOT_FOUND);
}
} }
}
async editPostByOrderNum(order: string, data: IEditPost) { async editPostByOrderNum(order: string, data: IEditPost) {
try { try {
this.logger.log(`[post.editPostByOrderNum] data: ${JSON.stringify(data)}`); this.logger.log(`[post.editPostByOrderNum] data: ${JSON.stringify(data)}`);
const posts = await this.postRepository.find({ where: { posted: false, deleted: false }, order: { timestamp: 'ASC' } }); const posts = await this.postRepository.find({
if (Math.abs(+order) > posts.length) { where: { posted: false, deleted: false },
throw new HttpException('There are only ' + posts.length + ' unsent messages.', HttpStatus.BAD_REQUEST); order: { timestamp: "ASC" },
} });
const post = posts[Math.abs(+order) - 1]; if (Math.abs(+order) > posts.length) {
if (post.text !== data.text || post.message_entities !== data.message_entities) { throw new HttpException(
post.text = data.text; "There are only " + posts.length + " unsent messages.",
post.message_entities = data.message_entities; HttpStatus.BAD_REQUEST,
post.edit_timestamp = new Date(); );
await this.postRepository.save(post); }
} const post = posts[Math.abs(+order) - 1];
return post; if (post.text !== data.text || post.message_entities !== data.message_entities) {
} catch (error) { post.text = data.text;
if (error instanceof HttpException) { post.message_entities = data.message_entities;
this.logger.debug(`[post.editPostByOrderNum] Order: ${order} is bad`); post.edit_timestamp = new Date();
throw error; await this.postRepository.save(post);
} }
this.logger.debug(`[post.editPostByOrderNum] Bad data. Order: ${order}. Data: ${JSON.stringify(data)}`); return post;
throw new HttpException('Server error', HttpStatus.BAD_GATEWAY); } catch (error) {
} if (error instanceof HttpException) {
this.logger.debug(`[post.editPostByOrderNum] Order: ${order} is bad`);
throw error;
}
this.logger.debug(
`[post.editPostByOrderNum] Bad data. Order: ${order}. Data: ${JSON.stringify(data)}`,
);
throw new HttpException("Server error", HttpStatus.BAD_GATEWAY);
} }
}
async getAllPosts(status: EGetAll) { async getAllPosts(status: EGetAll) {
try { try {
let obj: object; let obj: object;
switch (status) { switch (status) {
case EGetAll.will_post: case EGetAll.will_post:
obj = { where: { posted: false, deleted: false }, order: { timestamp: 'ASC' } }; obj = { where: { posted: false, deleted: false }, order: { timestamp: "ASC" } };
break; break;
case EGetAll.all: case EGetAll.all:
obj = { order: { timestamp: 'ASC' }, where: { deleted: false } }; obj = { order: { timestamp: "ASC" }, where: { deleted: false } };
break; break;
case EGetAll.posted: case EGetAll.posted:
obj = { where: { posted: true, deleted: false }, order: { timestamp: 'ASC' } }; obj = { where: { posted: true, deleted: false }, order: { timestamp: "ASC" } };
break; break;
} }
return await this.postRepository.find(obj); return await this.postRepository.find(obj);
} catch (error) { } catch (error) {
this.logger.log(`[post.getAllPosts] error: ${JSON.stringify(error)}`); this.logger.log(`[post.getAllPosts] error: ${JSON.stringify(error)}`);
return []; return [];
}
} }
}
async getPost(postId: string) { async getPost(postId: string) {
try { try {
this.logger.log(`[post.getPost] data: ${postId}`); this.logger.log(`[post.getPost] data: ${postId}`);
const post = await this.postRepository.findOne({ where: { uuid: postId }, relations: { images: true } }); const post = await this.postRepository.findOne({
if (!post) throw new Error("Can't find post"); where: { uuid: postId },
return post; relations: { images: true },
} catch (error) { });
this.logger.log(`[post.getPost] error: ${JSON.stringify(error)}`); if (!post) throw new Error("Can't find post");
throw new HttpException('No post with this id', HttpStatus.NOT_FOUND); return post;
} } catch (error) {
this.logger.log(`[post.getPost] error: ${JSON.stringify(error)}`);
throw new HttpException("No post with this id", HttpStatus.NOT_FOUND);
} }
}
async getPostByOrder(order: number) { async getPostByOrder(order: number) {
try { try {
this.logger.log(`[post.getPostByOrder] data: ${order}`); this.logger.log(`[post.getPostByOrder] data: ${order}`);
const posts = await this.postRepository.find({ const posts = await this.postRepository.find({
relations: { images: true }, relations: { images: true },
order: { timestamp: 'ASC' }, order: { timestamp: "ASC" },
where: { posted: false, deleted: false }, where: { posted: false, deleted: false },
}); });
if (Math.abs(+order) > posts.length) { if (Math.abs(+order) > posts.length) {
throw new HttpException('There are only ' + posts.length + ' posts.', HttpStatus.BAD_REQUEST); throw new HttpException(
} "There are only " + posts.length + " posts.",
return posts[Math.abs(+order) - 1]; HttpStatus.BAD_REQUEST,
} catch (error) { );
this.logger.log(`[post.getPostByOrder] error: ${JSON.stringify(error)}`); }
throw new HttpException('No post with this id', HttpStatus.NOT_FOUND); return posts[Math.abs(+order) - 1];
} } catch (error) {
this.logger.log(`[post.getPostByOrder] error: ${JSON.stringify(error)}`);
throw new HttpException("No post with this id", HttpStatus.NOT_FOUND);
} }
}
async getByMediaGroup(mediaGroupId: string) { async getByMediaGroup(mediaGroupId: string) {
try { try {
this.logger.log(`[post.getByMediaGroup] data: ${mediaGroupId}`); this.logger.log(`[post.getByMediaGroup] data: ${mediaGroupId}`);
let post: Post = null; let post: Post = null;
await this.dataSource.transaction(async (manager: EntityManager) => { await this.dataSource.transaction(async (manager: EntityManager) => {
post = await manager.findOne(Post, { where: { media_group_id: mediaGroupId } }); post = await manager.findOne(Post, { where: { media_group_id: mediaGroupId } });
}); });
if (!post) throw new Error("Can't find post"); if (!post) throw new Error("Can't find post");
return post; return post;
} catch (error) { } catch (error) {
this.logger.debug(`[post.getByMediaGroup] error: ${error}`); this.logger.debug(`[post.getByMediaGroup] error: ${error}`);
throw new HttpException("Can't find post with this media group id", HttpStatus.BAD_REQUEST); throw new HttpException("Can't find post with this media group id", HttpStatus.BAD_REQUEST);
}
} }
}
async post() { async post() {
try { try {
const posts = await this.postRepository.find({ const posts = await this.postRepository.find({
order: { timestamp: 'ASC' }, order: { timestamp: "ASC" },
where: { posted: false, deleted: false }, where: { posted: false, deleted: false },
relations: { images: true }, relations: { images: true },
}); });
if (!posts.length) throw new HttpException('Nothing to post', HttpStatus.NOT_FOUND); if (!posts.length) throw new HttpException("Nothing to post", HttpStatus.NOT_FOUND);
const post = posts[0]; const post = posts[0];
post.posted = true; post.posted = true;
this.logger.log(`[post.post] Post ${post.uuid} is posted`); this.logger.log(`[post.post] Post ${post.uuid} is posted`);
await this.postRepository.save(post); await this.postRepository.save(post);
return post; return post;
} catch (error) { } catch (error) {
if (error instanceof HttpException) { if (error instanceof HttpException) {
this.logger.debug('[post.post] Not found'); this.logger.debug("[post.post] Not found");
throw error; throw error;
} }
this.logger.debug(`[post.post] error: ${JSON.stringify(error)}`); this.logger.debug(`[post.post] error: ${JSON.stringify(error)}`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
}
} }
}
async deletePostByOrder(order: number) { async deletePostByOrder(order: number) {
try { try {
const posts = await this.postRepository.find({ order: { timestamp: 'ASC' }, where: { posted: false, deleted: false } }); const posts = await this.postRepository.find({
if (Math.abs(+order) > posts.length) { order: { timestamp: "ASC" },
throw new HttpException('There are only ' + posts.length + ' posts.', HttpStatus.BAD_REQUEST); where: { posted: false, deleted: false },
} });
const post = posts[Math.abs(+order) - 1]; if (Math.abs(+order) > posts.length) {
post.deleted = true; throw new HttpException(
this.logger.log(`[post.deletePostByOrder] Post ${post.uuid} is deleted`); "There are only " + posts.length + " posts.",
await this.postRepository.save(post); HttpStatus.BAD_REQUEST,
return post; );
} catch (error) { }
if (error instanceof HttpException) { const post = posts[Math.abs(+order) - 1];
this.logger.debug('[post.deletePostByOrder] Not found'); post.deleted = true;
throw error; this.logger.log(`[post.deletePostByOrder] Post ${post.uuid} is deleted`);
} await this.postRepository.save(post);
this.logger.debug(`[post.deletePostByOrder] error: ${JSON.stringify(error)}`); return post;
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); } catch (error) {
} if (error instanceof HttpException) {
this.logger.debug("[post.deletePostByOrder] Not found");
throw error;
}
this.logger.debug(`[post.deletePostByOrder] error: ${JSON.stringify(error)}`);
throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
} }
}
async getDeletedPosts() { async getDeletedPosts() {
try { try {
return await this.postRepository.find({ where: { deleted: true, posted: false }, order: { timestamp: 'ASC' } }); return await this.postRepository.find({
} catch (error) { where: { deleted: true, posted: false },
this.logger.debug(`[post.getDeleted] error: ${JSON.stringify(error)}`); order: { timestamp: "ASC" },
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); });
} } catch (error) {
this.logger.debug(`[post.getDeleted] error: ${JSON.stringify(error)}`);
throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
} }
}
async restorePostByOrder(order: string) { async restorePostByOrder(order: string) {
try { try {
const posts = await this.postRepository.find({ order: { timestamp: 'ASC' }, where: { deleted: true, posted: false } }); const posts = await this.postRepository.find({
if (Math.abs(+order) > posts.length) { order: { timestamp: "ASC" },
throw new HttpException('There are only ' + posts.length + ' posts.', HttpStatus.BAD_REQUEST); where: { deleted: true, posted: false },
} });
const post = posts[Math.abs(+order) - 1]; if (Math.abs(+order) > posts.length) {
post.deleted = false; throw new HttpException(
this.logger.log(`[post.restorePost] Post ${post.uuid} is restored`); "There are only " + posts.length + " posts.",
await this.postRepository.save(post); HttpStatus.BAD_REQUEST,
return post; );
} catch (error) { }
if (error instanceof HttpException) { const post = posts[Math.abs(+order) - 1];
this.logger.debug('[post.restorePost] Not found'); post.deleted = false;
throw error; this.logger.log(`[post.restorePost] Post ${post.uuid} is restored`);
} await this.postRepository.save(post);
this.logger.debug(`[post.restorePost] error: ${JSON.stringify(error)}`); return post;
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); } catch (error) {
} if (error instanceof HttpException) {
this.logger.debug("[post.restorePost] Not found");
throw error;
}
this.logger.debug(`[post.restorePost] error: ${JSON.stringify(error)}`);
throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
} }
}
} }

View File

@@ -1,46 +1,46 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common'; import { Body, Controller, Get, Param, Post } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { IOperation, IProxyUser } from './proxy.dto'; import { IOperation, IProxyUser } from "./proxy.dto";
import { ProxyService } from './proxy.service'; import { ProxyService } from "./proxy.service";
@ApiTags('Proxy') @ApiTags("Proxy")
@Controller('proxy') @Controller("proxy")
export class ProxyController { export class ProxyController {
constructor(private proxyService: ProxyService) {} constructor(private proxyService: ProxyService) {}
@ApiOperation({ description: 'Method to create a new proxy user' }) @ApiOperation({ description: "Method to create a new proxy user" })
@Post('new-user') @Post("new-user")
async newUser(@Body() data: IProxyUser) { async newUser(@Body() data: IProxyUser) {
return await this.proxyService.newUser(data); return await this.proxyService.newUser(data);
} }
@ApiOperation({ description: 'get user by its username' }) @ApiOperation({ description: "get user by its username" })
@Get('get-user/:userName') @Get("get-user/:userName")
async getUser(@Param('userName') userName: string) { async getUser(@Param("userName") userName: string) {
return await this.proxyService.getUser(userName); return await this.proxyService.getUser(userName);
} }
@ApiOperation({ description: 'get all users of proxy' }) @ApiOperation({ description: "get all users of proxy" })
@Get('get-all-users') @Get("get-all-users")
async getAllUsers() { async getAllUsers() {
return await this.proxyService.getAllUsers(); return await this.proxyService.getAllUsers();
} }
@ApiOperation({ description: 'adding an operation to user' }) @ApiOperation({ description: "adding an operation to user" })
@Post('operation/add') @Post("operation/add")
async addOperation(@Body() data: IOperation) { async addOperation(@Body() data: IOperation) {
return await this.proxyService.addOperation(data); return await this.proxyService.addOperation(data);
} }
@ApiOperation({ description: 'get user payments' }) @ApiOperation({ description: "get user payments" })
@Get('operation/get/:userName') @Get("operation/get/:userName")
async getOperations(@Param('userName') userName: string) { async getOperations(@Param("userName") userName: string) {
return this.proxyService.getOperations(userName); return this.proxyService.getOperations(userName);
} }
@ApiOperation({ description: 'get all payments' }) @ApiOperation({ description: "get all payments" })
@Get('operation/get-all') @Get("operation/get-all")
async getAllOperations() { async getAllOperations() {
return this.proxyService.getAllOperations(); return this.proxyService.getAllOperations();
} }
} }

View File

@@ -1,12 +1,17 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from "@nestjs/swagger";
export class IProxyUser { export class IProxyUser {
@ApiProperty({ description: 'user name of user to identify them', example: 'username' }) readonly userName!: string; @ApiProperty({ description: "user name of user to identify them", example: "username" })
@ApiProperty({ description: 'some user description if you want', example: 'Description of user' }) readonly description?: string; readonly userName!: string;
@ApiProperty({ description: 'user link to connect to the proxy', example: 'vless://....' }) readonly link!: string; @ApiProperty({ description: "some user description if you want", example: "Description of user" })
@ApiProperty({ description: 'telegram user id to connect to user entity', example: '187564' }) readonly user_id?: string; readonly description?: string;
@ApiProperty({ description: "user link to connect to the proxy", example: "vless://...." })
readonly link!: string;
@ApiProperty({ description: "telegram user id to connect to user entity", example: "187564" })
readonly user_id?: string;
} }
export class IOperation { export class IOperation {
@ApiProperty({ description: 'user name of user, that made new operation', example: 'username' }) readonly userName!: string; @ApiProperty({ description: "user name of user, that made new operation", example: "username" })
readonly userName!: string;
} }

View File

@@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { ProxyController } from './proxy.controller'; import { ProxyController } from "./proxy.controller";
import { ProxyService } from './proxy.service'; import { ProxyService } from "./proxy.service";
@Module({ @Module({
imports: [LibsModule], imports: [LibsModule],
controllers: [ProxyController], controllers: [ProxyController],
providers: [ProxyService], providers: [ProxyService],
}) })
export class ProxyModule {} export class ProxyModule {}

View File

@@ -1,106 +1,112 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'; import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Payment } from 'libs/database/payment.entity'; import { Payment } from "libs/database/payment.entity";
import { ProxyUser } from 'libs/database/proxy_user.entity'; import { ProxyUser } from "libs/database/proxy_user.entity";
import { User } from 'libs/database/user.entity'; import { User } from "libs/database/user.entity";
import { Repository } from 'typeorm'; import { Repository } from "typeorm";
import { IOperation, IProxyUser } from './proxy.dto'; import { IOperation, IProxyUser } from "./proxy.dto";
@Injectable() @Injectable()
export class ProxyService { export class ProxyService {
private readonly logger: Logger = new Logger(ProxyService.name); private readonly logger: Logger = new Logger(ProxyService.name);
constructor( constructor(
@InjectRepository(ProxyUser) private proxyUserRepository: Repository<ProxyUser>, @InjectRepository(ProxyUser) private proxyUserRepository: Repository<ProxyUser>,
@InjectRepository(Payment) private paymentRepository: Repository<Payment>, @InjectRepository(Payment) private paymentRepository: Repository<Payment>,
@InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(User) private userRepository: Repository<User>,
) {} ) {}
async newUser(data: IProxyUser) { async newUser(data: IProxyUser) {
try { try {
if ( if (
(await this.proxyUserRepository.findOne({ where: { userName: data.userName } })) || data.user_id (await this.proxyUserRepository.findOne({ where: { userName: data.userName } })) ||
? await this.proxyUserRepository.findOne({ where: { user_id: data.user_id } }) data.user_id
: false ? await this.proxyUserRepository.findOne({ where: { user_id: data.user_id } })
) : false
throw new HttpException('User already exists', HttpStatus.FOUND); )
const proxyUser = new ProxyUser(); throw new HttpException("User already exists", HttpStatus.FOUND);
const user = data.user_id ? await this.userRepository.findOne({ where: { id: data.user_id } }) : null; const proxyUser = new ProxyUser();
if (user) proxyUser.user = user; const user = data.user_id
proxyUser.description = data.description; ? await this.userRepository.findOne({ where: { id: data.user_id } })
proxyUser.connectDate = new Date(); : null;
proxyUser.userName = data.userName; if (user) proxyUser.user = user;
proxyUser.link = data.link; proxyUser.description = data.description;
return await this.proxyUserRepository.save(proxyUser); proxyUser.connectDate = new Date();
} catch (error) { proxyUser.userName = data.userName;
if (error instanceof HttpException) { proxyUser.link = data.link;
this.logger.debug(`[proxy.newUser] error: user already created`); return await this.proxyUserRepository.save(proxyUser);
throw error; } catch (error) {
} if (error instanceof HttpException) {
this.logger.debug(`[proxy.newUser] error: ${JSON.stringify(error)}`); this.logger.debug(`[proxy.newUser] error: user already created`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw error;
} }
this.logger.debug(`[proxy.newUser] error: ${JSON.stringify(error)}`);
throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
} }
}
async getUser(userName: string) { async getUser(userName: string) {
try { try {
const user = await this.proxyUserRepository.findOne({ where: { userName: userName } }); const user = await this.proxyUserRepository.findOne({ where: { userName: userName } });
if (!user) throw new HttpException('Not found', HttpStatus.NOT_FOUND); if (!user) throw new HttpException("Not found", HttpStatus.NOT_FOUND);
return user; return user;
} catch (error) { } catch (error) {
if (error instanceof HttpException) { if (error instanceof HttpException) {
this.logger.debug(`[proxy.getUser] error: not found`); this.logger.debug(`[proxy.getUser] error: not found`);
throw error; throw error;
} }
this.logger.debug(`[proxy.getUser] error: ${JSON.stringify(error)}`); this.logger.debug(`[proxy.getUser] error: ${JSON.stringify(error)}`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
}
} }
}
async getAllUsers() { async getAllUsers() {
try { try {
return await this.proxyUserRepository.find(); return await this.proxyUserRepository.find();
} catch (error) { } catch (error) {
this.logger.debug(`[proxy.getAllUsers] error: ${JSON.stringify(error)}`); this.logger.debug(`[proxy.getAllUsers] error: ${JSON.stringify(error)}`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
}
} }
}
async addOperation(data: IOperation) { async addOperation(data: IOperation) {
try { try {
const user = await this.proxyUserRepository.findOne({ where: { userName: data.userName } }); const user = await this.proxyUserRepository.findOne({ where: { userName: data.userName } });
if (!user) throw new HttpException('Not found', HttpStatus.NOT_FOUND); if (!user) throw new HttpException("Not found", HttpStatus.NOT_FOUND);
return await this.paymentRepository.save({ payTime: new Date(), user: user }); return await this.paymentRepository.save({ payTime: new Date(), user: user });
} catch (error) { } catch (error) {
if (error instanceof HttpException) { if (error instanceof HttpException) {
this.logger.debug(`[proxy.addOperation] error: not found`); this.logger.debug(`[proxy.addOperation] error: not found`);
throw error; throw error;
} }
this.logger.debug(`[proxy.addOperation] error: ${JSON.stringify(error)}`); this.logger.debug(`[proxy.addOperation] error: ${JSON.stringify(error)}`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
}
} }
}
async getOperations(userName: string) { async getOperations(userName: string) {
try { try {
const user = await this.proxyUserRepository.findOne({ where: { userName: userName }, relations: { payments: true } }); const user = await this.proxyUserRepository.findOne({
if (!user) throw new HttpException('Not found', HttpStatus.NOT_FOUND); where: { userName: userName },
return user.payments; relations: { payments: true },
} catch (error) { });
if (error instanceof HttpException) { if (!user) throw new HttpException("Not found", HttpStatus.NOT_FOUND);
this.logger.debug(`[proxy.addOperation] error: not found`); return user.payments;
throw error; } catch (error) {
} if (error instanceof HttpException) {
this.logger.debug(`[proxy.addOperation] error: ${error}`); this.logger.debug(`[proxy.addOperation] error: not found`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw error;
} }
this.logger.debug(`[proxy.addOperation] error: ${error}`);
throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
} }
}
async getAllOperations() { async getAllOperations() {
try { try {
return await this.paymentRepository.find(); return await this.paymentRepository.find();
} catch (error) { } catch (error) {
this.logger.debug(`[proxy.addOperation] error: ${error}`); this.logger.debug(`[proxy.addOperation] error: ${error}`);
throw new HttpException('Bad data', HttpStatus.BAD_REQUEST); throw new HttpException("Bad data", HttpStatus.BAD_REQUEST);
}
} }
}
} }

View File

@@ -1,52 +1,52 @@
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager'; import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager";
import { Body, Controller, Delete, Get, Param, Post, UseInterceptors } from '@nestjs/common'; import { Body, Controller, Delete, Get, Param, Post, UseInterceptors } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { ICreateBotSettingsProfile, IEditBotSettingsProfile } from './settings.dto'; import { ICreateBotSettingsProfile, IEditBotSettingsProfile } from "./settings.dto";
import { SettingsService } from './settings.service'; import { SettingsService } from "./settings.service";
// Если нужна будет авторизация, для выключения авторизации на конкретном // Если нужна будет авторизация, для выключения авторизации на конкретном
// const AllowUnathorizedRequest = () => SetMetadata('allowUnathorizedRequest', true); // const AllowUnathorizedRequest = () => SetMetadata('allowUnathorizedRequest', true);
@ApiTags('Settings') @ApiTags("Settings")
@Controller('settings') @Controller("settings")
export class SettingsController { export class SettingsController {
constructor(private settingsService: SettingsService) {} constructor(private settingsService: SettingsService) {}
@ApiOperation({ description: 'Get settings for bot' }) @ApiOperation({ description: "Get settings for bot" })
@Get() @Get()
@CacheKey('settings') @CacheKey("settings")
@CacheTTL({ ttl: 600 } as any) @CacheTTL({ ttl: 600 } as any)
@UseInterceptors(CacheInterceptor) @UseInterceptors(CacheInterceptor)
async getSettings() { async getSettings() {
return await this.settingsService.getSettings(); return await this.settingsService.getSettings();
} }
@ApiOperation({ description: 'Get active settings' }) @ApiOperation({ description: "Get active settings" })
@Get('active') @Get("active")
async getActiveSettings() { async getActiveSettings() {
return await this.settingsService.getActiveSettings(); return await this.settingsService.getActiveSettings();
} }
@ApiOperation({ description: 'Get all bot settings profiles' }) @ApiOperation({ description: "Get all bot settings profiles" })
@Get('profile') @Get("profile")
async getProfiles() { async getProfiles() {
return await this.settingsService.getProfiles(); return await this.settingsService.getProfiles();
} }
@ApiOperation({ description: 'Create new settings profile' }) @ApiOperation({ description: "Create new settings profile" })
@Post('profile/new') @Post("profile/new")
async newProfile(@Body() data: ICreateBotSettingsProfile) { async newProfile(@Body() data: ICreateBotSettingsProfile) {
return await this.settingsService.newProfile(data); return await this.settingsService.newProfile(data);
} }
@ApiOperation({ description: 'Edit settings profile' }) @ApiOperation({ description: "Edit settings profile" })
@Post('profile/edit') @Post("profile/edit")
async editProfile(@Body() data: IEditBotSettingsProfile) { async editProfile(@Body() data: IEditBotSettingsProfile) {
return await this.settingsService.editProfile(data); return await this.settingsService.editProfile(data);
} }
@ApiOperation({ description: 'Delete settings profile' }) @ApiOperation({ description: "Delete settings profile" })
@Delete('profile/delete/:uuid') @Delete("profile/delete/:uuid")
async deleteProfile(@Param('uuid') uuid: string) { async deleteProfile(@Param("uuid") uuid: string) {
return await this.settingsService.deleteProfile(uuid); return await this.settingsService.deleteProfile(uuid);
} }
} }

View File

@@ -1,13 +1,21 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from "@nestjs/swagger";
export class ICreateBotSettingsProfile { export class ICreateBotSettingsProfile {
@ApiProperty({ description: 'Channel', example: '@neurowoman_test' }) readonly channel: string; @ApiProperty({ description: "Channel", example: "@neurowoman_test" }) readonly channel: string;
@ApiProperty({ description: 'Post times', example: ['12:00', '14:00'] }) readonly postTimes: string[]; @ApiProperty({ description: "Post times", example: ["12:00", "14:00"] })
readonly postTimes: string[];
} }
export class IEditBotSettingsProfile { export class IEditBotSettingsProfile {
@ApiProperty({ description: 'Channel', example: '@neurowoman_test' }) readonly channel: string | undefined; @ApiProperty({ description: "Channel", example: "@neurowoman_test" }) readonly channel:
@ApiProperty({ description: 'Profile uuid', example: '96e7d1b3-20ca-46e8-ac68-e406f79b7eb9' }) readonly uuid: string; | string
@ApiProperty({ description: 'Post times', example: ['12:00', '14:00'] }) readonly postTimes: string[] | undefined; | undefined;
@ApiProperty({ description: 'Is active?', example: false }) readonly isActive: boolean | undefined; @ApiProperty({ description: "Profile uuid", example: "96e7d1b3-20ca-46e8-ac68-e406f79b7eb9" })
readonly uuid: string;
@ApiProperty({ description: "Post times", example: ["12:00", "14:00"] }) readonly postTimes:
| string[]
| undefined;
@ApiProperty({ description: "Is active?", example: false }) readonly isActive:
| boolean
| undefined;
} }

View File

@@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from "@nestjs/common";
import { LibsModule } from 'libs/libs.module'; import { LibsModule } from "libs/libs.module";
import { SettingsController } from './settings.controller'; import { SettingsController } from "./settings.controller";
import { SettingsService } from './settings.service'; import { SettingsService } from "./settings.service";
@Module({ @Module({
imports: [LibsModule], imports: [LibsModule],
controllers: [SettingsController], controllers: [SettingsController],
providers: [SettingsService], providers: [SettingsService],
}) })
export class SettingsModule {} export class SettingsModule {}

View File

@@ -1,82 +1,85 @@
import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { HttpException, Inject, Injectable, Logger } from '@nestjs/common'; import { HttpException, Inject, Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Cache } from 'cache-manager'; import { Cache } from "cache-manager";
import { BotSettings } from 'libs/database/settings.entity'; import { BotSettings } from "libs/database/settings.entity";
import { Repository } from 'typeorm'; import { Repository } from "typeorm";
import { ICreateBotSettingsProfile, IEditBotSettingsProfile } from './settings.dto'; import { ICreateBotSettingsProfile, IEditBotSettingsProfile } from "./settings.dto";
@Injectable() @Injectable()
export class SettingsService { export class SettingsService {
constructor( constructor(
@InjectRepository(BotSettings) private botSettingsRepository: Repository<BotSettings>, @InjectRepository(BotSettings) private botSettingsRepository: Repository<BotSettings>,
@Inject(CACHE_MANAGER) private cacheManager: Cache, @Inject(CACHE_MANAGER) private cacheManager: Cache,
) {} ) {}
private readonly logger: Logger = new Logger(SettingsService.name); private readonly logger: Logger = new Logger(SettingsService.name);
async getSettings() { async getSettings() {
this.logger.debug('[settings.getSettings]'); this.logger.debug("[settings.getSettings]");
const settings = await this.botSettingsRepository.findOneBy({ isActive: true }); const settings = await this.botSettingsRepository.findOneBy({ isActive: true });
if (settings) return settings; if (settings) return settings;
this.logger.debug(`[settings.getSettings] No active settings found`); this.logger.debug(`[settings.getSettings] No active settings found`);
throw new HttpException('No settings found', 404); throw new HttpException("No settings found", 404);
}
async getActiveSettings() {
this.logger.debug("[settings.getActiveSettings]");
const settings = await this.botSettingsRepository.findOneBy({ isActive: true });
await this.cacheManager.set("settings", settings, { ttl: 600 } as any);
if (settings) return settings;
this.logger.debug(`[settings.getActiveSettings] No active settings found`);
throw new HttpException("No settings found", 404);
}
async newProfile(data: ICreateBotSettingsProfile) {
this.logger.log(`[settings.newProfile] data: ${JSON.stringify(data)}`);
await this.cacheManager.del("settings");
return await this.botSettingsRepository.save({
channel: data.channel,
messageTimes: data.postTimes,
});
}
async getProfiles() {
this.logger.log(`[settings.getProfiles]`);
return await this.botSettingsRepository.find();
}
async editProfile(data: IEditBotSettingsProfile) {
this.logger.log(`[settings.editProfile] data: ${JSON.stringify(data)}`);
await this.cacheManager.del("settings");
const editProfile = await this.botSettingsRepository.findOneBy({ uuid: data.uuid });
if (!editProfile) {
this.logger.debug(`[settings.editProfile] No profile found`);
throw new HttpException("No profile found", 404);
} }
data.channel ? (editProfile.channel = data.channel) : "";
async getActiveSettings() { data.postTimes ? (editProfile.messageTimes = data.postTimes) : "";
this.logger.debug('[settings.getActiveSettings]'); if (data.isActive !== undefined) {
const settings = await this.botSettingsRepository.findOneBy({ isActive: true }); editProfile.isActive = data.isActive;
await this.cacheManager.set('settings', settings, { ttl: 600 } as any); if (data.isActive) {
if (settings) return settings; const nowActive = await this.botSettingsRepository.findOneBy({ isActive: true });
this.logger.debug(`[settings.getActiveSettings] No active settings found`); if (nowActive) {
throw new HttpException('No settings found', 404); nowActive.isActive = false;
} await this.botSettingsRepository.save(nowActive);
async newProfile(data: ICreateBotSettingsProfile) {
this.logger.log(`[settings.newProfile] data: ${JSON.stringify(data)}`);
await this.cacheManager.del('settings');
return await this.botSettingsRepository.save({ channel: data.channel, messageTimes: data.postTimes });
}
async getProfiles() {
this.logger.log(`[settings.getProfiles]`);
return await this.botSettingsRepository.find();
}
async editProfile(data: IEditBotSettingsProfile) {
this.logger.log(`[settings.editProfile] data: ${JSON.stringify(data)}`);
await this.cacheManager.del('settings');
const editProfile = await this.botSettingsRepository.findOneBy({ uuid: data.uuid });
if (!editProfile) {
this.logger.debug(`[settings.editProfile] No profile found`);
throw new HttpException('No profile found', 404);
} }
data.channel ? (editProfile.channel = data.channel) : ''; }
data.postTimes ? (editProfile.messageTimes = data.postTimes) : '';
if (data.isActive !== undefined) {
editProfile.isActive = data.isActive;
if (data.isActive) {
const nowActive = await this.botSettingsRepository.findOneBy({ isActive: true });
if (nowActive) {
nowActive.isActive = false;
await this.botSettingsRepository.save(nowActive);
}
}
}
return await this.botSettingsRepository.save(editProfile);
} }
return await this.botSettingsRepository.save(editProfile);
}
async deleteProfile(profile_uuid: string) { async deleteProfile(profile_uuid: string) {
this.logger.log(`[settings.deleteProfile] uuid: ${profile_uuid}`); this.logger.log(`[settings.deleteProfile] uuid: ${profile_uuid}`);
await this.cacheManager.del('settings'); await this.cacheManager.del("settings");
const deleteProfile = await this.botSettingsRepository.findOneBy({ uuid: profile_uuid }); const deleteProfile = await this.botSettingsRepository.findOneBy({ uuid: profile_uuid });
if (!deleteProfile) { if (!deleteProfile) {
this.logger.debug(`[settings.deleteProfile] No profile found`); this.logger.debug(`[settings.deleteProfile] No profile found`);
throw new HttpException('No profile found', 404); throw new HttpException("No profile found", 404);
}
if (deleteProfile.isActive) {
this.logger.debug(`[settings.deleteProfile] Can't delete active profile`);
throw new HttpException("Can't delete active profile", 400);
}
return await this.botSettingsRepository.delete(deleteProfile.uuid);
} }
if (deleteProfile.isActive) {
this.logger.debug(`[settings.deleteProfile] Can't delete active profile`);
throw new HttpException("Can't delete active profile", 400);
}
return await this.botSettingsRepository.delete(deleteProfile.uuid);
}
} }

View File

@@ -1,42 +1,42 @@
import { Body, Controller, Get, Param, Post, Put } from '@nestjs/common'; import { Body, Controller, Get, Param, Post, Put } from "@nestjs/common";
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { IGetUser } from './user.dto'; import { IGetUser } from "./user.dto";
import { UserService } from './user.service'; import { UserService } from "./user.service";
@ApiTags('User') @ApiTags("User")
@Controller('user') @Controller("user")
export class UserController { export class UserController {
constructor(private userService: UserService) {} constructor(private userService: UserService) {}
@ApiOperation({ @ApiOperation({
description: 'Create or get user from db', description: "Create or get user from db",
}) })
@Post('get') @Post("get")
async getUser(@Body() data: IGetUser) { async getUser(@Body() data: IGetUser) {
return await this.userService.getUser(data); return await this.userService.getUser(data);
} }
@ApiOperation({ @ApiOperation({
description: 'Ban user by its telegram id', description: "Ban user by its telegram id",
}) })
@Put('ban/:id') @Put("ban/:id")
async banUser(@Param('id') id: string) { async banUser(@Param("id") id: string) {
return await this.userService.banUser(id); return await this.userService.banUser(id);
} }
@ApiOperation({ @ApiOperation({
description: 'Unban user by its telegram id', description: "Unban user by its telegram id",
}) })
@Put('unBan/:id') @Put("unBan/:id")
async unBanUser(@Param('id') id: string) { async unBanUser(@Param("id") id: string) {
return await this.userService.unBanUser(id); return await this.userService.unBanUser(id);
} }
@ApiOperation({ @ApiOperation({
description: 'Get all banned users', description: "Get all banned users",
}) })
@Get('banned') @Get("banned")
async getBannedUsers() { async getBannedUsers() {
return await this.userService.getBannedUsers(); return await this.userService.getBannedUsers();
} }
} }

View File

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

View File

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

View File

@@ -1,87 +1,90 @@
import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { HttpException, HttpStatus, Inject, Injectable, Logger } from '@nestjs/common'; import { HttpException, HttpStatus, Inject, Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from "@nestjs/typeorm";
import { Cache } from 'cache-manager'; import { Cache } from "cache-manager";
import { User } from 'libs/database/user.entity'; import { User } from "libs/database/user.entity";
import { Repository } from 'typeorm'; import { Repository } from "typeorm";
import { IGetUser } from './user.dto'; import { IGetUser } from "./user.dto";
@Injectable() @Injectable()
export class UserService { export class UserService {
private readonly logger: Logger = new Logger(UserService.name); private readonly logger: Logger = new Logger(UserService.name);
constructor( constructor(
@InjectRepository(User) private userRepository: Repository<User>, @InjectRepository(User) private userRepository: Repository<User>,
@Inject(CACHE_MANAGER) private cacheManager: Cache, @Inject(CACHE_MANAGER) private cacheManager: Cache,
) {} ) {}
async getUser(data: IGetUser) { async getUser(data: IGetUser) {
try { try {
this.logger.debug(`[user.getUser] data: ${JSON.stringify(data)}`); this.logger.debug(`[user.getUser] data: ${JSON.stringify(data)}`);
let user = await this.cacheManager.get(`user_${data.id}`); let user = await this.cacheManager.get(`user_${data.id}`);
if (user) return user; if (user) return user;
user = await this.userRepository.findOne({ user = await this.userRepository.findOne({
where: { id: data.id }, where: { id: data.id },
}); });
if (!user) { if (!user) {
user = await this.userRepository.save({ id: data.id, user_name: data.username }); user = await this.userRepository.save({ id: data.id, user_name: data.username });
this.logger.log(`User ${data.id} created`); this.logger.log(`User ${data.id} created`);
} }
await this.cacheManager.set(`user_${data.id}`, user, { ttl: 600 } as any); await this.cacheManager.set(`user_${data.id}`, user, { ttl: 600 } as any);
return user; return user;
} catch (error) { } catch (error) {
this.logger.debug(`[user.getUser] ${JSON.stringify({ error })}`); this.logger.debug(`[user.getUser] ${JSON.stringify({ error })}`);
throw new HttpException('Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR); throw new HttpException("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR);
}
} }
}
async banUser(id: string) { async banUser(id: string) {
try { try {
this.logger.debug(`[user.banUser] id: ${JSON.stringify(id)}`); this.logger.debug(`[user.banUser] id: ${JSON.stringify(id)}`);
let user = await this.userRepository.findOne({ let user = await this.userRepository.findOne({
where: { id: id }, where: { id: id },
}); });
if (user) { if (user) {
user.banned = true; user.banned = true;
await this.userRepository.save(user); await this.userRepository.save(user);
return user; return user;
} }
user = await this.userRepository.save({ id: id, banned: true }); user = await this.userRepository.save({ id: id, banned: true });
return user; return user;
} catch (error) { } catch (error) {
this.logger.debug(`[user.banUser] ${JSON.stringify({ error })}`); this.logger.debug(`[user.banUser] ${JSON.stringify({ error })}`);
throw new HttpException('Error occurred', HttpStatus.INTERNAL_SERVER_ERROR); throw new HttpException("Error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
}
} }
}
async unBanUser(id: string) { async unBanUser(id: string) {
try { try {
this.logger.debug(`[user.unBanUser] id: ${JSON.stringify(id)}`); this.logger.debug(`[user.unBanUser] id: ${JSON.stringify(id)}`);
let user = await this.userRepository.findOne({ let user = await this.userRepository.findOne({
where: { id: id }, where: { id: id },
}); });
if (!user) { if (!user) {
throw new HttpException('No user with this id', HttpStatus.NOT_FOUND); throw new HttpException("No user with this id", HttpStatus.NOT_FOUND);
} }
user = await this.userRepository.save({ id: user.id, banned: false }); user = await this.userRepository.save({ id: user.id, banned: false });
return user; return user;
} catch (error) { } catch (error) {
if (error instanceof HttpException) { if (error instanceof HttpException) {
this.logger.debug(`[user.unBanUser] User with id: ${id} not found`); this.logger.debug(`[user.unBanUser] User with id: ${id} not found`);
throw error; throw error;
} }
this.logger.debug(`[user.deBanUser] ${JSON.stringify({ error })}`); this.logger.debug(`[user.deBanUser] ${JSON.stringify({ error })}`);
throw new HttpException(`Error occurred`, HttpStatus.INTERNAL_SERVER_ERROR); throw new HttpException(`Error occurred`, HttpStatus.INTERNAL_SERVER_ERROR);
}
} }
}
async getBannedUsers() { async getBannedUsers() {
try { try {
this.logger.log('[user.getBannedUsers]'); this.logger.log("[user.getBannedUsers]");
return await this.userRepository.find({ where: { banned: true }, select: { id: true, user_name: true } }); return await this.userRepository.find({
} catch (error) { where: { banned: true },
this.logger.debug(`[user.getBannedUsers] ${error}`); select: { id: true, user_name: true },
throw new HttpException('Error occurred', HttpStatus.INTERNAL_SERVER_ERROR); });
} } catch (error) {
this.logger.debug(`[user.getBannedUsers] ${error}`);
throw new HttpException("Error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
} }
}
} }

View File

@@ -1,9 +1,9 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from "@nestjs/testing";
import { INestApplication } from '@nestjs/common'; import { INestApplication } from "@nestjs/common";
import * as request from 'supertest'; import * as request from "supertest";
import { AppModule } from './../src/app.module'; import { AppModule } from "./../src/app.module";
describe('AppController (e2e)', () => { describe("AppController (e2e)", () => {
let app: INestApplication; let app: INestApplication;
beforeEach(async () => { beforeEach(async () => {
@@ -15,10 +15,7 @@ describe('AppController (e2e)', () => {
await app.init(); await app.init();
}); });
it('/ (GET)', () => { it("/ (GET)", () => {
return request(app.getHttpServer()) return request(app.getHttpServer()).get("/").expect(200).expect("Hello World!");
.get('/')
.expect(200)
.expect('Hello World!');
}); });
}); });

View File

@@ -18,4 +18,4 @@
"forceConsistentCasingInFileNames": false, "forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false "noFallthroughCasesInSwitch": false
} }
} }

View File

@@ -1 +0,0 @@
{ "dependencies": { "@nestjs/jwt": "^10.2.0" } }