@drax/crud-back 2.11.0 → 3.0.0
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/controllers/AbstractFastifyController.js +47 -24
- package/dist/repository/AbstractMongoRepository.js +12 -8
- package/dist/repository/AbstractSqliteRepository.js +40 -9
- package/dist/services/AbstractService.js +9 -6
- package/package.json +8 -7
- package/src/controllers/AbstractFastifyController.ts +56 -28
- package/src/repository/AbstractMongoRepository.ts +17 -8
- package/src/repository/AbstractSqliteRepository.ts +61 -10
- package/src/services/AbstractService.ts +12 -6
- package/test/_mocks/MockRepository.ts +1 -1
- package/test/controllers/PersonController.test.ts +547 -0
- package/test/people/controllers/CountryController.ts +40 -0
- package/test/people/controllers/LanguageController.ts +29 -0
- package/test/people/controllers/PersonController.ts +29 -0
- package/test/people/factory/services/CountryServiceFactory.ts +41 -0
- package/test/people/factory/services/LanguageServiceFactory.ts +41 -0
- package/test/people/factory/services/PersonServiceFactory.ts +41 -0
- package/test/people/interfaces/ICountry.ts +28 -0
- package/test/people/interfaces/ICountryRepository.ts +11 -0
- package/test/people/interfaces/ILanguage.ts +32 -0
- package/test/people/interfaces/ILanguageRepository.ts +11 -0
- package/test/people/interfaces/IPerson.ts +58 -0
- package/test/people/interfaces/IPersonRepository.ts +11 -0
- package/test/people/models/CountryModel.ts +38 -0
- package/test/people/models/LanguageModel.ts +40 -0
- package/test/people/models/PersonModel.ts +61 -0
- package/test/people/permissions/CountryPermissions.ts +14 -0
- package/test/people/permissions/LanguagePermissions.ts +14 -0
- package/test/people/permissions/PersonPermissions.ts +18 -0
- package/test/people/repository/mongo/CountryMongoRepository.ts +22 -0
- package/test/people/repository/mongo/LanguageMongoRepository.ts +22 -0
- package/test/people/repository/mongo/PersonMongoRepository.ts +22 -0
- package/test/people/repository/sqlite/CountrySqliteRepository.ts +33 -0
- package/test/people/repository/sqlite/LanguageSqliteRepository.ts +37 -0
- package/test/people/repository/sqlite/PersonSqliteRepository.ts +42 -0
- package/test/people/routes/CountryRoutes.ts +34 -0
- package/test/people/routes/LanguageRoutes.ts +34 -0
- package/test/people/routes/PersonRoutes.ts +40 -0
- package/test/people/schemas/CountrySchema.ts +22 -0
- package/test/people/schemas/LanguageSchema.ts +22 -0
- package/test/people/schemas/PersonSchema.ts +42 -0
- package/test/people/services/CountryService.ts +20 -0
- package/test/people/services/LanguageService.ts +20 -0
- package/test/people/services/PersonService.ts +20 -0
- package/test/services/AbstractService.test.ts +11 -7
- package/test/setup/MongoInMemory.ts +56 -0
- package/test/setup/TestSetup.ts +344 -0
- package/test/setup/data/admin-role.ts +13 -0
- package/test/setup/data/basic-user.ts +14 -0
- package/test/setup/data/one-tenant.ts +6 -0
- package/test/setup/data/restricted-role.ts +16 -0
- package/test/setup/data/root-user.ts +14 -0
- package/test/setup/data/tenant-one-user.ts +13 -0
- package/test/setup/data/tenant-two-user.ts +14 -0
- package/test/setup/data/two-tenant.ts +6 -0
- package/test/workers/ExportCsvWorker.test.ts +1 -1
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/types/controllers/AbstractFastifyController.d.ts.map +1 -1
- package/types/repository/AbstractMongoRepository.d.ts +3 -3
- package/types/repository/AbstractMongoRepository.d.ts.map +1 -1
- package/types/repository/AbstractSqliteRepository.d.ts +5 -4
- package/types/repository/AbstractSqliteRepository.d.ts.map +1 -1
- package/types/services/AbstractService.d.ts +4 -2
- package/types/services/AbstractService.d.ts.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CommonConfig, DraxConfig, LimitError, NotFoundError, BadRequestError, CommonController } from "@drax/common-back";
|
|
1
|
+
import { CommonConfig, DraxConfig, LimitError, NotFoundError, BadRequestError, CommonController, setNestedValue } from "@drax/common-back";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import QueryFilterRegex from "../regexs/QueryFilterRegex.js";
|
|
4
4
|
import CrudEventEmitter from "../events/CrudEventEmitter.js";
|
|
@@ -72,15 +72,26 @@ class AbstractFastifyController extends CommonController {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
assertTenant(item, rbac) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
//Si tenantAssert esta habilitado y si ademas el usuario pertenece a un tenant
|
|
76
|
+
if (this.tenantAssert && rbac.hasTenant) {
|
|
77
|
+
//Si esta populado
|
|
78
|
+
if (item[this.tenantField]?._id) {
|
|
79
|
+
rbac.assertTenantId(item[this.tenantField]._id.toString()); //
|
|
80
|
+
//Si esta crudo
|
|
81
|
+
}
|
|
82
|
+
else if (item[this.tenantField]) {
|
|
83
|
+
rbac.assertTenantId(item[this.tenantField].toString());
|
|
84
|
+
}
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
assertUser(item, rbac) {
|
|
81
88
|
if (this.userAssert) {
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
if (item[this.userField]?._id) {
|
|
90
|
+
rbac.assertUserId(item[this.userField]._id.toString());
|
|
91
|
+
}
|
|
92
|
+
else if (item[this.userField]) {
|
|
93
|
+
rbac.assertUserId(item[this.userField].toString());
|
|
94
|
+
}
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
97
|
assertUserAndTenant(item, rbac) {
|
|
@@ -89,10 +100,10 @@ class AbstractFastifyController extends CommonController {
|
|
|
89
100
|
}
|
|
90
101
|
applyUserAndTenantSetters(payload, rbac) {
|
|
91
102
|
if (this.tenantSetter && rbac.tenantId) {
|
|
92
|
-
payload
|
|
103
|
+
setNestedValue(payload, this.tenantField, rbac.tenantId);
|
|
93
104
|
}
|
|
94
105
|
if (this.userSetter && rbac.userId) {
|
|
95
|
-
payload
|
|
106
|
+
setNestedValue(payload, this.userField, rbac.userId);
|
|
96
107
|
}
|
|
97
108
|
}
|
|
98
109
|
extractRequestData(request) {
|
|
@@ -212,17 +223,21 @@ class AbstractFastifyController extends CommonController {
|
|
|
212
223
|
const id = request.params.id;
|
|
213
224
|
const payload = request.body;
|
|
214
225
|
let preItem = await this.service.findById(id);
|
|
226
|
+
if (!preItem) {
|
|
227
|
+
reply.statusCode = 404;
|
|
228
|
+
reply.send({ error: 'NOT_FOUND' });
|
|
229
|
+
}
|
|
215
230
|
if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
|
|
216
|
-
|
|
217
|
-
reply.statusCode = 404;
|
|
218
|
-
reply.send({ error: 'NOT_FOUND' });
|
|
219
|
-
}
|
|
231
|
+
//Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
|
|
220
232
|
this.assertUser(preItem, request.rbac);
|
|
221
233
|
}
|
|
222
|
-
//
|
|
234
|
+
//Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
|
|
235
|
+
this.assertTenant(preItem, request.rbac);
|
|
236
|
+
//Definido el tenant en create no debe modificarse en un update
|
|
223
237
|
if (this.tenantSetter) {
|
|
224
238
|
delete payload[this.tenantField];
|
|
225
239
|
}
|
|
240
|
+
//Definido el user en create no debe modificarse en un update
|
|
226
241
|
if (this.userSetter) {
|
|
227
242
|
delete payload[this.userField];
|
|
228
243
|
}
|
|
@@ -255,17 +270,21 @@ class AbstractFastifyController extends CommonController {
|
|
|
255
270
|
const id = request.params.id;
|
|
256
271
|
const payload = request.body;
|
|
257
272
|
let preItem = await this.service.findById(id);
|
|
273
|
+
if (!preItem) {
|
|
274
|
+
reply.statusCode = 404;
|
|
275
|
+
reply.send({ error: 'NOT_FOUND' });
|
|
276
|
+
}
|
|
258
277
|
if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
|
|
259
|
-
|
|
260
|
-
reply.statusCode = 404;
|
|
261
|
-
reply.send({ error: 'NOT_FOUND' });
|
|
262
|
-
}
|
|
278
|
+
//Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
|
|
263
279
|
this.assertUser(preItem, request.rbac);
|
|
264
280
|
}
|
|
265
|
-
//
|
|
281
|
+
//Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
|
|
282
|
+
this.assertTenant(preItem, request.rbac);
|
|
283
|
+
//Definido el tenant en el create no debe modificarse en un update
|
|
266
284
|
if (this.tenantSetter) {
|
|
267
285
|
delete payload[this.tenantField];
|
|
268
286
|
}
|
|
287
|
+
//Definido el user en el create no debe modificarse en un update
|
|
269
288
|
if (this.userSetter) {
|
|
270
289
|
delete payload[this.userField];
|
|
271
290
|
}
|
|
@@ -404,10 +423,12 @@ class AbstractFastifyController extends CommonController {
|
|
|
404
423
|
const limit = this.defaultLimit;
|
|
405
424
|
const field = request.params.field;
|
|
406
425
|
const value = request.params.value;
|
|
407
|
-
let
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
426
|
+
let filters = [];
|
|
427
|
+
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
428
|
+
let items = await this.service.findBy(field, value, limit, filters);
|
|
429
|
+
// for (let item of items) {
|
|
430
|
+
// this.assertUserAndTenant(item, request.rbac)
|
|
431
|
+
// }
|
|
411
432
|
return items;
|
|
412
433
|
}
|
|
413
434
|
catch (e) {
|
|
@@ -423,8 +444,10 @@ class AbstractFastifyController extends CommonController {
|
|
|
423
444
|
}
|
|
424
445
|
const field = request.params.field;
|
|
425
446
|
const value = request.params.value;
|
|
426
|
-
let
|
|
427
|
-
this.
|
|
447
|
+
let filters = [];
|
|
448
|
+
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
449
|
+
let item = await this.service.findOneBy(field, value, filters);
|
|
450
|
+
// this.assertUserAndTenant(item, request.rbac);
|
|
428
451
|
return item;
|
|
429
452
|
}
|
|
430
453
|
catch (e) {
|
|
@@ -89,28 +89,32 @@ class AbstractMongoRepository {
|
|
|
89
89
|
.exec();
|
|
90
90
|
return item;
|
|
91
91
|
}
|
|
92
|
-
async findByIds(ids) {
|
|
92
|
+
async findByIds(ids, filters = []) {
|
|
93
93
|
ids.map(id => this.assertId(id));
|
|
94
|
+
const query = { _id: { $in: ids } };
|
|
95
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model);
|
|
94
96
|
const items = await this._model
|
|
95
|
-
.find(
|
|
97
|
+
.find(query)
|
|
96
98
|
.populate(this._populateFields)
|
|
97
99
|
.lean(this._lean)
|
|
98
100
|
.exec();
|
|
99
101
|
return items;
|
|
100
102
|
}
|
|
101
|
-
async findOneBy(field, value) {
|
|
102
|
-
const
|
|
103
|
+
async findOneBy(field, value, filters = []) {
|
|
104
|
+
const query = { [field]: value };
|
|
105
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model);
|
|
103
106
|
const item = await this._model
|
|
104
|
-
.findOne(
|
|
107
|
+
.findOne(query)
|
|
105
108
|
.populate(this._populateFields)
|
|
106
109
|
.lean(this._lean)
|
|
107
110
|
.exec();
|
|
108
111
|
return item;
|
|
109
112
|
}
|
|
110
|
-
async findBy(field, value, limit = 0) {
|
|
111
|
-
const
|
|
113
|
+
async findBy(field, value, limit = 0, filters = []) {
|
|
114
|
+
const query = { [field]: value };
|
|
115
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model);
|
|
112
116
|
const items = await this._model
|
|
113
|
-
.find(
|
|
117
|
+
.find(query)
|
|
114
118
|
.limit(limit)
|
|
115
119
|
.populate(this._populateFields)
|
|
116
120
|
.lean(this._lean)
|
|
@@ -200,7 +200,7 @@ class AbstractSqliteRepository {
|
|
|
200
200
|
}
|
|
201
201
|
return items;
|
|
202
202
|
}
|
|
203
|
-
async search(value, limit = 1000) {
|
|
203
|
+
async search(value, limit = 1000, filters = []) {
|
|
204
204
|
let where = "";
|
|
205
205
|
let params = [];
|
|
206
206
|
if (value && this.searchFields.length > 0) {
|
|
@@ -225,19 +225,50 @@ class AbstractSqliteRepository {
|
|
|
225
225
|
await this.decorate(item);
|
|
226
226
|
return item;
|
|
227
227
|
}
|
|
228
|
-
async
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
async findByIds(ids, filters = []) {
|
|
229
|
+
const inPlaceholders = ids.map(() => '?').join(',');
|
|
230
|
+
let where = `WHERE ID IN(${inPlaceholders})`;
|
|
231
|
+
let params = [ids];
|
|
232
|
+
if (filters.length > 0) {
|
|
233
|
+
const result = SqlQueryFilter.applyFilters(where, filters);
|
|
234
|
+
where = result.where;
|
|
235
|
+
params.push(...result.params);
|
|
236
|
+
}
|
|
237
|
+
const items = this.db
|
|
238
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where}`)
|
|
239
|
+
.all(params);
|
|
232
240
|
for (const item of items) {
|
|
233
241
|
await this.decorate(item);
|
|
234
242
|
}
|
|
235
243
|
return items;
|
|
236
244
|
}
|
|
237
|
-
async
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
245
|
+
async findBy(field, value, limit = 0, filters = []) {
|
|
246
|
+
let where = `WHERE ${field} = ?`;
|
|
247
|
+
let params = [value];
|
|
248
|
+
if (filters.length > 0) {
|
|
249
|
+
const result = SqlQueryFilter.applyFilters(where, filters);
|
|
250
|
+
where = result.where;
|
|
251
|
+
params.push(...result.params);
|
|
252
|
+
}
|
|
253
|
+
const items = this.db
|
|
254
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT ?`)
|
|
255
|
+
.all([...params, limit]);
|
|
256
|
+
for (const item of items) {
|
|
257
|
+
await this.decorate(item);
|
|
258
|
+
}
|
|
259
|
+
return items;
|
|
260
|
+
}
|
|
261
|
+
async findOneBy(field, value, filters = []) {
|
|
262
|
+
let where = `WHERE ${field} = ?`;
|
|
263
|
+
let params = [value];
|
|
264
|
+
if (filters.length > 0) {
|
|
265
|
+
const result = SqlQueryFilter.applyFilters(where, filters);
|
|
266
|
+
where = result.where;
|
|
267
|
+
params.push(...result.params);
|
|
268
|
+
}
|
|
269
|
+
const item = this.db
|
|
270
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT 1`)
|
|
271
|
+
.get(params);
|
|
241
272
|
await this.decorate(item);
|
|
242
273
|
return item;
|
|
243
274
|
}
|
|
@@ -110,9 +110,12 @@ class AbstractService {
|
|
|
110
110
|
}
|
|
111
111
|
async updatePartial(id, data) {
|
|
112
112
|
data = await this.validateInputUpdatePartial(data);
|
|
113
|
+
if (this.transformUpdatePartial) {
|
|
114
|
+
data = await this.transformUpdatePartial(data);
|
|
115
|
+
}
|
|
113
116
|
let item = await this._repository.updatePartial(id, data);
|
|
114
|
-
if (this.
|
|
115
|
-
await this.
|
|
117
|
+
if (this.onUpdatedPartial) {
|
|
118
|
+
await this.onUpdatedPartial(item);
|
|
116
119
|
}
|
|
117
120
|
item = await this.validateOutput(item);
|
|
118
121
|
return item;
|
|
@@ -155,9 +158,9 @@ class AbstractService {
|
|
|
155
158
|
throw e;
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
|
-
async findOneBy(field, value) {
|
|
161
|
+
async findOneBy(field, value, filters = []) {
|
|
159
162
|
try {
|
|
160
|
-
let item = await this._repository.findOneBy(field, value);
|
|
163
|
+
let item = await this._repository.findOneBy(field, value, filters);
|
|
161
164
|
if (item && this.transformRead) {
|
|
162
165
|
item = await this.transformRead(item);
|
|
163
166
|
}
|
|
@@ -211,9 +214,9 @@ class AbstractService {
|
|
|
211
214
|
throw e;
|
|
212
215
|
}
|
|
213
216
|
}
|
|
214
|
-
async findBy(field, value, limit = 1000) {
|
|
217
|
+
async findBy(field, value, limit = 1000, filters = []) {
|
|
215
218
|
try {
|
|
216
|
-
let items = await this._repository.findBy(field, value, limit);
|
|
219
|
+
let items = await this._repository.findBy(field, value, limit, filters);
|
|
217
220
|
if (this.transformRead) {
|
|
218
221
|
items = await Promise.all(items.map(item => this.transformRead(item)));
|
|
219
222
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "3.0.0",
|
|
7
7
|
"description": "Crud utils across modules",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "types/index.d.ts",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"author": "Cristian Incarnato & Drax Team",
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@drax/common-back": "^
|
|
26
|
-
"@drax/common-share": "^
|
|
27
|
-
"@drax/identity-share": "^
|
|
28
|
-
"@drax/media-back": "^
|
|
25
|
+
"@drax/common-back": "^3.0.0",
|
|
26
|
+
"@drax/common-share": "^3.0.0",
|
|
27
|
+
"@drax/identity-share": "^3.0.0",
|
|
28
|
+
"@drax/media-back": "^3.0.0",
|
|
29
29
|
"@graphql-tools/load-files": "^7.0.0",
|
|
30
30
|
"@graphql-tools/merge": "^9.0.4",
|
|
31
31
|
"mongoose": "^8.23.0",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"nodemon": "^3.1.0",
|
|
45
45
|
"ts-node": "^10.9.2",
|
|
46
46
|
"tsc-alias": "^1.8.10",
|
|
47
|
-
"typescript": "^5.9.3"
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"vitest": "^3.2.4"
|
|
48
49
|
},
|
|
49
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "63ae718b24ea25ae80b1a9a5dfb84a3abbb95199"
|
|
50
51
|
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
LimitError,
|
|
6
6
|
NotFoundError,
|
|
7
7
|
BadRequestError,
|
|
8
|
-
CommonController
|
|
8
|
+
CommonController, setNestedValue
|
|
9
9
|
} from "@drax/common-back";
|
|
10
10
|
import {IRbac} from "@drax/identity-share";
|
|
11
11
|
import type {FastifyReply, FastifyRequest} from "fastify";
|
|
@@ -150,17 +150,28 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
protected assertTenant(item: T, rbac: IRbac) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
|
|
154
|
+
//Si tenantAssert esta habilitado y si ademas el usuario pertenece a un tenant
|
|
155
|
+
if (this.tenantAssert && rbac.hasTenant) {
|
|
156
|
+
|
|
157
|
+
//Si esta populado
|
|
158
|
+
if(item[this.tenantField]?._id){
|
|
159
|
+
rbac.assertTenantId(item[this.tenantField]._id.toString())//
|
|
160
|
+
//Si esta crudo
|
|
161
|
+
}else if(item[this.tenantField]){
|
|
162
|
+
rbac.assertTenantId(item[this.tenantField].toString())
|
|
163
|
+
}
|
|
156
164
|
}
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
protected assertUser(item: T, rbac: IRbac) {
|
|
160
168
|
|
|
161
169
|
if (this.userAssert) {
|
|
162
|
-
|
|
163
|
-
|
|
170
|
+
if(item[this.userField]?._id){
|
|
171
|
+
rbac.assertUserId(item[this.userField]._id.toString())
|
|
172
|
+
}else if(item[this.userField]){
|
|
173
|
+
rbac.assertUserId(item[this.userField].toString())
|
|
174
|
+
}
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
177
|
|
|
@@ -170,12 +181,13 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
170
181
|
}
|
|
171
182
|
|
|
172
183
|
protected applyUserAndTenantSetters(payload: any, rbac: any) {
|
|
184
|
+
|
|
173
185
|
if (this.tenantSetter && rbac.tenantId) {
|
|
174
|
-
payload
|
|
186
|
+
setNestedValue(payload, this.tenantField, rbac.tenantId)
|
|
175
187
|
}
|
|
176
188
|
|
|
177
189
|
if (this.userSetter && rbac.userId) {
|
|
178
|
-
payload
|
|
190
|
+
setNestedValue(payload, this.userField, rbac.userId)
|
|
179
191
|
}
|
|
180
192
|
}
|
|
181
193
|
|
|
@@ -309,21 +321,24 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
309
321
|
|
|
310
322
|
let preItem = await this.service.findById(id)
|
|
311
323
|
|
|
312
|
-
if (!
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
reply.send({error: 'NOT_FOUND'})
|
|
317
|
-
}
|
|
324
|
+
if (!preItem) {
|
|
325
|
+
reply.statusCode = 404
|
|
326
|
+
reply.send({error: 'NOT_FOUND'})
|
|
327
|
+
}
|
|
318
328
|
|
|
329
|
+
if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
|
|
330
|
+
//Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
|
|
319
331
|
this.assertUser(preItem, request.rbac)
|
|
320
332
|
}
|
|
333
|
+
//Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
|
|
334
|
+
this.assertTenant(preItem, request.rbac)
|
|
321
335
|
|
|
322
|
-
//Definido el tenant
|
|
336
|
+
//Definido el tenant en create no debe modificarse en un update
|
|
323
337
|
if(this.tenantSetter) {
|
|
324
338
|
delete payload[this.tenantField]
|
|
325
339
|
}
|
|
326
340
|
|
|
341
|
+
//Definido el user en create no debe modificarse en un update
|
|
327
342
|
if(this.userSetter){
|
|
328
343
|
delete payload[this.userField]
|
|
329
344
|
}
|
|
@@ -365,21 +380,25 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
365
380
|
|
|
366
381
|
let preItem = await this.service.findById(id)
|
|
367
382
|
|
|
368
|
-
if (!
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
reply.send({error: 'NOT_FOUND'})
|
|
373
|
-
}
|
|
383
|
+
if (!preItem) {
|
|
384
|
+
reply.statusCode = 404
|
|
385
|
+
reply.send({error: 'NOT_FOUND'})
|
|
386
|
+
}
|
|
374
387
|
|
|
388
|
+
if (!request.rbac.hasSomePermission([this.permission.All, this.permission.UpdateAll])) {
|
|
389
|
+
//Si assertUser habilitado y si el usuario no tiene UpdateAll/All, solo puede modificar sus propios registros
|
|
375
390
|
this.assertUser(preItem, request.rbac)
|
|
376
391
|
}
|
|
377
392
|
|
|
378
|
-
//
|
|
393
|
+
//Si assertTenant habilitado y si usuario tiene tenant, solo puede modificar registros de su tenant
|
|
394
|
+
this.assertTenant(preItem, request.rbac)
|
|
395
|
+
|
|
396
|
+
//Definido el tenant en el create no debe modificarse en un update
|
|
379
397
|
if(this.tenantSetter) {
|
|
380
398
|
delete payload[this.tenantField]
|
|
381
399
|
}
|
|
382
400
|
|
|
401
|
+
//Definido el user en el create no debe modificarse en un update
|
|
383
402
|
if(this.userSetter){
|
|
384
403
|
delete payload[this.userField]
|
|
385
404
|
}
|
|
@@ -552,11 +571,15 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
552
571
|
const limit = this.defaultLimit
|
|
553
572
|
const field = request.params.field
|
|
554
573
|
const value = request.params.value
|
|
555
|
-
let items = await this.service.findBy(field, value, limit)
|
|
556
574
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
575
|
+
let filters = []
|
|
576
|
+
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
577
|
+
|
|
578
|
+
let items = await this.service.findBy(field, value, limit, filters)
|
|
579
|
+
|
|
580
|
+
// for (let item of items) {
|
|
581
|
+
// this.assertUserAndTenant(item, request.rbac)
|
|
582
|
+
// }
|
|
560
583
|
|
|
561
584
|
return items
|
|
562
585
|
} catch (e) {
|
|
@@ -574,8 +597,13 @@ class AbstractFastifyController<T, C, U> extends CommonController {
|
|
|
574
597
|
|
|
575
598
|
const field = request.params.field
|
|
576
599
|
const value = request.params.value
|
|
577
|
-
|
|
578
|
-
|
|
600
|
+
|
|
601
|
+
let filters = []
|
|
602
|
+
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
603
|
+
|
|
604
|
+
let item = await this.service.findOneBy(field, value, filters)
|
|
605
|
+
|
|
606
|
+
// this.assertUserAndTenant(item, request.rbac);
|
|
579
607
|
|
|
580
608
|
return item
|
|
581
609
|
} catch (e) {
|
|
@@ -122,12 +122,16 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
122
122
|
return item as T;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
async findByIds(ids: Array<string
|
|
125
|
+
async findByIds(ids: Array<string>, filters: IDraxFieldFilter[] = []): Promise<T[]> {
|
|
126
126
|
|
|
127
127
|
ids.map(id => this.assertId(id))
|
|
128
128
|
|
|
129
|
+
const query: any = {_id: {$in: ids}}
|
|
130
|
+
|
|
131
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model)
|
|
132
|
+
|
|
129
133
|
const items = await this._model
|
|
130
|
-
.find(
|
|
134
|
+
.find(query)
|
|
131
135
|
.populate(this._populateFields)
|
|
132
136
|
.lean(this._lean)
|
|
133
137
|
.exec()
|
|
@@ -136,11 +140,13 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
136
140
|
return items as T[]
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
async findOneBy(field: string, value: any): Promise<T | null> {
|
|
140
|
-
const
|
|
143
|
+
async findOneBy(field: string, value: any, filters: IDraxFieldFilter[] = []): Promise<T | null> {
|
|
144
|
+
const query: any = {[field]: value}
|
|
145
|
+
|
|
146
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model)
|
|
141
147
|
|
|
142
148
|
const item = await this._model
|
|
143
|
-
.findOne(
|
|
149
|
+
.findOne(query)
|
|
144
150
|
.populate(this._populateFields)
|
|
145
151
|
.lean(this._lean)
|
|
146
152
|
.exec()
|
|
@@ -149,10 +155,13 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
149
155
|
return item as T
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
async findBy(field: string, value: any, limit: number = 0): Promise<T[]> {
|
|
153
|
-
const
|
|
158
|
+
async findBy(field: string, value: any, limit: number = 0, filters: IDraxFieldFilter[] = []): Promise<T[]> {
|
|
159
|
+
const query: any = {[field]: value}
|
|
160
|
+
|
|
161
|
+
MongooseQueryFilter.applyFilters(query, filters, this._model)
|
|
162
|
+
|
|
154
163
|
const items = await this._model
|
|
155
|
-
.find(
|
|
164
|
+
.find(query)
|
|
156
165
|
.limit(limit)
|
|
157
166
|
.populate(this._populateFields)
|
|
158
167
|
.lean(this._lean)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import sqlite from "better-sqlite3";
|
|
2
2
|
import type {
|
|
3
|
-
IDraxCrud,
|
|
3
|
+
IDraxCrud, IDraxFieldFilter,
|
|
4
4
|
IDraxFindOptions,
|
|
5
5
|
IDraxGroupByOptions,
|
|
6
6
|
IDraxPaginateOptions,
|
|
@@ -299,7 +299,7 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
299
299
|
return items
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
async search(value: any, limit: number = 1000): Promise<T[]> {
|
|
302
|
+
async search(value: any, limit: number = 1000, filters: IDraxFieldFilter[] = []): Promise<T[]> {
|
|
303
303
|
|
|
304
304
|
let where = ""
|
|
305
305
|
let params: any[] = []
|
|
@@ -334,22 +334,73 @@ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
|
|
|
334
334
|
return item
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
async
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
async findByIds(ids: string[], filters: IDraxFieldFilter[] = []): Promise<T[] | null> {
|
|
338
|
+
|
|
339
|
+
const inPlaceholders = ids.map(() => '?').join(',')
|
|
340
|
+
|
|
341
|
+
let where = `WHERE ID IN(${inPlaceholders})`
|
|
342
|
+
let params: any[] = [ids]
|
|
343
|
+
|
|
344
|
+
if (filters.length > 0) {
|
|
345
|
+
const result = SqlQueryFilter.applyFilters(where, filters)
|
|
346
|
+
where = result.where
|
|
347
|
+
params.push(...result.params)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const items = this.db
|
|
351
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where}`)
|
|
352
|
+
.all(params) as T[]
|
|
353
|
+
|
|
341
354
|
for (const item of items) {
|
|
342
355
|
await this.decorate(item)
|
|
343
356
|
}
|
|
357
|
+
|
|
344
358
|
return items
|
|
359
|
+
|
|
345
360
|
}
|
|
346
361
|
|
|
347
|
-
async
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
362
|
+
async findBy(field: string, value: any, limit: number = 0, filters: IDraxFieldFilter[] = []): Promise<T[] | null> {
|
|
363
|
+
|
|
364
|
+
let where = `WHERE ${field} = ?`
|
|
365
|
+
let params: any[] = [value]
|
|
366
|
+
|
|
367
|
+
if (filters.length > 0) {
|
|
368
|
+
const result = SqlQueryFilter.applyFilters(where, filters)
|
|
369
|
+
where = result.where
|
|
370
|
+
params.push(...result.params)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const items = this.db
|
|
374
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT ?`)
|
|
375
|
+
.all([...params, limit]) as T[]
|
|
376
|
+
|
|
377
|
+
for (const item of items) {
|
|
378
|
+
await this.decorate(item)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return items
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async findOneBy(field: string, value: any, filters: IDraxFieldFilter[] = []): Promise<T | null> {
|
|
386
|
+
|
|
387
|
+
let where = `WHERE ${field} = ?`
|
|
388
|
+
let params: any[] = [value]
|
|
389
|
+
|
|
390
|
+
if (filters.length > 0) {
|
|
391
|
+
const result = SqlQueryFilter.applyFilters(where, filters)
|
|
392
|
+
where = result.where
|
|
393
|
+
params.push(...result.params)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const item = this.db
|
|
397
|
+
.prepare(`SELECT * FROM ${this.tableName} ${where} LIMIT 1`)
|
|
398
|
+
.get(params) as T
|
|
399
|
+
|
|
351
400
|
await this.decorate(item)
|
|
401
|
+
|
|
352
402
|
return item
|
|
403
|
+
|
|
353
404
|
}
|
|
354
405
|
|
|
355
406
|
async findOne({
|