feat: implement project settings management with CRUD operations and caching
This commit is contained in:
@ -14,6 +14,7 @@ import { Database } from "../../databaseManager/entities/database.entity";
|
||||
import { FunctionEntity } from "../../query/entities/function.entity";
|
||||
import { RedisNode } from "../../redisManager/entities/redis.node.entity";
|
||||
import { Log } from "../../query/logger/entities/log.entity";
|
||||
import { ProjectSetting } from "../settings/entities/project.setting.entity";
|
||||
|
||||
@Entity("project")
|
||||
export class Project {
|
||||
@ -39,6 +40,9 @@ export class Project {
|
||||
@OneToMany(() => FunctionEntity, (functionEntity) => functionEntity.project)
|
||||
functions: FunctionEntity[];
|
||||
|
||||
@OneToMany(() => ProjectSetting, (setting) => setting.project)
|
||||
settings: ProjectSetting[];
|
||||
|
||||
@ManyToMany(() => RedisNode, (redisNode) => redisNode.projects)
|
||||
@JoinTable()
|
||||
redisNodes: RedisNode[];
|
||||
|
||||
@ -1,14 +1,26 @@
|
||||
import { Body, Controller, Inject, Put, UseGuards } from "@nestjs/common";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Inject,
|
||||
Put,
|
||||
Req,
|
||||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import { ProjectService } from "./project.service";
|
||||
import { ApiTokenGuard } from "src/api/guards/api-token.guard";
|
||||
import { AdminGuard } from "src/api/guards/admin.guard";
|
||||
import { ProjectSettingService } from "./settings/project.setting.service";
|
||||
|
||||
@Controller("project")
|
||||
@UseGuards(ApiTokenGuard)
|
||||
export class ProjectController {
|
||||
constructor(
|
||||
@Inject(ProjectService)
|
||||
private readonly projectService: ProjectService
|
||||
private readonly projectService: ProjectService,
|
||||
@Inject(ProjectSettingService)
|
||||
private readonly projectSettingService: ProjectSettingService
|
||||
) {}
|
||||
|
||||
@Put("create")
|
||||
@ -21,4 +33,29 @@ export class ProjectController {
|
||||
createProjectWithoutDB(@Body() body: { name: string }) {
|
||||
return this.projectService.create(body.name, false);
|
||||
}
|
||||
|
||||
@Put("settings/create")
|
||||
createSetting(
|
||||
@Body() body: { key: string; value: string },
|
||||
@Req() req: Request & { apiToken: { id: string } }
|
||||
) {
|
||||
return this.projectSettingService.create(
|
||||
req.apiToken.id,
|
||||
body.key,
|
||||
body.value
|
||||
);
|
||||
}
|
||||
|
||||
@Delete("settings/delete")
|
||||
deleteSetting(
|
||||
@Body() body: { key: string },
|
||||
@Req() req: Request & { apiToken: { id: string } }
|
||||
) {
|
||||
return this.projectSettingService.delete(req.apiToken.id, body.key);
|
||||
}
|
||||
|
||||
@Get("settings")
|
||||
getAllSettings(@Req() req: Request & { apiToken: { id: string } }) {
|
||||
return this.projectSettingService.getAll(req.apiToken.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,16 +6,18 @@ import { ProjectController } from "./project.controller";
|
||||
import { ApiModule } from "src/api/api.module";
|
||||
import { RedisModule } from "src/redis/redis.module";
|
||||
import { DatabaseManagerModule } from "src/databaseManager/database.manager.module";
|
||||
import { ProjectSetting } from "./settings/entities/project.setting.entity";
|
||||
import { ProjectSettingService } from "./settings/project.setting.service";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => RedisModule),
|
||||
forwardRef(() => DatabaseManagerModule),
|
||||
TypeOrmModule.forFeature([Project]),
|
||||
TypeOrmModule.forFeature([Project, ProjectSetting]),
|
||||
],
|
||||
controllers: [ProjectController],
|
||||
providers: [ProjectService],
|
||||
exports: [ProjectService],
|
||||
providers: [ProjectService, ProjectSettingService],
|
||||
exports: [ProjectService, ProjectSettingService],
|
||||
})
|
||||
export class ProjectModule {}
|
||||
|
||||
@ -4,6 +4,7 @@ import { Repository } from "typeorm";
|
||||
import { Project } from "./entities/project.entity";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
import { DatabaseManagerService } from "src/databaseManager/database/database.manager.service";
|
||||
import { ProjectSettingService } from "./settings/project.setting.service";
|
||||
|
||||
@Injectable()
|
||||
export class ProjectService {
|
||||
@ -13,9 +14,23 @@ export class ProjectService {
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient,
|
||||
@Inject(forwardRef(() => DatabaseManagerService))
|
||||
private readonly databaseManagerService: DatabaseManagerService
|
||||
private readonly databaseManagerService: DatabaseManagerService,
|
||||
@Inject(ProjectSettingService)
|
||||
private readonly projectSettingService: ProjectSettingService
|
||||
) {}
|
||||
|
||||
async createDefaultSettings(projectId: string) {
|
||||
const defaultSettings = [{ key: "sessionTTL", value: "3600" }];
|
||||
|
||||
await Promise.all(
|
||||
defaultSettings.map((setting) =>
|
||||
this.projectSettingService.create(projectId, setting.key, setting.value)
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async create(name: string, createDatabase: boolean = true) {
|
||||
const project = this.projectRepository.create({ name });
|
||||
const projectSaved = await this.projectRepository.save(project);
|
||||
@ -24,6 +39,9 @@ export class ProjectService {
|
||||
await this.databaseManagerService.createDatabase(projectSaved.id);
|
||||
}
|
||||
|
||||
await this.createDefaultSettings(projectSaved.id);
|
||||
await this.redisClient.set(`project_${projectSaved.id}`, projectSaved, 300);
|
||||
|
||||
return projectSaved;
|
||||
}
|
||||
|
||||
|
||||
19
src/project/settings/entities/project.setting.entity.ts
Normal file
19
src/project/settings/entities/project.setting.entity.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
|
||||
import { Project } from "../../entities/project.entity";
|
||||
|
||||
@Entity("projectSetting")
|
||||
export class ProjectSetting {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
id: string;
|
||||
|
||||
@ManyToOne(() => Project, (project) => project.settings, {
|
||||
onDelete: "CASCADE",
|
||||
})
|
||||
project: Project;
|
||||
|
||||
@Column({ type: "varchar", length: 255, nullable: false })
|
||||
key: string;
|
||||
|
||||
@Column({ type: "text", nullable: false })
|
||||
value: string;
|
||||
}
|
||||
112
src/project/settings/project.setting.service.ts
Normal file
112
src/project/settings/project.setting.service.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { ProjectSetting } from "./entities/project.setting.entity";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
|
||||
@Injectable()
|
||||
export class ProjectSettingService {
|
||||
constructor(
|
||||
@InjectRepository(ProjectSetting)
|
||||
private readonly projectSettingRepository: Repository<ProjectSetting>,
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient
|
||||
) {}
|
||||
|
||||
async updateCache(projectId: string) {
|
||||
const settings = await this.projectSettingRepository.find({
|
||||
where: { project: { id: projectId } },
|
||||
});
|
||||
|
||||
const settingsObject = settings.reduce((obj, setting) => {
|
||||
obj[setting.key] = setting.value;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
await this.redisClient.set(
|
||||
`project_settings_${projectId}`,
|
||||
settingsObject,
|
||||
300
|
||||
);
|
||||
|
||||
return settingsObject;
|
||||
}
|
||||
|
||||
async get(key: string, projectId: string) {
|
||||
const cached = await this.redisClient.get(`project_settings_${projectId}`);
|
||||
|
||||
if (cached && key in cached) {
|
||||
return cached[key];
|
||||
}
|
||||
|
||||
const setting = await this.projectSettingRepository.findOne({
|
||||
where: { project: { id: projectId }, key },
|
||||
});
|
||||
|
||||
if (setting) {
|
||||
return setting.value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async getAll(projectId: string) {
|
||||
const cached = await this.redisClient.get(`project_settings_${projectId}`);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const settings = await this.projectSettingRepository.find({
|
||||
where: { project: { id: projectId } },
|
||||
});
|
||||
|
||||
const settingsObject = settings.reduce((obj, setting) => {
|
||||
obj[setting.key] = setting.value;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
await this.redisClient.set(
|
||||
`project_settings_${projectId}`,
|
||||
settingsObject,
|
||||
300
|
||||
);
|
||||
|
||||
return settingsObject;
|
||||
}
|
||||
|
||||
async create(projectId: string, key: string, value: string) {
|
||||
const existingSetting = await this.projectSettingRepository.findOne({
|
||||
where: { project: { id: projectId }, key },
|
||||
});
|
||||
|
||||
if (existingSetting) {
|
||||
existingSetting.value = value;
|
||||
await this.projectSettingRepository.save(existingSetting);
|
||||
|
||||
return await this.updateCache(projectId);
|
||||
}
|
||||
|
||||
const newSetting = this.projectSettingRepository.create({
|
||||
key,
|
||||
value,
|
||||
project: { id: projectId },
|
||||
});
|
||||
|
||||
await this.projectSettingRepository.save(newSetting);
|
||||
|
||||
return await this.updateCache(projectId);
|
||||
}
|
||||
|
||||
async delete(projectId: string, key: string) {
|
||||
const setting = await this.projectSettingRepository.findOne({
|
||||
where: { project: { id: projectId }, key },
|
||||
});
|
||||
|
||||
if (setting) {
|
||||
await this.projectSettingRepository.remove(setting);
|
||||
}
|
||||
|
||||
return await this.updateCache(projectId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user