@ecopex/ecopex-framework 1.0.9 → 1.0.12
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/config/swagger.js +4 -3
- package/index.js +1 -1
- package/libraries/controls.js +9 -1
- package/libraries/fastify.js +22 -13
- package/libraries/knex.js +8 -5
- package/package.json +1 -1
- package/routes/auto/handler.js +71 -67
- package/stores/base.js +2 -2
- package/stores/config.js +8 -3
- package/utils/jsonRouteLoader.js +50 -35
- package/utils/middleware.js +6 -9
- package/utils/routeLoader.js +50 -26
package/config/swagger.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Swagger configuration for Admin service
|
|
3
3
|
*/
|
|
4
4
|
const { config } = require('../stores/config');
|
|
5
|
+
|
|
5
6
|
module.exports = {
|
|
6
7
|
swagger: {
|
|
7
8
|
openapi: {
|
|
8
9
|
info: {
|
|
9
|
-
title: config.name + ' API',
|
|
10
|
-
description: config.name + ' API
|
|
10
|
+
title: (config.name || '').toUpperCase() + ' API',
|
|
11
|
+
description: (config.name || '').toUpperCase() + ' API DOCUMENTATION',
|
|
11
12
|
version: '1.0.0'
|
|
12
13
|
},
|
|
13
14
|
host: `${config.host || 'localhost'}:${config.port || 3001}`,
|
|
@@ -40,6 +41,6 @@ module.exports = {
|
|
|
40
41
|
}
|
|
41
42
|
},
|
|
42
43
|
swaggerUi: {
|
|
43
|
-
routePrefix: '/
|
|
44
|
+
routePrefix: '/'
|
|
44
45
|
}
|
|
45
46
|
};
|
package/index.js
CHANGED
package/libraries/controls.js
CHANGED
|
@@ -98,6 +98,13 @@ const ipcheck = (req, whitelists = '') => {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
const toTitleCase = (str = '') => {
|
|
102
|
+
return str.replace(
|
|
103
|
+
/\w\S*/g,
|
|
104
|
+
text => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase()
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
101
108
|
module.exports = {
|
|
102
109
|
emailValidation,
|
|
103
110
|
phoneValidation,
|
|
@@ -109,5 +116,6 @@ module.exports = {
|
|
|
109
116
|
checkPassoword,
|
|
110
117
|
ipcheck,
|
|
111
118
|
sleep,
|
|
112
|
-
roundTo
|
|
119
|
+
roundTo,
|
|
120
|
+
toTitleCase
|
|
113
121
|
}
|
package/libraries/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { loadRoutes } = require('../utils/routeLoader');
|
|
2
2
|
const Middleware = require('../utils/middleware');
|
|
3
|
-
const { setConfig } = require('../stores/config');
|
|
3
|
+
const { setConfig, config: configStore } = require('../stores/config');
|
|
4
4
|
|
|
5
5
|
let fastifyInstance = null;
|
|
6
6
|
|
|
@@ -15,8 +15,8 @@ async function registerPlugins(config) {
|
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
// Set error handler first, before any plugins
|
|
18
|
-
fastifyInstance.setErrorHandler(Middleware.errorHandler);
|
|
19
|
-
fastifyInstance.setNotFoundHandler(Middleware.errorNotFoundHandler);
|
|
18
|
+
fastifyInstance.setErrorHandler((error, request, reply) => Middleware.errorHandler(error, request, reply, config));
|
|
19
|
+
fastifyInstance.setNotFoundHandler((request, reply) => Middleware.errorNotFoundHandler(request, reply));
|
|
20
20
|
|
|
21
21
|
// CORS plugin
|
|
22
22
|
await fastifyInstance.register(require('@fastify/cors'), {
|
|
@@ -52,14 +52,23 @@ async function registerPlugins(config) {
|
|
|
52
52
|
fastifyInstance.addHook('preHandler', Middleware.responseFormatter());
|
|
53
53
|
|
|
54
54
|
// Health check endpoint
|
|
55
|
-
fastifyInstance.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
55
|
+
fastifyInstance.route({
|
|
56
|
+
method: 'GET',
|
|
57
|
+
url: '/' + (configStore.prefix ? configStore.prefix + '/' : '') + 'health',
|
|
58
|
+
schema: {
|
|
59
|
+
description: 'Health check',
|
|
60
|
+
summary: 'Health check',
|
|
61
|
+
tags: ['Global Services']
|
|
62
|
+
},
|
|
63
|
+
handler: async (request, reply) => {
|
|
64
|
+
return {
|
|
65
|
+
status: 'ok',
|
|
66
|
+
service: config.name,
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
uptime: process.uptime(),
|
|
69
|
+
pid: process.pid
|
|
70
|
+
};
|
|
71
|
+
}
|
|
63
72
|
});
|
|
64
73
|
|
|
65
74
|
return fastifyInstance;
|
|
@@ -70,7 +79,7 @@ async function loadAdminRoutes(config) {
|
|
|
70
79
|
try {
|
|
71
80
|
// Load admin routes
|
|
72
81
|
if(fastifyInstance) {
|
|
73
|
-
await loadRoutes(fastifyInstance, './routes/' + config.name,
|
|
82
|
+
await loadRoutes(fastifyInstance, './routes/' + config.name, config.common || false, config.name);
|
|
74
83
|
}
|
|
75
84
|
} catch (error) {
|
|
76
85
|
console.error('Error loading admin routes:', error);
|
|
@@ -83,7 +92,7 @@ async function start(config) {
|
|
|
83
92
|
try {
|
|
84
93
|
|
|
85
94
|
setConfig(config);
|
|
86
|
-
|
|
95
|
+
|
|
87
96
|
// Register plugins
|
|
88
97
|
await registerPlugins(config);
|
|
89
98
|
|
package/libraries/knex.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const knex = require('knex');
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const connection = {
|
|
4
|
+
db: null
|
|
5
|
+
}
|
|
4
6
|
|
|
5
|
-
const initialize = async (
|
|
6
|
-
const { config: configStore } = require('../stores/config');
|
|
7
|
+
const initialize = async (configStore) => {
|
|
7
8
|
const databaseConfig = configStore?.database || {};
|
|
8
9
|
|
|
9
10
|
const db_config = {
|
|
@@ -30,10 +31,12 @@ const initialize = async (config) => {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const db = knex(db_config[configStore.development ? 'development' : 'production']);
|
|
33
|
-
|
|
34
|
+
connection.db = db;
|
|
35
|
+
|
|
36
|
+
return connection.db;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
module.exports = {
|
|
37
40
|
initialize,
|
|
38
|
-
|
|
41
|
+
connection
|
|
39
42
|
}
|
package/package.json
CHANGED
package/routes/auto/handler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const knex = require('../../libraries/knex');
|
|
2
2
|
const BCRYPT = require('../../libraries/bcrypt');
|
|
3
3
|
const bcrypt = new BCRYPT();
|
|
4
4
|
const i18n = require('../../utils/i18n');
|
|
@@ -26,11 +26,12 @@ async function getAll(request, reply, routeOptions = {}) {
|
|
|
26
26
|
const routeConfig = routeOptions.routeConfig || {};
|
|
27
27
|
const primaryKey = routeOptions.primaryKey || 'id';
|
|
28
28
|
const filters = routeOptions.filters || {};
|
|
29
|
+
const joinTables = routeOptions.joinTables || {};
|
|
29
30
|
const splitOrder = order.split(':');
|
|
30
31
|
const orderBy = `${tableName}.${(splitOrder[0] || primaryKey)}`;
|
|
31
32
|
const orderDirection = splitOrder[1] || 'desc';
|
|
32
33
|
|
|
33
|
-
let query = db
|
|
34
|
+
let query = knex.connection.db(tableName + ' as ' + tableName).select(`${tableName}.*`);
|
|
34
35
|
|
|
35
36
|
// Apply search filter if provided
|
|
36
37
|
if (search && routeConfig.searchable_fields) {
|
|
@@ -49,18 +50,18 @@ async function getAll(request, reply, routeOptions = {}) {
|
|
|
49
50
|
query.where(routeConfig.owned, request.user?.id || 0);
|
|
50
51
|
query.where(routeConfig.owned_type, request.user?.type || 'user');
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
-
if(
|
|
54
|
-
for(let i = 0; i < Object.values(
|
|
55
|
-
const tableKey = Object.keys(
|
|
56
|
-
let joinTable = Object.values(
|
|
53
|
+
|
|
54
|
+
if(joinTables) {
|
|
55
|
+
for(let i = 0; i < Object.values(joinTables).length; i++) {
|
|
56
|
+
const tableKey = Object.keys(joinTables)[i];
|
|
57
|
+
let joinTable = Object.values(joinTables)[i];
|
|
57
58
|
if(joinTable.type == 'one-to-one') {
|
|
58
59
|
if(joinTable.extra_where) {
|
|
59
60
|
query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key} = ${tableKey}.${joinTable.primary_key} AND ${joinTable.extra_where}`);
|
|
60
61
|
} else {
|
|
61
62
|
query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key}`, `${tableKey}.${joinTable.primary_key}`);
|
|
62
63
|
}
|
|
63
|
-
query.select(`${tableKey}
|
|
64
|
+
query.select(knex.connection.db.raw(Object.entries(joinTable.properties || {}).map(n => `${tableKey}.${n[0]} as ${n[0]}`).join(', ')));
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -107,14 +108,11 @@ async function getAll(request, reply, routeOptions = {}) {
|
|
|
107
108
|
|
|
108
109
|
const total = parseInt(count);
|
|
109
110
|
|
|
110
|
-
const rows = structureRows(items, tableName,
|
|
111
|
+
const rows = structureRows(items, tableName, joinTables)
|
|
111
112
|
|
|
112
113
|
// Process join tables if configured
|
|
113
|
-
const processedItems = await processJoinTables(rows,
|
|
114
|
+
const processedItems = await processJoinTables(rows, joinTables);
|
|
114
115
|
|
|
115
|
-
// console.log(processedItems);
|
|
116
|
-
|
|
117
|
-
|
|
118
116
|
const totalPages = Math.ceil(total / limit);
|
|
119
117
|
|
|
120
118
|
return reply.send({
|
|
@@ -143,33 +141,30 @@ async function getAll(request, reply, routeOptions = {}) {
|
|
|
143
141
|
* @param {Object} routeOptions - The route options
|
|
144
142
|
* @returns {Promise<Object>} - The response object
|
|
145
143
|
*/
|
|
146
|
-
async function getById(request, reply, routeOptions = {}) {
|
|
144
|
+
async function getById(request, reply, routeOptions = {}, inner = false) {
|
|
147
145
|
|
|
148
146
|
if(routeOptions.store) {
|
|
149
147
|
return get_by_primary_key(routeOptions.store, request.params[routeOptions.primaryKey], reply, routeOptions);
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
try {
|
|
153
|
-
const primaryKey = routeOptions.primaryKey || 'id';
|
|
154
|
-
const { [primaryKey]: id } = request.params;
|
|
155
151
|
const tableName = routeOptions.tableName || 'users';
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
const item_query = db.instance(tableName)
|
|
152
|
+
const joinTables = routeOptions.joinTables || {};
|
|
153
|
+
const item_query = knex.connection.db(tableName)
|
|
159
154
|
.select(`${tableName}.*`)
|
|
160
|
-
.where(
|
|
161
|
-
|
|
162
|
-
if(
|
|
163
|
-
for(let i = 0; i < Object.values(
|
|
164
|
-
const tableKey = Object.keys(
|
|
165
|
-
let joinTable = Object.values(
|
|
155
|
+
.where(request.params);
|
|
156
|
+
|
|
157
|
+
if(joinTables) {
|
|
158
|
+
for(let i = 0; i < Object.values(joinTables).length; i++) {
|
|
159
|
+
const tableKey = Object.keys(joinTables)[i];
|
|
160
|
+
let joinTable = Object.values(joinTables)[i];
|
|
166
161
|
if(joinTable.type == 'one-to-one') {
|
|
167
162
|
if(joinTable.extra_where) {
|
|
168
163
|
item_query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key} = ${tableKey}.${joinTable.primary_key} AND ${joinTable.extra_where}`);
|
|
169
164
|
} else {
|
|
170
165
|
item_query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key}`, `${tableKey}.${joinTable.primary_key}`);
|
|
171
166
|
}
|
|
172
|
-
item_query.select(`${tableKey}
|
|
167
|
+
item_query.select(knex.connection.db.raw(Object.entries(joinTable.properties || {}).map(n => `${tableKey}.${n[0]} as ${n[0]}`).join(', ')));
|
|
173
168
|
}
|
|
174
169
|
}
|
|
175
170
|
|
|
@@ -177,16 +172,15 @@ async function getById(request, reply, routeOptions = {}) {
|
|
|
177
172
|
}
|
|
178
173
|
|
|
179
174
|
const item_data = await item_query.first();
|
|
180
|
-
console.log(item_data);
|
|
181
175
|
|
|
182
176
|
let item = {}
|
|
183
177
|
|
|
184
178
|
|
|
185
|
-
if(
|
|
179
|
+
if(joinTables) {
|
|
186
180
|
item = {
|
|
187
181
|
...item_data[tableName],
|
|
188
182
|
}
|
|
189
|
-
const join_one_to_one = Object.entries(
|
|
183
|
+
const join_one_to_one = Object.entries(joinTables).filter(n => n[1].type === 'one-to-one');
|
|
190
184
|
if(join_one_to_one.length > 0) {
|
|
191
185
|
for(let i = 0; i < join_one_to_one.length; i++) {
|
|
192
186
|
const join_table = join_one_to_one[i];
|
|
@@ -198,26 +192,44 @@ async function getById(request, reply, routeOptions = {}) {
|
|
|
198
192
|
}
|
|
199
193
|
|
|
200
194
|
if (!item) {
|
|
201
|
-
|
|
202
|
-
status
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
if(!inner) {
|
|
196
|
+
return reply.status(404).send({
|
|
197
|
+
status: false,
|
|
198
|
+
message: request.t('messages.record_not_found')
|
|
199
|
+
});
|
|
200
|
+
} else {
|
|
201
|
+
return {
|
|
202
|
+
status: false,
|
|
203
|
+
message: request.t('messages.record_not_found')
|
|
204
|
+
};
|
|
205
|
+
}
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
// Process join tables if configured
|
|
208
|
-
const processedItem = await processJoinTables([item],
|
|
209
|
+
const processedItem = await processJoinTables([item], joinTables);
|
|
209
210
|
const result = processedItem[0];
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
if(!inner) {
|
|
213
|
+
return reply.send({
|
|
214
|
+
status: true,
|
|
215
|
+
data: result
|
|
216
|
+
});
|
|
217
|
+
} else {
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
215
220
|
} catch (error) {
|
|
216
221
|
console.error('Error getting record by ID:', error);
|
|
217
|
-
|
|
218
|
-
status
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
if(!inner) {
|
|
223
|
+
return reply.status(500).send({
|
|
224
|
+
status: false,
|
|
225
|
+
message: request.t('messages.internal_server_error')
|
|
226
|
+
});
|
|
227
|
+
} else {
|
|
228
|
+
return {
|
|
229
|
+
status: false,
|
|
230
|
+
message: request.t('messages.internal_server_error')
|
|
231
|
+
};
|
|
232
|
+
}
|
|
221
233
|
}
|
|
222
234
|
}
|
|
223
235
|
|
|
@@ -237,7 +249,6 @@ async function create(request, reply, routeOptions = {}) {
|
|
|
237
249
|
try {
|
|
238
250
|
const tableName = routeOptions.tableName || 'users';
|
|
239
251
|
const primaryKey = routeOptions.primaryKey || 'id';
|
|
240
|
-
const routeConfig = routeOptions.routeConfig || {};
|
|
241
252
|
const schema = routeOptions.schema || {};
|
|
242
253
|
|
|
243
254
|
// Use payload field if available, otherwise use request.body directly
|
|
@@ -259,18 +270,14 @@ async function create(request, reply, routeOptions = {}) {
|
|
|
259
270
|
}
|
|
260
271
|
}
|
|
261
272
|
}
|
|
262
|
-
|
|
273
|
+
|
|
263
274
|
try {
|
|
264
|
-
const [id] = await db
|
|
275
|
+
const [id] = await knex.connection.db(tableName)
|
|
265
276
|
.insert({
|
|
266
|
-
...data
|
|
267
|
-
created_at: new Date(),
|
|
268
|
-
updated_at: new Date()
|
|
277
|
+
...data
|
|
269
278
|
});
|
|
270
279
|
|
|
271
|
-
const item = await
|
|
272
|
-
.where(primaryKey, id)
|
|
273
|
-
.first();
|
|
280
|
+
const item = await getById({ ...request, params: { [primaryKey]: id } }, {}, { ...routeOptions, primaryKey: primaryKey }, true)
|
|
274
281
|
|
|
275
282
|
return reply.send({
|
|
276
283
|
status: true,
|
|
@@ -314,8 +321,8 @@ async function update(request, reply, routeOptions = {}) {
|
|
|
314
321
|
try {
|
|
315
322
|
const tableName = routeOptions.tableName || 'users';
|
|
316
323
|
const primaryKey = routeOptions.primaryKey || 'id';
|
|
317
|
-
const routeConfig = routeOptions.routeConfig || {};
|
|
318
324
|
const schema = routeOptions.schema || {};
|
|
325
|
+
const routeConfig = routeOptions.routeConfig || {};
|
|
319
326
|
|
|
320
327
|
// Use payload field if available, otherwise use request.body directly
|
|
321
328
|
let data = request.body;
|
|
@@ -345,7 +352,7 @@ async function update(request, reply, routeOptions = {}) {
|
|
|
345
352
|
|
|
346
353
|
|
|
347
354
|
// Check if record exists
|
|
348
|
-
const existingItem = await db
|
|
355
|
+
const existingItem = await knex.connection.db(tableName)
|
|
349
356
|
.where(request.params)
|
|
350
357
|
.first();
|
|
351
358
|
|
|
@@ -363,16 +370,14 @@ async function update(request, reply, routeOptions = {}) {
|
|
|
363
370
|
}
|
|
364
371
|
}
|
|
365
372
|
|
|
366
|
-
await db
|
|
373
|
+
await knex.connection.db(tableName)
|
|
367
374
|
.where(request.params)
|
|
368
375
|
.update({
|
|
369
376
|
...data,
|
|
370
377
|
updated_at: new Date()
|
|
371
378
|
})
|
|
372
379
|
|
|
373
|
-
const updatedItem = await
|
|
374
|
-
.where(request.params)
|
|
375
|
-
.first();
|
|
380
|
+
const updatedItem = await getById({ ...request }, {}, { ...routeOptions, primaryKey: primaryKey }, true);
|
|
376
381
|
|
|
377
382
|
return reply.send({
|
|
378
383
|
status: true,
|
|
@@ -403,11 +408,10 @@ async function upload(request, reply, routeOptions = {}) {
|
|
|
403
408
|
try {
|
|
404
409
|
const tableName = routeOptions.tableName || 'users';
|
|
405
410
|
const primaryKey = routeOptions.primaryKey || 'id';
|
|
406
|
-
const { [primaryKey]: id } = request.params;
|
|
407
411
|
const routeConfig = routeOptions.routeConfig || {};
|
|
408
412
|
|
|
409
|
-
const existingItem = await db
|
|
410
|
-
.where(
|
|
413
|
+
const existingItem = await knex.connection.db(tableName)
|
|
414
|
+
.where(request.params)
|
|
411
415
|
.first();
|
|
412
416
|
|
|
413
417
|
if (!existingItem) {
|
|
@@ -417,7 +421,7 @@ async function upload(request, reply, routeOptions = {}) {
|
|
|
417
421
|
});
|
|
418
422
|
}
|
|
419
423
|
|
|
420
|
-
const uploadResult = await uploadFile(request.body[routeConfig.upload_field],
|
|
424
|
+
const uploadResult = await uploadFile(request.body[routeConfig.upload_field], request.params[primaryKey], tableName);
|
|
421
425
|
if(!uploadResult.status) {
|
|
422
426
|
return reply.status(500).send({
|
|
423
427
|
status: false,
|
|
@@ -425,8 +429,8 @@ async function upload(request, reply, routeOptions = {}) {
|
|
|
425
429
|
});
|
|
426
430
|
}
|
|
427
431
|
|
|
428
|
-
await db
|
|
429
|
-
.where(
|
|
432
|
+
await knex.connection.db(tableName)
|
|
433
|
+
.where(request.params)
|
|
430
434
|
.update({
|
|
431
435
|
[routeConfig.upload_field]: uploadResult.file.fileUrl
|
|
432
436
|
});
|
|
@@ -464,7 +468,7 @@ async function deleteRecord(request, reply, routeOptions = {}) {
|
|
|
464
468
|
const tableName = routeOptions.tableName || 'users';
|
|
465
469
|
|
|
466
470
|
// Check if record exists
|
|
467
|
-
const existingItem = await db
|
|
471
|
+
const existingItem = await knex.connection.db(tableName)
|
|
468
472
|
.where('id', id)
|
|
469
473
|
.first();
|
|
470
474
|
|
|
@@ -475,7 +479,7 @@ async function deleteRecord(request, reply, routeOptions = {}) {
|
|
|
475
479
|
});
|
|
476
480
|
}
|
|
477
481
|
|
|
478
|
-
await db
|
|
482
|
+
await knex.connection.db(tableName)
|
|
479
483
|
.where('id', id)
|
|
480
484
|
.del();
|
|
481
485
|
|
|
@@ -524,7 +528,7 @@ const generateRandomString = async (from_string = null, field_name = null, table
|
|
|
524
528
|
* @returns {Promise<boolean>} - The unique status
|
|
525
529
|
*/
|
|
526
530
|
const checkUnique = async (value = null, field_name = null, tableName = null) => {
|
|
527
|
-
const existing_item = await db
|
|
531
|
+
const existing_item = await knex.connection.db(tableName).select(field_name).where(field_name, value).first();
|
|
528
532
|
return existing_item ? true : false;
|
|
529
533
|
}
|
|
530
534
|
|
|
@@ -594,7 +598,7 @@ const processJoinTables = async (items, joinTables) => {
|
|
|
594
598
|
|
|
595
599
|
const personal_ids = items.map(item => item[joinTable.primary_key]);
|
|
596
600
|
|
|
597
|
-
const personal_items = db
|
|
601
|
+
const personal_items = knex.connection.db(joinTable.table).whereIn(joinTable.table + '.' + joinTable.foreign_key, personal_ids);
|
|
598
602
|
|
|
599
603
|
if(joinTable.extra_where) {
|
|
600
604
|
personal_items.where(db.raw(joinTable.table + '.' + joinTable.extra_where));
|
package/stores/base.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { connection } = require('../libraries/knex');
|
|
2
2
|
|
|
3
3
|
module.exports = class StoreModel {
|
|
4
4
|
constructor(name = 'store_model', primary_key = 'id', schema = {}) {
|
|
5
5
|
this.name = name;
|
|
6
|
-
this.knex =
|
|
6
|
+
this.knex = connection.db;
|
|
7
7
|
this.data = new Map();
|
|
8
8
|
this.primary_key = primary_key;
|
|
9
9
|
this.schema = schema;
|
package/stores/config.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
const config = {};
|
|
2
2
|
|
|
3
|
-
const setConfig = (
|
|
4
|
-
|
|
3
|
+
const setConfig = (newConfig) => {
|
|
4
|
+
if(Object.keys(newConfig).length > 0) {
|
|
5
|
+
for(const key in newConfig) {
|
|
6
|
+
config[key] = newConfig[key];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return config;
|
|
5
10
|
}
|
|
6
11
|
|
|
7
12
|
module.exports = {
|
package/utils/jsonRouteLoader.js
CHANGED
|
@@ -3,6 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const handlers = require('../routes/auto/handler');
|
|
4
4
|
const general = require('../libraries/general');
|
|
5
5
|
const { add_model } = require('../stores');
|
|
6
|
+
const { config: configStore } = require('../stores/config');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* JSON Route Loader
|
|
@@ -19,7 +20,7 @@ class JsonRouteLoader {
|
|
|
19
20
|
* Load all JSON route configurations from routes/admin folder
|
|
20
21
|
* @param {Object} fastify - Fastify instance
|
|
21
22
|
*/
|
|
22
|
-
async loadJsonRoutes(fastify, routesDir, workerName) {
|
|
23
|
+
async loadJsonRoutes(fastify, routesDir, workerName, type = 'service') {
|
|
23
24
|
const adminPath = path.resolve(routesDir);
|
|
24
25
|
|
|
25
26
|
if(!workerName) {
|
|
@@ -39,7 +40,7 @@ class JsonRouteLoader {
|
|
|
39
40
|
|
|
40
41
|
for (const jsonFile of jsonFiles) {
|
|
41
42
|
try {
|
|
42
|
-
await this.loadJsonRoute(fastify, path.join(adminPath, jsonFile), workerName);
|
|
43
|
+
await this.loadJsonRoute(fastify, path.join(adminPath, jsonFile), workerName, type);
|
|
43
44
|
} catch (error) {
|
|
44
45
|
console.log(error.message);
|
|
45
46
|
}
|
|
@@ -51,7 +52,7 @@ class JsonRouteLoader {
|
|
|
51
52
|
* @param {Object} fastify - Fastify instance
|
|
52
53
|
* @param {string} jsonPath - Path to JSON file
|
|
53
54
|
*/
|
|
54
|
-
async loadJsonRoute(fastify, jsonPath, workerName) {
|
|
55
|
+
async loadJsonRoute(fastify, jsonPath, workerName, type = 'service') {
|
|
55
56
|
try {
|
|
56
57
|
|
|
57
58
|
const config = require(jsonPath);
|
|
@@ -66,6 +67,7 @@ class JsonRouteLoader {
|
|
|
66
67
|
const store = config.store || null;
|
|
67
68
|
const routes = config.routes || {};
|
|
68
69
|
const schema = config.schema || {};
|
|
70
|
+
const joinTables = config.join_tables || {};
|
|
69
71
|
|
|
70
72
|
// Validate configuration
|
|
71
73
|
this.validateConfig(config);
|
|
@@ -75,7 +77,7 @@ class JsonRouteLoader {
|
|
|
75
77
|
const routeName = route.action;
|
|
76
78
|
const routeConfig = route;
|
|
77
79
|
if (this.supportedRoutes.includes(routeName)) {
|
|
78
|
-
await this.registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema);
|
|
80
|
+
await this.registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, joinTables, type);
|
|
79
81
|
if(store) {
|
|
80
82
|
await add_model(store, primaryKey, schema);
|
|
81
83
|
}
|
|
@@ -111,9 +113,9 @@ class JsonRouteLoader {
|
|
|
111
113
|
* @param {string} routeName - Route name (list, get, create, update, delete)
|
|
112
114
|
* @param {Object} routeConfig - Route configuration
|
|
113
115
|
*/
|
|
114
|
-
async registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema) {
|
|
116
|
+
async registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, joinTables, type = 'service') {
|
|
115
117
|
|
|
116
|
-
const routeDefinition = this.generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema);
|
|
118
|
+
const routeDefinition = this.generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type, joinTables);
|
|
117
119
|
const routeKey = `${routeDefinition.method}:${routeDefinition.url}`;
|
|
118
120
|
|
|
119
121
|
if (this.registeredRoutes.has(routeKey)) {
|
|
@@ -148,7 +150,7 @@ class JsonRouteLoader {
|
|
|
148
150
|
},
|
|
149
151
|
handler: async (request, reply) => {
|
|
150
152
|
// Pass table name and route config to handler as additional parameters
|
|
151
|
-
return handler(request, reply, { tableName, routeConfig, schema, primaryKey, store, filters });
|
|
153
|
+
return handler(request, reply, { tableName, routeConfig, schema, primaryKey, store, filters, joinTables });
|
|
152
154
|
}
|
|
153
155
|
});
|
|
154
156
|
|
|
@@ -166,40 +168,41 @@ class JsonRouteLoader {
|
|
|
166
168
|
* @param {Object} routeConfig - Route configuration
|
|
167
169
|
* @returns {Object} Route definition
|
|
168
170
|
*/
|
|
169
|
-
generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema) {
|
|
170
|
-
const
|
|
171
|
+
generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type = 'service', joinTables = {}) {
|
|
172
|
+
const prefix = configStore.prefix ? configStore.prefix + '/' : '';
|
|
173
|
+
const baseUrl = `/${prefix}${fileName}`;
|
|
171
174
|
primaryKey = primaryKey || 'id';
|
|
172
175
|
|
|
173
176
|
const routeDefinitions = {
|
|
174
177
|
list: {
|
|
175
178
|
method: 'GET',
|
|
176
179
|
url: baseUrl,
|
|
177
|
-
schema: this.generateListSchema(tableName, routeConfig, primaryKey, schema)
|
|
180
|
+
schema: this.generateListSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
|
|
178
181
|
},
|
|
179
182
|
get: {
|
|
180
183
|
method: 'GET',
|
|
181
184
|
url: `${baseUrl}/:${primaryKey}`,
|
|
182
|
-
schema: this.generateGetSchema(tableName, routeConfig, primaryKey, schema)
|
|
185
|
+
schema: this.generateGetSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
|
|
183
186
|
},
|
|
184
187
|
create: {
|
|
185
188
|
method: 'POST',
|
|
186
189
|
url: baseUrl,
|
|
187
|
-
schema: this.generateCreateSchema(tableName, routeConfig, primaryKey, schema)
|
|
190
|
+
schema: this.generateCreateSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
|
|
188
191
|
},
|
|
189
192
|
update: {
|
|
190
193
|
method: 'PUT',
|
|
191
194
|
url: `${baseUrl}/:${primaryKey}`,
|
|
192
|
-
schema: this.generateUpdateSchema(tableName, routeConfig, primaryKey, schema)
|
|
195
|
+
schema: this.generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
|
|
193
196
|
},
|
|
194
197
|
delete: {
|
|
195
198
|
method: 'DELETE',
|
|
196
199
|
url: `${baseUrl}/:${primaryKey}`,
|
|
197
|
-
schema: this.generateDeleteSchema(tableName, routeConfig, primaryKey, schema)
|
|
200
|
+
schema: this.generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
|
|
198
201
|
},
|
|
199
202
|
upload: {
|
|
200
203
|
method: 'POST',
|
|
201
|
-
url: `${baseUrl}/:${primaryKey}
|
|
202
|
-
schema: this.generateUploadSchema(tableName, routeConfig, primaryKey, schema),
|
|
204
|
+
url: `${baseUrl}/:${primaryKey}/${routeConfig.upload_field || 'upload'}`,
|
|
205
|
+
schema: this.generateUploadSchema(tableName, routeConfig, primaryKey, schema, type, joinTables),
|
|
203
206
|
validatorCompiler: ({ schema }) => {
|
|
204
207
|
return (data) => {
|
|
205
208
|
return true;
|
|
@@ -220,12 +223,12 @@ class JsonRouteLoader {
|
|
|
220
223
|
* @param {Object} filters - Filters object
|
|
221
224
|
* @returns {Object} Schema
|
|
222
225
|
*/
|
|
223
|
-
generateListSchema(tableName, routeConfig, primaryKey, schema) {
|
|
224
|
-
const itemSchema = this.generateItemSchema(schema, primaryKey);
|
|
226
|
+
generateListSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
227
|
+
const itemSchema = this.generateItemSchema(schema, primaryKey, joinTables);
|
|
225
228
|
|
|
226
229
|
return {
|
|
227
230
|
description: `Get all ${tableName} with pagination and search`,
|
|
228
|
-
tags: [general.titleCase(tableName)],
|
|
231
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
229
232
|
summary: routeConfig.summary || `List of ${tableName} with pagination and search`,
|
|
230
233
|
querystring: {
|
|
231
234
|
type: 'object',
|
|
@@ -279,13 +282,13 @@ class JsonRouteLoader {
|
|
|
279
282
|
* @param {Object} routeConfig - Route configuration
|
|
280
283
|
* @returns {Object} Schema
|
|
281
284
|
*/
|
|
282
|
-
generateGetSchema(tableName, routeConfig, primaryKey, schema) {
|
|
283
|
-
const itemSchema = this.generateItemSchema(schema, primaryKey);
|
|
285
|
+
generateGetSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
286
|
+
const itemSchema = this.generateItemSchema(schema, primaryKey, joinTables);
|
|
284
287
|
primaryKey = primaryKey || 'id';
|
|
285
288
|
|
|
286
289
|
return {
|
|
287
290
|
description: `Get ${tableName} by ${primaryKey}`,
|
|
288
|
-
tags: [general.titleCase(tableName)],
|
|
291
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
289
292
|
summary: routeConfig.summary || `Get ${tableName} by ${primaryKey}`,
|
|
290
293
|
params: {
|
|
291
294
|
type: 'object',
|
|
@@ -320,12 +323,12 @@ class JsonRouteLoader {
|
|
|
320
323
|
* @param {Object} routeConfig - Route configuration
|
|
321
324
|
* @returns {Object} Schema
|
|
322
325
|
*/
|
|
323
|
-
generateCreateSchema(tableName, routeConfig, primaryKey, schema) {
|
|
326
|
+
generateCreateSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
324
327
|
const bodySchema = this.generateBodySchema(schema, false, primaryKey);
|
|
325
328
|
|
|
326
329
|
return {
|
|
327
330
|
description: `Create new ${tableName}`,
|
|
328
|
-
tags: [general.titleCase(tableName)],
|
|
331
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
329
332
|
summary: routeConfig.summary || `Create new ${tableName}`,
|
|
330
333
|
body: bodySchema,
|
|
331
334
|
response: {
|
|
@@ -333,7 +336,7 @@ class JsonRouteLoader {
|
|
|
333
336
|
type: 'object',
|
|
334
337
|
properties: {
|
|
335
338
|
status: { type: 'boolean', default: true },
|
|
336
|
-
data: this.generateItemSchema(schema, primaryKey)
|
|
339
|
+
data: this.generateItemSchema(schema, primaryKey, joinTables)
|
|
337
340
|
},
|
|
338
341
|
additionalProperties: false
|
|
339
342
|
},
|
|
@@ -354,12 +357,12 @@ class JsonRouteLoader {
|
|
|
354
357
|
* @param {Object} routeConfig - Route configuration
|
|
355
358
|
* @returns {Object} Schema
|
|
356
359
|
*/
|
|
357
|
-
generateUpdateSchema(tableName, routeConfig, primaryKey, schema) {
|
|
360
|
+
generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
358
361
|
const bodySchema = this.generateBodySchema(schema, true, primaryKey, 'updatable');
|
|
359
362
|
|
|
360
363
|
return {
|
|
361
364
|
description: `Update ${tableName} by ID`,
|
|
362
|
-
tags: [general.titleCase(tableName)],
|
|
365
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
363
366
|
summary: routeConfig.summary || `Update ${tableName} by ${primaryKey}`,
|
|
364
367
|
params: {
|
|
365
368
|
type: 'object',
|
|
@@ -375,7 +378,7 @@ class JsonRouteLoader {
|
|
|
375
378
|
type: 'object',
|
|
376
379
|
properties: {
|
|
377
380
|
status: { type: 'boolean', default: true },
|
|
378
|
-
data: this.generateItemSchema(schema, primaryKey)
|
|
381
|
+
data: this.generateItemSchema(schema, primaryKey, joinTables)
|
|
379
382
|
},
|
|
380
383
|
additionalProperties: false
|
|
381
384
|
},
|
|
@@ -396,10 +399,10 @@ class JsonRouteLoader {
|
|
|
396
399
|
* @param {Object} routeConfig - Route configuration
|
|
397
400
|
* @returns {Object} Schema
|
|
398
401
|
*/
|
|
399
|
-
generateDeleteSchema(tableName, routeConfig, primaryKey, schema) {
|
|
402
|
+
generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
400
403
|
return {
|
|
401
404
|
description: `Delete ${tableName} by ID`,
|
|
402
|
-
tags: [general.titleCase(tableName)],
|
|
405
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
403
406
|
summary: routeConfig.summary || `Delete ${tableName} by ${primaryKey}`,
|
|
404
407
|
params: {
|
|
405
408
|
type: 'object',
|
|
@@ -414,7 +417,7 @@ class JsonRouteLoader {
|
|
|
414
417
|
type: 'object',
|
|
415
418
|
properties: {
|
|
416
419
|
status: { type: 'boolean', default: true },
|
|
417
|
-
data: this.generateItemSchema(schema, primaryKey)
|
|
420
|
+
data: this.generateItemSchema(schema, primaryKey, joinTables)
|
|
418
421
|
},
|
|
419
422
|
additionalProperties: false
|
|
420
423
|
},
|
|
@@ -435,11 +438,11 @@ class JsonRouteLoader {
|
|
|
435
438
|
* @param {Object} routeConfig - Route configuration
|
|
436
439
|
* @returns {Object} Schema
|
|
437
440
|
*/
|
|
438
|
-
generateUploadSchema(tableName, routeConfig, primaryKey, schema) {
|
|
441
|
+
generateUploadSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
|
|
439
442
|
const uploadField = routeConfig.upload_field || 'file';
|
|
440
443
|
return {
|
|
441
444
|
description: `Upload file for ${tableName} by ${primaryKey}`,
|
|
442
|
-
tags: [general.titleCase(tableName)],
|
|
445
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
|
|
443
446
|
summary: routeConfig.summary || `Upload file for ${tableName} by ${primaryKey}`,
|
|
444
447
|
params: {
|
|
445
448
|
type: 'object',
|
|
@@ -462,7 +465,7 @@ class JsonRouteLoader {
|
|
|
462
465
|
type: 'object',
|
|
463
466
|
properties: {
|
|
464
467
|
status: { type: 'boolean', default: true },
|
|
465
|
-
data: this.generateItemSchema(schema, primaryKey)
|
|
468
|
+
data: this.generateItemSchema(schema, primaryKey, joinTables)
|
|
466
469
|
},
|
|
467
470
|
additionalProperties: false
|
|
468
471
|
},
|
|
@@ -482,7 +485,7 @@ class JsonRouteLoader {
|
|
|
482
485
|
* @param {Object} itemSchema - Item schema from config
|
|
483
486
|
* @returns {Object} Item schema
|
|
484
487
|
*/
|
|
485
|
-
generateItemSchema(schema, primaryKey) {
|
|
488
|
+
generateItemSchema(schema, primaryKey, joinTables = {}) {
|
|
486
489
|
if (!schema) {
|
|
487
490
|
return { type: 'object' };
|
|
488
491
|
}
|
|
@@ -507,6 +510,18 @@ class JsonRouteLoader {
|
|
|
507
510
|
}
|
|
508
511
|
}
|
|
509
512
|
|
|
513
|
+
if(Object.entries(joinTables).length > 0) {
|
|
514
|
+
for(const [key, value] of Object.entries(joinTables)) {
|
|
515
|
+
if(value.type == 'one-to-one') {
|
|
516
|
+
withoutReferences[value.table] = {
|
|
517
|
+
type: 'object',
|
|
518
|
+
properties: value.properties,
|
|
519
|
+
additionalProperties: false
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
510
525
|
return {
|
|
511
526
|
type: 'object',
|
|
512
527
|
properties: withoutReferences,
|
package/utils/middleware.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const i18n = require('./i18n');
|
|
2
|
-
const db = require('../libraries/knex');
|
|
3
2
|
const { config } = require('../stores/config');
|
|
4
3
|
/**
|
|
5
4
|
* Middleware utilities for Fastify
|
|
@@ -17,10 +16,6 @@ class Middleware {
|
|
|
17
16
|
// Add locale to request object
|
|
18
17
|
request.locale = locale;
|
|
19
18
|
request.t = (key, params = {}) => i18n.t(key, locale, params);
|
|
20
|
-
|
|
21
|
-
const language = await db.instance('languages').where('code', locale).first();
|
|
22
|
-
|
|
23
|
-
request.language = language ? language.language_id : 1;
|
|
24
19
|
|
|
25
20
|
// Add locale to reply headers
|
|
26
21
|
reply.header('Content-Language', locale);
|
|
@@ -30,8 +25,8 @@ class Middleware {
|
|
|
30
25
|
/**
|
|
31
26
|
* Error handler middleware with custom response format
|
|
32
27
|
*/
|
|
33
|
-
static errorHandler(error, request, reply) {
|
|
34
|
-
|
|
28
|
+
static errorHandler(error, request, reply, config) {
|
|
29
|
+
|
|
35
30
|
if(config.development) {
|
|
36
31
|
console.log(error);
|
|
37
32
|
}
|
|
@@ -68,7 +63,7 @@ class Middleware {
|
|
|
68
63
|
code: 404
|
|
69
64
|
});
|
|
70
65
|
}
|
|
71
|
-
|
|
66
|
+
|
|
72
67
|
// Handle other errors
|
|
73
68
|
const statusCode = error.statusCode || 500;
|
|
74
69
|
|
|
@@ -116,9 +111,11 @@ class Middleware {
|
|
|
116
111
|
*/
|
|
117
112
|
static responseFormatter() {
|
|
118
113
|
return async (request, reply) => {
|
|
114
|
+
|
|
115
|
+
const route_url = request?.routeOptions?.url || request.url;
|
|
119
116
|
|
|
120
117
|
// Skip response formatting for Swagger routes
|
|
121
|
-
if (
|
|
118
|
+
if (route_url.startsWith('/') || route_url.startsWith('/')) {
|
|
122
119
|
return;
|
|
123
120
|
}
|
|
124
121
|
|
package/utils/routeLoader.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const JsonRouteLoader = require('./jsonRouteLoader');
|
|
4
4
|
const general = require('../libraries/general');
|
|
5
|
+
const { config: configStore } = require('../stores/config');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Automatically loads routes from the routes directory
|
|
@@ -11,6 +12,7 @@ const general = require('../libraries/general');
|
|
|
11
12
|
* @param {boolean} includeAuto - Whether to include auto routes
|
|
12
13
|
*/
|
|
13
14
|
async function loadRoutes(fastify, routesDir = './routes', includeCommon = false, workerName) {
|
|
15
|
+
|
|
14
16
|
const routesPath = path.resolve(routesDir);
|
|
15
17
|
|
|
16
18
|
if (!fs.existsSync(routesPath)) {
|
|
@@ -31,17 +33,17 @@ async function loadRoutes(fastify, routesDir = './routes', includeCommon = false
|
|
|
31
33
|
|
|
32
34
|
for (const group of routeGroups) {
|
|
33
35
|
const groupPath = path.join(routesPath + '/spec', group);
|
|
34
|
-
await loadRouteGroup(fastify, group, groupPath, workerName);
|
|
36
|
+
await loadRouteGroup(fastify, group, groupPath, workerName, 'service');
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
// Load JSON routes from routes/admin folder
|
|
38
40
|
const jsonLoader = new JsonRouteLoader();
|
|
39
|
-
await jsonLoader.loadJsonRoutes(fastify, routesPath + '/auto', workerName);
|
|
41
|
+
await jsonLoader.loadJsonRoutes(fastify, routesPath + '/auto', workerName, 'service');
|
|
40
42
|
|
|
41
43
|
// // Load common routes if requested
|
|
42
44
|
if (includeCommon) {
|
|
43
|
-
const commonPath = path.resolve(
|
|
44
|
-
|
|
45
|
+
const commonPath = path.resolve('./routes/common');
|
|
46
|
+
|
|
45
47
|
if (fs.existsSync(commonPath)) {
|
|
46
48
|
|
|
47
49
|
if(!fs.existsSync(commonPath + '/spec')) {
|
|
@@ -56,10 +58,10 @@ async function loadRoutes(fastify, routesDir = './routes', includeCommon = false
|
|
|
56
58
|
|
|
57
59
|
for (const group of routeGroupsCommon) {
|
|
58
60
|
const groupPath = path.join(commonPath + '/spec', group);
|
|
59
|
-
await loadRouteGroup(fastify, group, groupPath, workerName);
|
|
61
|
+
await loadRouteGroup(fastify, group, groupPath, workerName, 'common');
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
await jsonLoader.loadJsonRoutes(fastify, commonPath + '/auto', workerName);
|
|
64
|
+
await jsonLoader.loadJsonRoutes(fastify, commonPath + '/auto', workerName, 'common');
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
}
|
|
@@ -70,8 +72,8 @@ async function loadRoutes(fastify, routesDir = './routes', includeCommon = false
|
|
|
70
72
|
* @param {string} groupName - Name of the route group
|
|
71
73
|
* @param {string} groupPath - Path to the route group directory
|
|
72
74
|
*/
|
|
73
|
-
async function loadRouteGroup(fastify, groupName, groupPath, workerName) {
|
|
74
|
-
await loadRouteModule(fastify, groupName, groupPath, workerName);
|
|
75
|
+
async function loadRouteGroup(fastify, groupName, groupPath, workerName, type = '--') {
|
|
76
|
+
await loadRouteModule(fastify, groupName, groupPath, workerName, type);
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
/**
|
|
@@ -81,7 +83,7 @@ async function loadRouteGroup(fastify, groupName, groupPath, workerName) {
|
|
|
81
83
|
* @param {string} moduleName - Name of the route module
|
|
82
84
|
* @param {string} modulePath - Path to the route module directory
|
|
83
85
|
*/
|
|
84
|
-
async function loadRouteModule(fastify, groupName, modulePath, workerName) {
|
|
86
|
+
async function loadRouteModule(fastify, groupName, modulePath, workerName, type = '--') {
|
|
85
87
|
|
|
86
88
|
// Check if route file exists
|
|
87
89
|
if (!fs.existsSync(modulePath)) {
|
|
@@ -106,14 +108,16 @@ async function loadRouteModule(fastify, groupName, modulePath, workerName) {
|
|
|
106
108
|
console.warn(`Route handler is required for route ${route.path}`);
|
|
107
109
|
continue;
|
|
108
110
|
}
|
|
111
|
+
|
|
112
|
+
const prefix = configStore.prefix ? configStore.prefix + '/' : '';
|
|
109
113
|
|
|
110
114
|
if(route.path) {
|
|
111
|
-
route.path = `/${moduleName}/${route.path}`;
|
|
115
|
+
route.path = `/${prefix}${moduleName}/${route.path}`;
|
|
112
116
|
} else {
|
|
113
|
-
route.path = `/${moduleName}`;
|
|
117
|
+
route.path = `/${prefix}${moduleName}`;
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
await registerRoute(fastify, route, moduleName, workerName);
|
|
120
|
+
await registerRoute(fastify, route, moduleName, workerName, type);
|
|
117
121
|
}
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -130,7 +134,7 @@ async function loadRouteModule(fastify, groupName, modulePath, workerName) {
|
|
|
130
134
|
* @param {Object} validation - Route validation
|
|
131
135
|
* @param {string} prefix - Route prefix
|
|
132
136
|
*/
|
|
133
|
-
async function registerRoute(fastify, routeConfig, moduleName, workerName) {
|
|
137
|
+
async function registerRoute(fastify, routeConfig, moduleName, workerName, type = '--') {
|
|
134
138
|
const {
|
|
135
139
|
method = 'GET',
|
|
136
140
|
path = '',
|
|
@@ -143,20 +147,8 @@ async function registerRoute(fastify, routeConfig, moduleName, workerName) {
|
|
|
143
147
|
// Build full URL
|
|
144
148
|
const fullUrl = path;
|
|
145
149
|
|
|
146
|
-
if(schema.success_response && schema.success_response.type === 'object' && schema.success_response.properties && schema.success_response.properties.pagination) {
|
|
147
|
-
schema.success_response.properties.pagination = {
|
|
148
|
-
type: 'object',
|
|
149
|
-
properties: {
|
|
150
|
-
total: { type: 'integer' },
|
|
151
|
-
page: { type: 'integer' },
|
|
152
|
-
limit: { type: 'integer' },
|
|
153
|
-
totalPages: { type: 'integer' }
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
150
|
const schemaRoute = {
|
|
159
|
-
tags: [general.titleCase(moduleName)],
|
|
151
|
+
tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(moduleName)],
|
|
160
152
|
response: {
|
|
161
153
|
200: schema.success_response ? { ...schema.success_response, additionalProperties: schema.success_response.additionalProperties || false } : {
|
|
162
154
|
type: 'object',
|
|
@@ -209,6 +201,38 @@ async function registerRoute(fastify, routeConfig, moduleName, workerName) {
|
|
|
209
201
|
schemaRoute.security = [{ bearer: [] }];
|
|
210
202
|
}
|
|
211
203
|
|
|
204
|
+
if(schema.pagination) {
|
|
205
|
+
|
|
206
|
+
if(schemaRoute.querystring && schemaRoute.querystring.properties) {
|
|
207
|
+
schemaRoute.querystring.properties = Object.assign(schemaRoute.querystring.properties || {}, {
|
|
208
|
+
page: { type: 'integer', minimum: 1, default: 1 },
|
|
209
|
+
limit: { type: 'integer', minimum: 1, maximum: 100, default: 25 },
|
|
210
|
+
search: { type: 'string' },
|
|
211
|
+
order: { type: 'string' }
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
schemaRoute.querystring = {
|
|
215
|
+
type: 'object',
|
|
216
|
+
properties: {
|
|
217
|
+
page: { type: 'integer', minimum: 1, default: 1 },
|
|
218
|
+
limit: { type: 'integer', minimum: 1, maximum: 100, default: 25 },
|
|
219
|
+
search: { type: 'string' },
|
|
220
|
+
order: { type: 'string' }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
schemaRoute.response[200].properties.pagination = {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties: {
|
|
228
|
+
total: { type: 'integer' },
|
|
229
|
+
page: { type: 'integer' },
|
|
230
|
+
limit: { type: 'integer' },
|
|
231
|
+
totalPages: { type: 'integer' }
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
212
236
|
// Register the route
|
|
213
237
|
fastify.route({
|
|
214
238
|
method: method.toUpperCase(),
|