@drax/settings-back 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/controller/SettingController.js +89 -0
- package/dist/factory/SettingServiceFactory.js +24 -0
- package/dist/index.js +8 -0
- package/dist/interfaces/ISettingRepository.js +1 -0
- package/dist/model/SettingsModel.js +28 -0
- package/dist/permissions/SettingPermissions.js +8 -0
- package/dist/repository/mongo/SettingMongoRepository.js +13 -0
- package/dist/repository/sqlite/SettingSqliteRepository.js +113 -0
- package/dist/routes/SettingRoutes.js +10 -0
- package/dist/schemas/SettingSchema.js +7 -0
- package/dist/services/SettingService.js +95 -0
- package/package.json +66 -0
- package/src/controller/SettingController.ts +92 -0
- package/src/factory/SettingServiceFactory.ts +32 -0
- package/src/index.ts +24 -0
- package/src/interfaces/ISettingRepository.ts +6 -0
- package/src/model/SettingsModel.ts +46 -0
- package/src/permissions/SettingPermissions.ts +9 -0
- package/src/repository/mongo/SettingMongoRepository.ts +23 -0
- package/src/repository/sqlite/SettingSqliteRepository.ts +176 -0
- package/src/routes/SettingRoutes.ts +17 -0
- package/src/schemas/SettingSchema.ts +11 -0
- package/src/services/SettingService.ts +111 -0
- package/test/repository/mongo/MongoInMemory.ts +43 -0
- package/test/repository/mongo/SettingMongoRepository.test.ts +180 -0
- package/test/repository/sqlite/SettingSqliteRepository.test.ts +175 -0
- package/test/services/SettingService.test.ts +319 -0
- package/test.db +0 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/types/controller/SettingController.d.ts +15 -0
- package/types/controller/SettingController.d.ts.map +1 -0
- package/types/factory/SettingServiceFactory.d.ts +4 -0
- package/types/factory/SettingServiceFactory.d.ts.map +1 -0
- package/types/index.d.ts +11 -0
- package/types/index.d.ts.map +1 -0
- package/types/interfaces/ISettingRepository.d.ts +6 -0
- package/types/interfaces/ISettingRepository.d.ts.map +1 -0
- package/types/model/SettingsModel.d.ts +19 -0
- package/types/model/SettingsModel.d.ts.map +1 -0
- package/types/permissions/SettingPermissions.d.ts +8 -0
- package/types/permissions/SettingPermissions.d.ts.map +1 -0
- package/types/repository/mongo/SettingMongoRepository.d.ts +9 -0
- package/types/repository/mongo/SettingMongoRepository.d.ts.map +1 -0
- package/types/repository/sqlite/SettingSqliteRepository.d.ts +22 -0
- package/types/repository/sqlite/SettingSqliteRepository.d.ts.map +1 -0
- package/types/routes/SettingRoutes.d.ts +4 -0
- package/types/routes/SettingRoutes.d.ts.map +1 -0
- package/types/schemas/SettingSchema.d.ts +10 -0
- package/types/schemas/SettingSchema.d.ts.map +1 -0
- package/types/services/SettingService.d.ts +23 -0
- package/types/services/SettingService.d.ts.map +1 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { SettingPermissions } from "../permissions/SettingPermissions.js";
|
|
2
|
+
import SettingServiceFactory from "../factory/SettingServiceFactory.js";
|
|
3
|
+
import { UnauthorizedError, ValidationError } from "@drax/common-back";
|
|
4
|
+
class SettingController {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.service = SettingServiceFactory();
|
|
7
|
+
}
|
|
8
|
+
async fetchAll(request, reply) {
|
|
9
|
+
try {
|
|
10
|
+
request.rbac.assertPermission(SettingPermissions.View);
|
|
11
|
+
const settings = await this.service.fetchAll();
|
|
12
|
+
return settings;
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
console.error(e);
|
|
16
|
+
if (e instanceof UnauthorizedError) {
|
|
17
|
+
reply.statusCode = e.statusCode;
|
|
18
|
+
reply.send({ error: e.message });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
reply.statusCode = 500;
|
|
22
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async fetchGrouped(request, reply) {
|
|
27
|
+
try {
|
|
28
|
+
request.rbac.assertPermission(SettingPermissions.View);
|
|
29
|
+
const settings = await this.service.fetchGrouped();
|
|
30
|
+
return settings;
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.error(e);
|
|
34
|
+
if (e instanceof UnauthorizedError) {
|
|
35
|
+
reply.statusCode = e.statusCode;
|
|
36
|
+
reply.send({ error: e.message });
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
reply.statusCode = 500;
|
|
40
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async findByKey(request, reply) {
|
|
45
|
+
try {
|
|
46
|
+
request.rbac.assertPermission(SettingPermissions.View);
|
|
47
|
+
const key = request.params.key;
|
|
48
|
+
const setting = await this.service.findByKey(key);
|
|
49
|
+
return setting;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
console.error(e);
|
|
53
|
+
if (e instanceof UnauthorizedError) {
|
|
54
|
+
reply.statusCode = e.statusCode;
|
|
55
|
+
reply.send({ error: e.message });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
reply.statusCode = 500;
|
|
59
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async updateValue(request, reply) {
|
|
64
|
+
try {
|
|
65
|
+
request.rbac.assertPermission(SettingPermissions.Update);
|
|
66
|
+
const id = request.params.id;
|
|
67
|
+
let { value } = request.body;
|
|
68
|
+
const setting = await this.service.updateValue(id, value);
|
|
69
|
+
return setting;
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.error(e);
|
|
73
|
+
if (e instanceof ValidationError) {
|
|
74
|
+
reply.statusCode = e.statusCode;
|
|
75
|
+
reply.send({ error: e.message, inputErrors: e.errors });
|
|
76
|
+
}
|
|
77
|
+
else if (e instanceof UnauthorizedError) {
|
|
78
|
+
reply.statusCode = e.statusCode;
|
|
79
|
+
reply.send({ error: e.message });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
reply.statusCode = 500;
|
|
83
|
+
reply.send({ error: 'INTERNAL_SERVER_ERROR' });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export default SettingController;
|
|
89
|
+
export { SettingController };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { COMMON, CommonConfig, DraxConfig } from "@drax/common-back";
|
|
2
|
+
import { SettingService } from "../services/SettingService.js";
|
|
3
|
+
import SettingMongoRepository from "../repository/mongo/SettingMongoRepository.js";
|
|
4
|
+
import SettingSqliteRepository from "../repository/sqlite/SettingSqliteRepository.js";
|
|
5
|
+
let settingService;
|
|
6
|
+
const SettingServiceFactory = (verbose = false) => {
|
|
7
|
+
if (!settingService) {
|
|
8
|
+
let settingRepository;
|
|
9
|
+
switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
|
|
10
|
+
case COMMON.DB_ENGINES.MONGODB:
|
|
11
|
+
settingRepository = new SettingMongoRepository();
|
|
12
|
+
break;
|
|
13
|
+
case COMMON.DB_ENGINES.SQLITE:
|
|
14
|
+
const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile);
|
|
15
|
+
settingRepository = new SettingSqliteRepository(dbFile, verbose);
|
|
16
|
+
break;
|
|
17
|
+
default:
|
|
18
|
+
throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
|
|
19
|
+
}
|
|
20
|
+
settingService = new SettingService(settingRepository);
|
|
21
|
+
}
|
|
22
|
+
return settingService;
|
|
23
|
+
};
|
|
24
|
+
export default SettingServiceFactory;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SettingModel, SettingSchema } from "./model/SettingsModel.js";
|
|
2
|
+
import { SettingMongoRepository } from "./repository/mongo/SettingMongoRepository.js";
|
|
3
|
+
import { SettingService } from "./services/SettingService.js";
|
|
4
|
+
import SettingServiceFactory from "./factory/SettingServiceFactory.js";
|
|
5
|
+
import SettingController from "./controller/SettingController.js";
|
|
6
|
+
import SettingRoutes from "./routes/SettingRoutes.js";
|
|
7
|
+
import { SettingPermissions } from "./permissions/SettingPermissions.js";
|
|
8
|
+
export { SettingSchema, SettingModel, SettingMongoRepository, SettingService, SettingServiceFactory, SettingController, SettingRoutes, SettingPermissions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { mongoose } from '@drax/common-back';
|
|
2
|
+
import uniqueValidator from 'mongoose-unique-validator';
|
|
3
|
+
const SettingSchema = new mongoose.Schema({
|
|
4
|
+
key: { type: String, required: true, unique: true },
|
|
5
|
+
value: { type: mongoose.Schema.Types.Mixed, required: false, unique: false },
|
|
6
|
+
//valueList: [{type: String, required: false, unique: false}],
|
|
7
|
+
label: { type: String, required: false },
|
|
8
|
+
group: { type: String, required: true },
|
|
9
|
+
type: { type: String, default: "string", enum: ['string', 'longString', 'number', 'enum', 'boolean', 'password', 'stringList', 'numberList', 'enumList', 'ref', 'secret'], required: false, unique: false },
|
|
10
|
+
options: [{ type: String }],
|
|
11
|
+
regex: { type: String },
|
|
12
|
+
entity: { type: String, required: false },
|
|
13
|
+
entityValue: { type: String, required: false },
|
|
14
|
+
entityText: { type: String, required: false, unique: false },
|
|
15
|
+
prefix: { type: String, required: false },
|
|
16
|
+
suffix: { type: String, required: false },
|
|
17
|
+
});
|
|
18
|
+
SettingSchema.virtual("id").get(function () {
|
|
19
|
+
return this._id.toString();
|
|
20
|
+
});
|
|
21
|
+
SettingSchema.set('toJSON', { getters: true, virtuals: true });
|
|
22
|
+
SettingSchema.set('toObject', { getters: true, virtuals: true });
|
|
23
|
+
SettingSchema.plugin(uniqueValidator, { message: 'validation.unique' });
|
|
24
|
+
const MODEL_NAME = 'Setting';
|
|
25
|
+
const COLLECTION_NAME = 'settings';
|
|
26
|
+
const SettingModel = mongoose.model(MODEL_NAME, SettingSchema, COLLECTION_NAME);
|
|
27
|
+
export { SettingSchema, SettingModel };
|
|
28
|
+
export default SettingModel;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var SettingPermissions;
|
|
2
|
+
(function (SettingPermissions) {
|
|
3
|
+
SettingPermissions["Update"] = "setting:update";
|
|
4
|
+
SettingPermissions["View"] = "setting:view";
|
|
5
|
+
SettingPermissions["Manage"] = "setting:manage";
|
|
6
|
+
})(SettingPermissions || (SettingPermissions = {}));
|
|
7
|
+
export default SettingPermissions;
|
|
8
|
+
export { SettingPermissions };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AbstractMongoRepository } from "@drax/crud-back";
|
|
2
|
+
import { SettingModel } from "../../model/SettingsModel.js";
|
|
3
|
+
class SettingMongoRepository extends AbstractMongoRepository {
|
|
4
|
+
constructor() {
|
|
5
|
+
super();
|
|
6
|
+
//@ts-ignore
|
|
7
|
+
this._model = SettingModel;
|
|
8
|
+
this._searchFields = ['_id', 'key'];
|
|
9
|
+
this._populateFields = [];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default SettingMongoRepository;
|
|
13
|
+
export { SettingMongoRepository };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import sqlite from "better-sqlite3";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { SqliteErrorToValidationError, SqliteTableBuilder, SqlQueryFilter, SqlSort } from "@drax/common-back";
|
|
4
|
+
const tableFields = [
|
|
5
|
+
{ name: "key", type: "TEXT", unique: true, primary: false },
|
|
6
|
+
{ name: "value", type: "TEXT", unique: false, primary: false },
|
|
7
|
+
];
|
|
8
|
+
class SettingSqliteRepository {
|
|
9
|
+
constructor(dataBaseFile, verbose = false) {
|
|
10
|
+
this._searchFields = [];
|
|
11
|
+
this.dataBaseFile = dataBaseFile;
|
|
12
|
+
this._searchFields = ['_id', 'key'];
|
|
13
|
+
this.db = new sqlite(dataBaseFile, { verbose: verbose ? console.log : null });
|
|
14
|
+
this.table();
|
|
15
|
+
}
|
|
16
|
+
table() {
|
|
17
|
+
const builder = new SqliteTableBuilder(this.dataBaseFile, 'settings', tableFields, false);
|
|
18
|
+
builder.build('id');
|
|
19
|
+
}
|
|
20
|
+
async create(data) {
|
|
21
|
+
try {
|
|
22
|
+
if (!data.id) {
|
|
23
|
+
data.id = randomUUID();
|
|
24
|
+
}
|
|
25
|
+
// data.createdAt = (new Date().toISOString())
|
|
26
|
+
const fields = Object.keys(data)
|
|
27
|
+
.map(field => `${field}`)
|
|
28
|
+
.join(', ');
|
|
29
|
+
const values = Object.keys(data)
|
|
30
|
+
.map(field => `@${field}`)
|
|
31
|
+
.join(', ');
|
|
32
|
+
const stmt = this.db.prepare(`INSERT INTO settings (${fields}) VALUES (${values})`);
|
|
33
|
+
stmt.run(data);
|
|
34
|
+
return this.findById(data.id);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
console.log(e);
|
|
38
|
+
throw SqliteErrorToValidationError(e, data);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async update(id, data) {
|
|
42
|
+
try {
|
|
43
|
+
// data.updatedAt = (new Date().toISOString())
|
|
44
|
+
const setClauses = Object.keys(data)
|
|
45
|
+
.map(field => `${field} = @${field}`)
|
|
46
|
+
.join(', ');
|
|
47
|
+
data.id = id;
|
|
48
|
+
const stmt = this.db.prepare(`UPDATE settings SET ${setClauses} WHERE id = @id `);
|
|
49
|
+
stmt.run(data);
|
|
50
|
+
return this.findById(id);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
console.log(e);
|
|
54
|
+
throw SqliteErrorToValidationError(e, data);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async paginate({ page = 1, limit = 5, orderBy = '', order = false, search = '', filters = [] }) {
|
|
58
|
+
const offset = page > 1 ? (page - 1) * limit : 0;
|
|
59
|
+
let where = "";
|
|
60
|
+
if (search) {
|
|
61
|
+
where = ` WHERE name LIKE '%${search}%'`;
|
|
62
|
+
}
|
|
63
|
+
where = SqlQueryFilter.applyFilters(where, filters);
|
|
64
|
+
const sort = SqlSort.applySort(orderBy, order);
|
|
65
|
+
const rCount = this.db.prepare('SELECT COUNT(*) as count FROM settings' + where).get();
|
|
66
|
+
where += sort;
|
|
67
|
+
const settings = this.db.prepare('SELECT * FROM settings ' + where + ' LIMIT ? OFFSET ?').all([limit, offset]);
|
|
68
|
+
return {
|
|
69
|
+
page: page,
|
|
70
|
+
limit: limit,
|
|
71
|
+
total: rCount.count,
|
|
72
|
+
items: settings
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async delete(id) {
|
|
76
|
+
const stmt = this.db.prepare('DELETE FROM settings WHERE id = ?');
|
|
77
|
+
stmt.run(id);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
async deleteAll() {
|
|
81
|
+
const stmt = this.db.prepare('DELETE FROM settings');
|
|
82
|
+
stmt.run();
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
async findById(id) {
|
|
86
|
+
const setting = this.db.prepare('SELECT * FROM settings WHERE id = ?').get(id);
|
|
87
|
+
if (setting) {
|
|
88
|
+
return setting;
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
async findByKey(key) {
|
|
93
|
+
const setting = this.db.prepare('SELECT * FROM settings WHERE key = ?').get(key);
|
|
94
|
+
if (setting) {
|
|
95
|
+
return setting;
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
async fetchAll() {
|
|
100
|
+
const settings = this.db.prepare('SELECT * FROM settings').all();
|
|
101
|
+
return settings;
|
|
102
|
+
}
|
|
103
|
+
async search(value, limit = 1000) {
|
|
104
|
+
let where = "";
|
|
105
|
+
if (value && this._searchFields.length > 0) {
|
|
106
|
+
where = ` WHERE ${this._searchFields.map(field => `${field} LIKE '%${value}%'`).join(" OR ")}`;
|
|
107
|
+
}
|
|
108
|
+
const items = this.db.prepare(`SELECT * FROM settings ${where}`).all();
|
|
109
|
+
return items;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export default SettingSqliteRepository;
|
|
113
|
+
export { SettingSqliteRepository };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import SettingController from "../controller/SettingController.js";
|
|
2
|
+
async function SettingsRoutes(fastify, options) {
|
|
3
|
+
const controller = new SettingController();
|
|
4
|
+
fastify.get('/api/settings', (req, rep) => controller.fetchAll(req, rep));
|
|
5
|
+
fastify.get('/api/settings/grouped', (req, rep) => controller.fetchGrouped(req, rep));
|
|
6
|
+
fastify.get('/api/settings/:key', (req, rep) => controller.findByKey(req, rep));
|
|
7
|
+
fastify.patch('/api/settings/:id', (req, rep) => controller.updateValue(req, rep));
|
|
8
|
+
}
|
|
9
|
+
export default SettingsRoutes;
|
|
10
|
+
export { SettingsRoutes };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { settingSchema } from "../schemas/SettingSchema.js";
|
|
2
|
+
import { AbstractService } from "@drax/crud-back";
|
|
3
|
+
import { DraxCache, ZodErrorToValidationError } from "@drax/common-back";
|
|
4
|
+
import { ZodError } from "zod";
|
|
5
|
+
class SettingService extends AbstractService {
|
|
6
|
+
constructor(repostitory) {
|
|
7
|
+
super(repostitory, settingSchema);
|
|
8
|
+
this._cache = new DraxCache();
|
|
9
|
+
this._repository = repostitory;
|
|
10
|
+
console.log("SettingService constructor");
|
|
11
|
+
}
|
|
12
|
+
async cache(key) {
|
|
13
|
+
return this._cache.getOrLoad(key, async () => {
|
|
14
|
+
return await this.findByKey(key);
|
|
15
|
+
}, 20000);
|
|
16
|
+
}
|
|
17
|
+
async cacheValue(key) {
|
|
18
|
+
let setting = await this.cache(key);
|
|
19
|
+
return setting?.value;
|
|
20
|
+
}
|
|
21
|
+
async findByKey(key) {
|
|
22
|
+
return this._repository.findOneBy("key", key);
|
|
23
|
+
}
|
|
24
|
+
async fetchAll() {
|
|
25
|
+
return await this._repository.fetchAll();
|
|
26
|
+
}
|
|
27
|
+
async fetchGrouped() {
|
|
28
|
+
const settings = await this._repository.fetchAll();
|
|
29
|
+
return settings.reduce((acc, setting) => {
|
|
30
|
+
if (!acc[setting.group]) {
|
|
31
|
+
acc[setting.group] = [];
|
|
32
|
+
}
|
|
33
|
+
acc[setting.group].push(setting);
|
|
34
|
+
return acc;
|
|
35
|
+
}, {});
|
|
36
|
+
}
|
|
37
|
+
async updateValue(id, value) {
|
|
38
|
+
return this._repository.updatePartial(id, { value });
|
|
39
|
+
}
|
|
40
|
+
async create(data) {
|
|
41
|
+
try {
|
|
42
|
+
await settingSchema.parseAsync(data);
|
|
43
|
+
if (Array.isArray(data.value)) {
|
|
44
|
+
data.value = JSON.stringify(data.value);
|
|
45
|
+
}
|
|
46
|
+
const setting = await this._repository.create(data);
|
|
47
|
+
return setting;
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
console.error("Error on create setting", e);
|
|
51
|
+
if (e instanceof ZodError) {
|
|
52
|
+
throw ZodErrorToValidationError(e, data);
|
|
53
|
+
}
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async update(id, data) {
|
|
58
|
+
try {
|
|
59
|
+
await settingSchema.parseAsync(data);
|
|
60
|
+
//Borramos el valor para evitar el conflicto de actualización
|
|
61
|
+
delete data.value;
|
|
62
|
+
const setting = await this._repository.update(id, data);
|
|
63
|
+
return setting;
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.error("Error on update setting", e);
|
|
67
|
+
if (e instanceof ZodError) {
|
|
68
|
+
throw ZodErrorToValidationError(e, data);
|
|
69
|
+
}
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async createOrUpdate(data) {
|
|
74
|
+
try {
|
|
75
|
+
await settingSchema.parseAsync(data);
|
|
76
|
+
const setting = await this._repository.findOneBy("key", data.key);
|
|
77
|
+
if (setting) {
|
|
78
|
+
delete data.value;
|
|
79
|
+
return await this._repository.updatePartial(setting.id, data);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return await this._repository.create(data);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
console.error("Error on create or update setting", e);
|
|
87
|
+
if (e instanceof ZodError) {
|
|
88
|
+
throw ZodErrorToValidationError(e, data);
|
|
89
|
+
}
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export default SettingService;
|
|
95
|
+
export { SettingService };
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drax/settings-back",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "0.11.3",
|
|
7
|
+
"description": "Setting module for nice management options.",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "types/index.d.ts",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"prepublish": "tsc && npm run copygql",
|
|
13
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"copygql": "copyfiles -u 1 ./**/*.graphql dist/",
|
|
15
|
+
"tsc": "tsc -b tsconfig.json",
|
|
16
|
+
"tsclistFiles": "tsc --listFiles",
|
|
17
|
+
"tscexplain": "tsc --explainFiles",
|
|
18
|
+
"test": "node --import tsx --test test/**/*",
|
|
19
|
+
"testMongoRepositoryRole": "node --import tsx --test test/repository/mongo/role*",
|
|
20
|
+
"testMongoRepositoryUser": "node --import tsx --test test/repository/mongo/user-mongo*",
|
|
21
|
+
"testMongoRepositoryUserApiKey": "node --import tsx --test test/repository/mongo/user-apikey-mongo*",
|
|
22
|
+
"testSqliteRepositoryUser": "node --import tsx --test test/repository/sqlite/user*",
|
|
23
|
+
"testSqliteRepositoryRole": "node --import tsx --test test/repository/sqlite/role*",
|
|
24
|
+
"testServiceRole": "node --import tsx --test test/service/role*",
|
|
25
|
+
"testServiceUser": "node --import tsx --test test/service/user*",
|
|
26
|
+
"testcoverage": "node --import tsx --experimental-test-coverage test/service/*"
|
|
27
|
+
},
|
|
28
|
+
"author": "Cristian Incarnato & Drax Team",
|
|
29
|
+
"license": "ISC",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@drax/common-back": "^0.11.3",
|
|
32
|
+
"@drax/crud-back": "^0.11.3",
|
|
33
|
+
"@drax/crud-share": "^0.11.3",
|
|
34
|
+
"@drax/email-back": "^0.11.3",
|
|
35
|
+
"@drax/identity-share": "^0.11.3",
|
|
36
|
+
"bcryptjs": "^2.4.3",
|
|
37
|
+
"express-jwt": "^8.4.1",
|
|
38
|
+
"graphql": "^16.8.2",
|
|
39
|
+
"jsonwebtoken": "^9.0.2",
|
|
40
|
+
"zod": "^3.23.8"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"better-sqlite3": "^11.0.0",
|
|
44
|
+
"fastify": "^4.27.0",
|
|
45
|
+
"mongoose": "^8.6.3",
|
|
46
|
+
"mongoose-paginate-v2": "^1.8.3",
|
|
47
|
+
"mongoose-unique-validator": "^5.0.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/bcryptjs": "^2.4.6",
|
|
51
|
+
"@types/node": "^20.12.10",
|
|
52
|
+
"copyfiles": "^2.4.1",
|
|
53
|
+
"glob": "^10.2.6",
|
|
54
|
+
"mongodb-memory-server": "^9.2.0",
|
|
55
|
+
"nodemon": "^3.1.0",
|
|
56
|
+
"ts-node": "^10.9.2",
|
|
57
|
+
"tsc-alias": "^1.8.10",
|
|
58
|
+
"typescript": "^5.4.5"
|
|
59
|
+
},
|
|
60
|
+
"config": {
|
|
61
|
+
"mongodbMemoryServer": {
|
|
62
|
+
"debug": "0"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"gitHead": "54216d94d68dac488969f9c95d3c6be780935f9d"
|
|
66
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {SettingPermissions} from "../permissions/SettingPermissions.js";
|
|
2
|
+
import SettingService from "../services/SettingService.js";
|
|
3
|
+
import SettingServiceFactory from "../factory/SettingServiceFactory.js";
|
|
4
|
+
import {UnauthorizedError, ValidationError} from "@drax/common-back";
|
|
5
|
+
|
|
6
|
+
class SettingController {
|
|
7
|
+
|
|
8
|
+
protected service: SettingService
|
|
9
|
+
protected permission
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
this.service = SettingServiceFactory()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async fetchAll(request, reply) {
|
|
16
|
+
try {
|
|
17
|
+
request.rbac.assertPermission(SettingPermissions.View)
|
|
18
|
+
const settings = await this.service.fetchAll()
|
|
19
|
+
return settings
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error(e)
|
|
22
|
+
if (e instanceof UnauthorizedError) {
|
|
23
|
+
reply.statusCode = e.statusCode
|
|
24
|
+
reply.send({error: e.message})
|
|
25
|
+
} else {
|
|
26
|
+
reply.statusCode = 500
|
|
27
|
+
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async fetchGrouped(request, reply) {
|
|
33
|
+
try {
|
|
34
|
+
request.rbac.assertPermission(SettingPermissions.View)
|
|
35
|
+
const settings = await this.service.fetchGrouped()
|
|
36
|
+
return settings
|
|
37
|
+
} catch (e) {
|
|
38
|
+
console.error(e)
|
|
39
|
+
if (e instanceof UnauthorizedError) {
|
|
40
|
+
reply.statusCode = e.statusCode
|
|
41
|
+
reply.send({error: e.message})
|
|
42
|
+
} else {
|
|
43
|
+
reply.statusCode = 500
|
|
44
|
+
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async findByKey(request, reply) {
|
|
50
|
+
try {
|
|
51
|
+
request.rbac.assertPermission(SettingPermissions.View)
|
|
52
|
+
const key = request.params.key
|
|
53
|
+
const setting = await this.service.findByKey(key)
|
|
54
|
+
return setting
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error(e)
|
|
57
|
+
if (e instanceof UnauthorizedError) {
|
|
58
|
+
reply.statusCode = e.statusCode
|
|
59
|
+
reply.send({error: e.message})
|
|
60
|
+
} else {
|
|
61
|
+
reply.statusCode = 500
|
|
62
|
+
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async updateValue(request, reply) {
|
|
68
|
+
try {
|
|
69
|
+
request.rbac.assertPermission(SettingPermissions.Update)
|
|
70
|
+
const id = request.params.id
|
|
71
|
+
let {value} = request.body
|
|
72
|
+
const setting = await this.service.updateValue(id, value)
|
|
73
|
+
return setting
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.error(e)
|
|
76
|
+
if (e instanceof ValidationError) {
|
|
77
|
+
reply.statusCode = e.statusCode
|
|
78
|
+
reply.send({error: e.message, inputErrors: e.errors})
|
|
79
|
+
} else if (e instanceof UnauthorizedError) {
|
|
80
|
+
reply.statusCode = e.statusCode
|
|
81
|
+
reply.send({error: e.message})
|
|
82
|
+
} else {
|
|
83
|
+
reply.statusCode = 500
|
|
84
|
+
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
export default SettingController;
|
|
92
|
+
export {SettingController}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {COMMON, CommonConfig, DraxConfig} from "@drax/common-back"
|
|
2
|
+
import {SettingService} from "../services/SettingService.js";
|
|
3
|
+
import SettingMongoRepository from "../repository/mongo/SettingMongoRepository.js";
|
|
4
|
+
import SettingSqliteRepository from "../repository/sqlite/SettingSqliteRepository.js";
|
|
5
|
+
import type {ISettingRepository} from "../interfaces/ISettingRepository";
|
|
6
|
+
|
|
7
|
+
let settingService: SettingService
|
|
8
|
+
|
|
9
|
+
const SettingServiceFactory = (verbose: boolean = false): SettingService => {
|
|
10
|
+
|
|
11
|
+
if (!settingService) {
|
|
12
|
+
let settingRepository: ISettingRepository
|
|
13
|
+
|
|
14
|
+
switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
|
|
15
|
+
case COMMON.DB_ENGINES.MONGODB:
|
|
16
|
+
settingRepository = new SettingMongoRepository()
|
|
17
|
+
break;
|
|
18
|
+
case COMMON.DB_ENGINES.SQLITE:
|
|
19
|
+
const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
|
|
20
|
+
settingRepository = new SettingSqliteRepository(dbFile, verbose)
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
settingService = new SettingService(settingRepository)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return settingService
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default SettingServiceFactory
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {ISettingRepository} from "./interfaces/ISettingRepository";
|
|
2
|
+
export type {ISettingRepository};
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import {SettingModel, SettingSchema} from "./model/SettingsModel.js"
|
|
6
|
+
import {SettingMongoRepository} from "./repository/mongo/SettingMongoRepository.js"
|
|
7
|
+
import {SettingService} from "./services/SettingService.js"
|
|
8
|
+
import SettingServiceFactory from "./factory/SettingServiceFactory.js"
|
|
9
|
+
import SettingController from "./controller/SettingController.js"
|
|
10
|
+
import SettingRoutes from "./routes/SettingRoutes.js"
|
|
11
|
+
import {SettingPermissions} from "./permissions/SettingPermissions.js"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
SettingSchema,
|
|
17
|
+
SettingModel,
|
|
18
|
+
SettingMongoRepository,
|
|
19
|
+
SettingService,
|
|
20
|
+
SettingServiceFactory,
|
|
21
|
+
SettingController,
|
|
22
|
+
SettingRoutes,
|
|
23
|
+
SettingPermissions
|
|
24
|
+
}
|