migrate to ci and postgress

This commit is contained in:
2026-02-08 20:06:17 +03:00
parent 88fcc33e87
commit f839d215f3
16 changed files with 1195 additions and 240 deletions

View File

@ -1,31 +1,34 @@
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { DB_STORAGES, DB_USERS, MONGO_URL } from './consts';
import {
StorageDocument,
StorageScheme,
UserDocument,
UserScheme,
} from './schemas';
import { UserEntity } from './entities/user.entity';
import { StorageEntity } from './entities/storage.entity';
import { HealthModule } from './health/health.module';
@Module({
imports: [
MongooseModule.forRoot(`${MONGO_URL}/${DB_USERS}`, {
connectionName: DB_USERS,
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ['.env.local', '.env'],
}),
MongooseModule.forRoot(`${MONGO_URL}/${DB_STORAGES}`, {
connectionName: DB_STORAGES,
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get('DATABASE_HOST', 'localhost'),
port: configService.get('DATABASE_PORT', 5432),
username: configService.get('DATABASE_USER', 'postgres'),
password: configService.get('DATABASE_PASSWORD', 'postgres'),
database: configService.get('DATABASE_NAME', 'simple_storage_db'),
entities: [UserEntity, StorageEntity],
synchronize: true,
}),
}),
MongooseModule.forFeature(
[{ name: UserDocument.name, schema: UserScheme }],
DB_USERS,
),
MongooseModule.forFeature(
[{ name: StorageDocument.name, schema: StorageScheme }],
DB_STORAGES,
),
TypeOrmModule.forFeature([UserEntity, StorageEntity]),
HealthModule,
],
controllers: [AppController],
providers: [AppService],

View File

@ -3,9 +3,11 @@ import {
Injectable,
NotAcceptableException,
} from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { StorageDocument, UserDocument } from './schemas';
import { Model } from 'mongoose';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { v4 } from 'uuid';
import { UserEntity } from './entities/user.entity';
import { StorageEntity } from './entities/storage.entity';
import {
User,
Storage,
@ -13,21 +15,18 @@ import {
StorageUpdate,
StorageList,
} from './types';
import { v4 } from 'uuid';
import { DB_STORAGES, DB_USERS } from './consts';
@Injectable()
export class AppService {
constructor(
@InjectModel(UserDocument.name, DB_USERS)
private userModel: Model<UserDocument>,
@InjectModel(StorageDocument.name, DB_STORAGES)
private storageModel: Model<StorageDocument>,
@InjectRepository(UserEntity)
private userRepository: Repository<UserEntity>,
@InjectRepository(StorageEntity)
private storageRepository: Repository<StorageEntity>,
) {}
async checkRequest(token?: string): Promise<User> {
const userList = await this.userModel.find().exec();
const searchUser = userList.find((user) => user.token === token);
const searchUser = await this.userRepository.findOne({ where: { token } });
if (searchUser) {
return {
login: searchUser.login,
@ -38,37 +37,36 @@ export class AppService {
}
async authUser(login: string): Promise<string> {
const userList = await this.userModel.find().exec();
const searchUser = userList.find((user) => user.login === login);
const searchUser = await this.userRepository.findOne({ where: { login } });
if (searchUser) {
return searchUser.token;
}
const Model = this.userModel;
const userModel = new Model({
const newUser = await this.userRepository.save({
login,
token: v4(),
});
const newUser = await userModel.save();
return newUser.token;
}
async getStorageList(login: string): Promise<StorageList> {
const storageList = await this.storageModel.find().exec();
const preparedList = storageList.map(({ _id, user, storageName }) => ({
id: _id as string,
const storageList = await this.storageRepository.find({
where: { user: login },
});
return storageList.map(({ id, user, storageName }) => ({
id,
user,
storageName,
}));
return preparedList.filter(({ user }) => user === login);
}
async getStorageById(login: string, id: string): Promise<Storage> {
const searchStorage = await this.storageModel.findById(id);
const searchStorage = await this.storageRepository.findOne({
where: { id },
});
if (searchStorage && searchStorage.user === login) {
return {
data: searchStorage.data,
id: searchStorage._id as string,
id: searchStorage.id,
storageName: searchStorage.storageName,
user: searchStorage.user,
};
@ -77,25 +75,19 @@ export class AppService {
}
async addStorage(login: string, storage: StorageCreate): Promise<Storage> {
const Model = this.storageModel;
const storageModel = new Model({
if (!storage.data || !storage.storageName) {
throw new BadRequestException('data и storageName обязательны');
}
const newStorage = await this.storageRepository.save({
data: storage.data,
storageName: storage.storageName,
user: login,
});
try {
await storageModel.validate();
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
throw new BadRequestException(e.message);
}
const newStorage = await storageModel.save();
return {
data: newStorage.data,
user: newStorage.user,
storageName: newStorage.storageName,
id: newStorage._id as string,
id: newStorage.id,
};
}
@ -104,7 +96,9 @@ export class AppService {
id: string,
storage: StorageUpdate,
): Promise<Storage> {
const searchStorage = await this.storageModel.findById(id);
const searchStorage = await this.storageRepository.findOne({
where: { id },
});
if (!searchStorage || searchStorage.user !== login) {
throw new BadRequestException(`Storage с id - "${id}" не найден`);
@ -112,7 +106,7 @@ export class AppService {
const updatedStorageName = storage.storageName ?? searchStorage.storageName;
await searchStorage.updateOne({
await this.storageRepository.update(id, {
data: storage.data,
storageName: updatedStorageName,
});
@ -121,24 +115,25 @@ export class AppService {
data: storage.data,
user: searchStorage.user,
storageName: updatedStorageName,
id: searchStorage._id as string,
id: searchStorage.id,
};
}
async deleteStorageById(login: string, id: string): Promise<Storage> {
const searchStorage = await this.storageModel.findById(id);
const searchStorage = await this.storageRepository.findOne({
where: { id },
});
if (!searchStorage || searchStorage.user !== login) {
throw new BadRequestException(`Storage с id - "${id}" не найден`);
}
const Model = this.storageModel;
await Model.findByIdAndDelete(id);
await this.storageRepository.delete(id);
return {
data: searchStorage.data,
user: searchStorage.user,
storageName: searchStorage.storageName,
id: searchStorage._id as string,
id: searchStorage.id,
};
}
}

View File

@ -1,10 +1,3 @@
// Подключение к MongoDB
export const MONGO_URL = process.env.MONGODB_URI || 'mongodb://localhost:27017';
// Имя базы данных для пользователей и хранилищ
export const DB_USERS = process.env.DB_USERS || 'storage-back-users';
export const DB_STORAGES = process.env.DB_STORAGES || 'storage-back-storages';
// Порт приложения
export const APP_PORT = parseInt(process.env.APP_PORT || '3000', 10);

View File

@ -0,0 +1,16 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity('storages')
export class StorageEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'jsonb' })
data: object;
@Column({ type: 'varchar' })
storageName: string;
@Column({ type: 'varchar' })
user: string;
}

View File

@ -0,0 +1,13 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity('users')
export class UserEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ type: 'varchar', unique: true })
login: string;
@Column({ type: 'varchar' })
token: string;
}

View File

@ -0,0 +1,20 @@
import { Controller, Get } from '@nestjs/common';
import {
HealthCheckService,
HealthCheck,
TypeOrmHealthIndicator,
} from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private db: TypeOrmHealthIndicator,
) {}
@Get()
@HealthCheck()
check() {
return this.health.check([() => this.db.pingCheck('database')]);
}
}

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';
@Module({
imports: [TerminusModule],
controllers: [HealthController],
})
export class HealthModule {}

View File

@ -1,6 +1,4 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { ApiProperty } from '@nestjs/swagger';
import { Document } from 'mongoose';
import { Storage, StorageCreate } from './types';
export class AuthRequest {
@ -8,45 +6,6 @@ export class AuthRequest {
login: string;
}
@Schema()
export class UserDocument extends Document {
@Prop({
type: String,
required: true,
})
login: string;
@Prop({
type: String,
required: true,
})
token: string;
}
@Schema()
export class StorageDocument extends Document {
@Prop({
type: Object,
required: true,
})
data: object;
@Prop({
type: String,
required: true,
})
storageName: string;
@Prop({
type: String,
required: true,
})
user: string;
}
export const StorageScheme = SchemaFactory.createForClass(StorageDocument);
export const UserScheme = SchemaFactory.createForClass(UserDocument);
export class StorageResponse implements Storage {
@ApiProperty()
data: object;