mirror of
https://github.com/MrSedan/neuro-reply-website.git
synced 2026-01-14 20:49:42 +03:00
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "neuro-reply-bot-reworked"]
|
||||
path = neuro-reply-bot-reworked
|
||||
url = git@github.com:MrSedan/neuro-reply-bot-reworked.git
|
||||
branch = dev
|
||||
@@ -4,5 +4,6 @@
|
||||
"semi": true,
|
||||
"tabWidth": 4,
|
||||
"printWidth": 150,
|
||||
"bracketSpacing": true
|
||||
"bracketSpacing": true,
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
|
||||
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
@@ -11,4 +11,15 @@
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[dockercompose]": {
|
||||
"editor.insertSpaces": true,
|
||||
"editor.tabSize": 2,
|
||||
"editor.autoIndent": "advanced",
|
||||
"editor.quickSuggestions": {
|
||||
"other": true,
|
||||
"comments": false,
|
||||
"strings": true
|
||||
},
|
||||
"editor.defaultFormatter": "ms-azuretools.vscode-docker"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { config as configInit } from 'dotenv';
|
||||
|
||||
configInit();
|
||||
configInit({ path: '../.env' });
|
||||
|
||||
export const config = {
|
||||
database: {
|
||||
|
||||
19
backend/libs/database/admin.entity.ts
Normal file
19
backend/libs/database/admin.entity.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { User } from './user.entity';
|
||||
|
||||
@Entity()
|
||||
export class Admin {
|
||||
constructor(props?: Partial<Admin>) {
|
||||
Object.assign(this, props);
|
||||
}
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
public id!: number;
|
||||
|
||||
@Column({ nullable: false })
|
||||
public user_id!: string;
|
||||
|
||||
@OneToOne(() => User, (user) => user.id, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
public user!: User;
|
||||
}
|
||||
25
backend/libs/database/image.entity.ts
Normal file
25
backend/libs/database/image.entity.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
|
||||
import { Post } from './post.entity';
|
||||
|
||||
@Entity()
|
||||
export class Image {
|
||||
constructor(props?: Partial<Image>) {
|
||||
Object.assign(this, props);
|
||||
}
|
||||
|
||||
@PrimaryColumn()
|
||||
public message_id!: number;
|
||||
|
||||
@Column({ nullable: false })
|
||||
public file_id!: string;
|
||||
|
||||
@Column({ default: false })
|
||||
public has_spoiler!: boolean;
|
||||
|
||||
@Column({ nullable: false })
|
||||
public post_uuid!: string;
|
||||
|
||||
@ManyToOne(() => Post, (post) => post.uuid, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'post_uuid' })
|
||||
public post!: Post;
|
||||
}
|
||||
34
backend/libs/database/post.entity.ts
Normal file
34
backend/libs/database/post.entity.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { Admin } from './admin.entity';
|
||||
import { Image } from './image.entity';
|
||||
@Entity()
|
||||
export class Post {
|
||||
constructor(props?: Partial<Post>) {
|
||||
Object.assign(this, props);
|
||||
}
|
||||
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
public uuid!: string;
|
||||
|
||||
@Column({ default: false })
|
||||
public posted!: boolean;
|
||||
|
||||
@Column()
|
||||
public text: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
public media_group_id: string;
|
||||
|
||||
@Column({ type: 'timestamptz' })
|
||||
public timestamp!: Date;
|
||||
|
||||
@Column({ nullable: false })
|
||||
public from_user_id!: string;
|
||||
|
||||
@ManyToOne(() => Admin, (admin) => admin.user.id)
|
||||
@JoinColumn({ name: 'from_user_id', referencedColumnName: 'user_id' })
|
||||
public from_user!: Admin;
|
||||
|
||||
@OneToMany(() => Image, (image) => image.post)
|
||||
public images: Image[];
|
||||
}
|
||||
5
backend/libs/enums/getAll.enum.ts
Normal file
5
backend/libs/enums/getAll.enum.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum EGetAll {
|
||||
all = 'all',
|
||||
will_post = 'will-post',
|
||||
posted = 'posted',
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { User } from './database/user.entity';
|
||||
import { Admin } from './database/admin.entity';
|
||||
import { Post } from './database/post.entity';
|
||||
import { Image } from './database/image.entity';
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([User])],
|
||||
imports: [TypeOrmModule.forFeature([User, Admin, Post, Image])],
|
||||
exports: [TypeOrmModule],
|
||||
})
|
||||
export class LibsModule {}
|
||||
|
||||
@@ -2,11 +2,14 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
import { config } from 'config';
|
||||
import { LibsModule } from 'libs/libs.module';
|
||||
import { AdminModule } from './modules/admin/admin.module';
|
||||
import { ImageModule } from './modules/image/image.module';
|
||||
import { AppInitService } from './modules/initialization/app.init.service';
|
||||
import { PostModule } from './modules/post/post.module';
|
||||
import { UserModule } from './modules/user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [LibsModule, UserModule, TypeOrmModule.forRoot(<TypeOrmModuleOptions>config.database)],
|
||||
imports: [LibsModule, PostModule, AdminModule, UserModule, ImageModule, TypeOrmModule.forRoot(<TypeOrmModuleOptions>config.database)],
|
||||
controllers: [],
|
||||
providers: [AppInitService],
|
||||
})
|
||||
|
||||
22
backend/src/modules/admin/admin.controller.ts
Normal file
22
backend/src/modules/admin/admin.controller.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Controller, Get, Param } from '@nestjs/common';
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { AdminService } from './admin.service';
|
||||
|
||||
@ApiTags('Admin')
|
||||
@Controller('admin')
|
||||
export class AdminController {
|
||||
constructor(private adminService: AdminService) {}
|
||||
|
||||
@ApiOperation({
|
||||
description: 'Get admins from db',
|
||||
})
|
||||
@Get('get')
|
||||
async getAdmin() {
|
||||
return await this.adminService.getAdmins();
|
||||
}
|
||||
@ApiOperation({ description: 'Check admin is or not' })
|
||||
@Get('is-admin/:id')
|
||||
async isAdmin(@Param('id') id: string) {
|
||||
return await this.adminService.checkIsAdmin(id);
|
||||
}
|
||||
}
|
||||
11
backend/src/modules/admin/admin.module.ts
Normal file
11
backend/src/modules/admin/admin.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LibsModule } from 'libs/libs.module';
|
||||
import { AdminController } from './admin.controller';
|
||||
import { AdminService } from './admin.service';
|
||||
|
||||
@Module({
|
||||
imports: [LibsModule],
|
||||
controllers: [AdminController],
|
||||
providers: [AdminService],
|
||||
})
|
||||
export class AdminModule {}
|
||||
37
backend/src/modules/admin/admin.service.ts
Normal file
37
backend/src/modules/admin/admin.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Admin } from 'libs/database/admin.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class AdminService {
|
||||
private readonly logger: Logger = new Logger(AdminService.name);
|
||||
constructor(@InjectRepository(Admin) private adminRepository: Repository<Admin>) {}
|
||||
|
||||
async getAdmins() {
|
||||
try {
|
||||
this.logger.debug(`[admin.getAdmins]`);
|
||||
const admins = await this.adminRepository.find();
|
||||
return admins;
|
||||
} catch (error) {
|
||||
this.logger.log(`[getAdmin] ${JSON.stringify({ error })}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
async checkIsAdmin(id: string) {
|
||||
try {
|
||||
this.logger.debug(`[admin.checkIsAdmin]`);
|
||||
const admins = await this.adminRepository.findOne({
|
||||
relations: { user: true },
|
||||
where: { user: { id: id } },
|
||||
});
|
||||
if (!admins) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
this.logger.debug(`[checkIsAdmin] ${JSON.stringify({ error })}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
backend/src/modules/image/image.controller.ts
Normal file
16
backend/src/modules/image/image.controller.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import { IAddImage } from './image.dto';
|
||||
import { ImageService } from './image.service';
|
||||
|
||||
@ApiTags('Image')
|
||||
@Controller('image')
|
||||
export class ImageController {
|
||||
constructor(private imageService: ImageService) {}
|
||||
|
||||
@ApiOperation({ description: 'A method to add photo to post' })
|
||||
@Post('add')
|
||||
async addImage(@Body() data: IAddImage) {
|
||||
return await this.imageService.add(data);
|
||||
}
|
||||
}
|
||||
8
backend/src/modules/image/image.dto.ts
Normal file
8
backend/src/modules/image/image.dto.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class IAddImage {
|
||||
@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: 'Has image the spoiler?', example: false }) readonly has_spoiler!: boolean;
|
||||
@ApiProperty({ description: 'A photo message id', example: '123124' }) readonly message_id!: number;
|
||||
}
|
||||
11
backend/src/modules/image/image.module.ts
Normal file
11
backend/src/modules/image/image.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LibsModule } from 'libs/libs.module';
|
||||
import { ImageController } from './image.controller';
|
||||
import { ImageService } from './image.service';
|
||||
|
||||
@Module({
|
||||
imports: [LibsModule],
|
||||
controllers: [ImageController],
|
||||
providers: [ImageService],
|
||||
})
|
||||
export class ImageModule {}
|
||||
26
backend/src/modules/image/image.service.ts
Normal file
26
backend/src/modules/image/image.service.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Image } from 'libs/database/image.entity';
|
||||
import { Post } from 'libs/database/post.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
import { IAddImage } from './image.dto';
|
||||
@Injectable()
|
||||
export class ImageService {
|
||||
private readonly logger: Logger = new Logger(ImageService.name);
|
||||
constructor(
|
||||
@InjectRepository(Image) private imageRepository: Repository<Image>,
|
||||
@InjectRepository(Post) private postRepository: Repository<Post>,
|
||||
) {}
|
||||
|
||||
async add(data: IAddImage) {
|
||||
try {
|
||||
this.logger.log(`[image.add] data: ${JSON.stringify(data)}`);
|
||||
const post = await this.postRepository.findOne({ where: { uuid: data.post_id } });
|
||||
await this.imageRepository.save({ post: post, file_id: data.file_id, has_spoiler: data.has_spoiler, message_id: data.message_id });
|
||||
return { status: 'ok' };
|
||||
} catch (error) {
|
||||
this.logger.debug(`[image.add] error: ${JSON.stringify(error)}`);
|
||||
throw new HttpException('No posts', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,19 @@
|
||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Admin } from 'libs/database/admin.entity';
|
||||
import { Image } from 'libs/database/image.entity';
|
||||
import { Post } from 'libs/database/post.entity';
|
||||
import { User } from 'libs/database/user.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class AppInitService implements OnModuleInit {
|
||||
constructor(@InjectRepository(User) private userRepository: Repository<User>) {}
|
||||
constructor(
|
||||
@InjectRepository(User) private userRepository: Repository<User>,
|
||||
@InjectRepository(Admin) private adminRepository: Repository<Admin>,
|
||||
@InjectRepository(Post) private postRepository: Repository<Post>,
|
||||
@InjectRepository(Image) private ImageRepository: Repository<Image>,
|
||||
) {}
|
||||
|
||||
async onModuleInit() {}
|
||||
}
|
||||
|
||||
42
backend/src/modules/post/post.controller.ts
Normal file
42
backend/src/modules/post/post.controller.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
|
||||
import { ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
||||
import { EGetAll } from 'libs/enums/getAll.enum';
|
||||
import { ICreatePost, IEditPost } from './post.dto';
|
||||
import { PostService } from './post.service';
|
||||
|
||||
@ApiTags('Post')
|
||||
@Controller('post')
|
||||
export class PostController {
|
||||
constructor(private postService: PostService) {}
|
||||
|
||||
@ApiOperation({ description: 'Creates a new post' })
|
||||
@Post('new')
|
||||
async newPost(@Body() data: ICreatePost) {
|
||||
return await this.postService.newPost(data);
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Getting all posts. By default - all' })
|
||||
@Get('get-all/:status')
|
||||
@ApiParam({ name: 'status', required: false, enum: EGetAll })
|
||||
async getAllPosts(@Param('status') status?: EGetAll) {
|
||||
return await this.postService.getAllPosts(status || EGetAll.all);
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Getting a post by uuid' })
|
||||
@Get('get/:postId')
|
||||
async getPost(@Param('postId') postId: string) {
|
||||
return await this.postService.getPost(postId);
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Getting a post by its media group id' })
|
||||
@Get('get-by-media-group-id/:mediaGroupId')
|
||||
async getByMediaGroup(@Param('mediaGroupId') mediaGroupId: string) {
|
||||
return await this.postService.getByMediaGroup(mediaGroupId);
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Editing a post by its uuid' })
|
||||
@Post('edit/:postId')
|
||||
async editPost(@Param('postId') postId: string, @Body() data: IEditPost) {
|
||||
return await this.postService.editPost(postId, data);
|
||||
}
|
||||
}
|
||||
13
backend/src/modules/post/post.dto.ts
Normal file
13
backend/src/modules/post/post.dto.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class ICreatePost {
|
||||
@ApiProperty({ description: 'Post text', example: 'Post text' }) readonly text!: string;
|
||||
|
||||
@ApiProperty({ description: 'An 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;
|
||||
}
|
||||
|
||||
export class IEditPost {
|
||||
@ApiProperty({ description: 'Post text', example: 'Post text' }) readonly text!: string;
|
||||
}
|
||||
11
backend/src/modules/post/post.module.ts
Normal file
11
backend/src/modules/post/post.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LibsModule } from 'libs/libs.module';
|
||||
import { PostController } from './post.controller';
|
||||
import { PostService } from './post.service';
|
||||
|
||||
@Module({
|
||||
imports: [LibsModule],
|
||||
controllers: [PostController],
|
||||
providers: [PostService],
|
||||
})
|
||||
export class PostModule {}
|
||||
98
backend/src/modules/post/post.service.ts
Normal file
98
backend/src/modules/post/post.service.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Admin } from 'libs/database/admin.entity';
|
||||
import { Post } from 'libs/database/post.entity';
|
||||
import { EGetAll } from 'libs/enums/getAll.enum';
|
||||
import { Repository } from 'typeorm';
|
||||
import { ICreatePost, IEditPost } from './post.dto';
|
||||
|
||||
@Injectable()
|
||||
export class PostService {
|
||||
private readonly logger: Logger = new Logger(PostService.name);
|
||||
constructor(
|
||||
@InjectRepository(Post) private postRepository: Repository<Post>,
|
||||
@InjectRepository(Admin) private adminRepository: Repository<Admin>,
|
||||
) {}
|
||||
|
||||
async newPost(data: ICreatePost) {
|
||||
try {
|
||||
this.logger.log(`[post.newPost] data: ${JSON.stringify(data)}`);
|
||||
const user = await this.adminRepository.findOne({ where: { user: { id: data.from_user_id } }, relations: { user: true } });
|
||||
const result = await this.postRepository.save({
|
||||
text: data.text,
|
||||
media_group_id: data.media_group_id,
|
||||
from_user: user,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
this.logger.log(`Created new post: ${result.uuid}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.debug(`[post.newPost] error: ${JSON.stringify(error)}`);
|
||||
throw new HttpException('No user with this id', HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
async editPost(postId: string, data: IEditPost) {
|
||||
try {
|
||||
this.logger.log(`[post.editPost] data: ${JSON.stringify(data)}`);
|
||||
const post = await this.postRepository.findOne({ where: { uuid: postId } });
|
||||
if (!post) {
|
||||
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
if (post.text !== data.text) {
|
||||
post.text = data.text;
|
||||
post.timestamp = new Date();
|
||||
await this.postRepository.save(post);
|
||||
}
|
||||
return post;
|
||||
} catch (error) {
|
||||
this.logger.debug(`[post.editPost] error: ${JSON.stringify(error)}`);
|
||||
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
async getAllPosts(status: EGetAll) {
|
||||
try {
|
||||
let obj: object;
|
||||
switch (status) {
|
||||
case EGetAll.will_post:
|
||||
obj = { where: { posted: false } };
|
||||
break;
|
||||
case EGetAll.all:
|
||||
obj = {};
|
||||
break;
|
||||
case EGetAll.posted:
|
||||
obj = { where: { posted: true } };
|
||||
break;
|
||||
}
|
||||
return await this.postRepository.find(obj);
|
||||
} catch (error) {
|
||||
this.logger.log(`[post.getAllPosts] error: ${JSON.stringify(error)}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getPost(postId: string) {
|
||||
try {
|
||||
this.logger.log(`[post.getPost] data: ${postId}`);
|
||||
const post = await this.postRepository.findOne({ where: { uuid: postId }, relations: { images: true } });
|
||||
if (!post) throw new Error("Can't find post");
|
||||
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 getByMediaGroup(mediaGroupId: string) {
|
||||
try {
|
||||
this.logger.log(`[post.getByMediaGroup] data: ${mediaGroupId}`);
|
||||
const post = await this.postRepository.findOne({ where: { media_group_id: mediaGroupId } });
|
||||
if (!post) throw new Error("Can't find post");
|
||||
return post;
|
||||
} catch (error) {
|
||||
this.logger.debug(`[post.getByMediaGroup] error: ${JSON.stringify(error)}`);
|
||||
throw new HttpException("Can't find post with this media group id", HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,13 @@ import { UserService } from './user.service';
|
||||
@ApiTags('User')
|
||||
@Controller('user')
|
||||
export class UserController {
|
||||
constructor(private adminService: UserService) {}
|
||||
constructor(private userService: UserService) {}
|
||||
|
||||
@ApiOperation({
|
||||
description: 'Create or get user from db',
|
||||
})
|
||||
@Post('get')
|
||||
async getUser(@Body() data: IGetUser) {
|
||||
return await this.adminService.getUser(data);
|
||||
return await this.userService.getUser(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export class UserService {
|
||||
|
||||
async getUser(data: IGetUser) {
|
||||
try {
|
||||
this.logger.debug(`[admin.getUser] data: ${JSON.stringify(data)}`);
|
||||
this.logger.debug(`[user.getUser] data: ${JSON.stringify(data)}`);
|
||||
let user = await this.userRepository.findOne({
|
||||
where: { id: data.id },
|
||||
});
|
||||
@@ -21,7 +21,7 @@ export class UserService {
|
||||
}
|
||||
return user;
|
||||
} catch (error) {
|
||||
this.logger.log(`[getUser] ${JSON.stringify({ error })}`);
|
||||
this.logger.log(`[user.getUser] ${JSON.stringify({ error })}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
docker-compose.yml
Normal file
21
docker-compose.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
db:
|
||||
container_name: neuro_db
|
||||
image: postgres:alpine
|
||||
environment:
|
||||
- POSTGRES_USER=${DATABASE_USER}
|
||||
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
|
||||
- POSTGRES_DB=${DATABASE_NAME}
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
ports:
|
||||
- "${DATABASE_PORT}:5432"
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- neuro_postgres_db:/var/lib/postgresql/data
|
||||
restart: always
|
||||
volumes:
|
||||
neuro_postgres_db:
|
||||
driver: local
|
||||
1
neuro-reply-bot-reworked
Submodule
1
neuro-reply-bot-reworked
Submodule
Submodule neuro-reply-bot-reworked added at d286da698e
Reference in New Issue
Block a user