@drax/crud-back 0.11.4 → 0.12.1
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/builders/CrudSchemaBuilder.js +349 -0
- package/dist/controllers/AbstractFastifyController.js +105 -176
- package/dist/index.js +15 -1
- package/dist/regexs/QueryFilterRegex.js +3 -0
- package/dist/repository/AbstractMongoRepository.js +114 -28
- package/dist/repository/AbstractSqliteRepository.js +131 -41
- package/dist/schemas/DeleteBodyResponseSchema.js +9 -0
- package/dist/schemas/ErrorBodyResponseSchema.js +16 -0
- package/dist/schemas/ExportBodyResponseSchema.js +9 -0
- package/dist/schemas/FindBySchema.js +6 -0
- package/dist/schemas/FindSchema.js +9 -0
- package/dist/schemas/IdParamSchema.js +6 -0
- package/dist/schemas/PaginateBodySchema.js +20 -0
- package/dist/schemas/PaginateSchema.js +17 -0
- package/dist/schemas/SearchSchema.js +5 -0
- package/dist/services/AbstractService.js +8 -5
- package/dist/zod/DeleteBodySchema.js +6 -0
- package/dist/zod/IdParamSchema.js +6 -0
- package/dist/zod/PaginateBodySchema.js +20 -0
- package/package.json +7 -6
- package/src/builders/CrudSchemaBuilder.ts +420 -0
- package/src/controllers/AbstractFastifyController.ts +149 -165
- package/src/index.ts +28 -0
- package/src/regexs/QueryFilterRegex.ts +4 -0
- package/src/repository/AbstractMongoRepository.ts +153 -40
- package/src/repository/AbstractSqliteRepository.ts +196 -72
- package/src/schemas/DeleteBodyResponseSchema.ts +12 -0
- package/src/schemas/ErrorBodyResponseSchema.ts +20 -0
- package/src/schemas/ExportBodyResponseSchema.ts +12 -0
- package/src/schemas/FindBySchema.ts +9 -0
- package/src/schemas/FindSchema.ts +13 -0
- package/src/schemas/IdParamSchema.ts +9 -0
- package/src/schemas/PaginateSchema.ts +21 -0
- package/src/schemas/SearchSchema.ts +8 -0
- package/src/services/AbstractService.ts +42 -33
- package/tsconfig.tsbuildinfo +1 -1
- package/types/builders/CrudSchemaBuilder.d.ts +2401 -0
- package/types/builders/CrudSchemaBuilder.d.ts.map +1 -0
- package/types/controllers/AbstractFastifyController.d.ts +6 -1
- package/types/controllers/AbstractFastifyController.d.ts.map +1 -1
- package/types/index.d.ts +10 -1
- package/types/index.d.ts.map +1 -1
- package/types/regexs/QueryFilterRegex.d.ts +4 -0
- package/types/regexs/QueryFilterRegex.d.ts.map +1 -0
- package/types/repository/AbstractMongoRepository.d.ts +6 -3
- package/types/repository/AbstractMongoRepository.d.ts.map +1 -1
- package/types/repository/AbstractSqliteRepository.d.ts +23 -8
- package/types/repository/AbstractSqliteRepository.d.ts.map +1 -1
- package/types/schemas/DeleteBodyResponseSchema.d.ts +20 -0
- package/types/schemas/DeleteBodyResponseSchema.d.ts.map +1 -0
- package/types/schemas/ErrorBodyResponseSchema.d.ts +60 -0
- package/types/schemas/ErrorBodyResponseSchema.d.ts.map +1 -0
- package/types/schemas/ExportBodyResponseSchema.d.ts +20 -0
- package/types/schemas/ExportBodyResponseSchema.d.ts.map +1 -0
- package/types/schemas/FindBySchema.d.ts +13 -0
- package/types/schemas/FindBySchema.d.ts.map +1 -0
- package/types/schemas/FindSchema.d.ts +19 -0
- package/types/schemas/FindSchema.d.ts.map +1 -0
- package/types/schemas/IdParamSchema.d.ts +11 -0
- package/types/schemas/IdParamSchema.d.ts.map +1 -0
- package/types/schemas/PaginateBodySchema.d.ts +61 -0
- package/types/schemas/PaginateBodySchema.d.ts.map +1 -0
- package/types/schemas/PaginateSchema.d.ts +41 -0
- package/types/schemas/PaginateSchema.d.ts.map +1 -0
- package/types/schemas/SearchSchema.d.ts +10 -0
- package/types/schemas/SearchSchema.d.ts.map +1 -0
- package/types/services/AbstractService.d.ts +5 -5
- package/types/services/AbstractService.d.ts.map +1 -1
- package/types/zod/DeleteBodySchema.d.ts +11 -0
- package/types/zod/DeleteBodySchema.d.ts.map +1 -0
- package/types/zod/IdParamSchema.d.ts +11 -0
- package/types/zod/IdParamSchema.d.ts.map +1 -0
- package/types/zod/PaginateBodySchema.d.ts +61 -0
- package/types/zod/PaginateBodySchema.d.ts.map +1 -0
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import AbstractService from "../services/AbstractService";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
CommonConfig,
|
|
4
|
+
DraxConfig,
|
|
5
|
+
ForbiddenError,
|
|
6
|
+
InternalServerError,
|
|
7
|
+
InvalidIdError,
|
|
8
|
+
LimitError,
|
|
9
|
+
NotFoundError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
SecuritySensitiveError,
|
|
12
|
+
UploadFileError,
|
|
13
|
+
BadRequestError
|
|
14
|
+
} from "@drax/common-back";
|
|
3
15
|
import {UnauthorizedError} from "@drax/common-back";
|
|
4
16
|
import {IRbac} from "@drax/identity-share";
|
|
5
17
|
import type {FastifyReply, FastifyRequest} from "fastify";
|
|
6
18
|
import {IDraxExportResult, IDraxPermission, IDraxFieldFilter} from "@drax/crud-share";
|
|
7
19
|
import {join} from "path";
|
|
20
|
+
import QueryFilterRegex from "../regexs/QueryFilterRegex.js";
|
|
8
21
|
|
|
9
22
|
declare module 'fastify' {
|
|
10
23
|
interface FastifyRequest {
|
|
@@ -25,7 +38,7 @@ type CustomRequest = FastifyRequest<{
|
|
|
25
38
|
page?: number
|
|
26
39
|
limit?: number
|
|
27
40
|
orderBy?: string
|
|
28
|
-
order?: 'asc' | 'desc'
|
|
41
|
+
order?: 'asc' | 'desc'
|
|
29
42
|
search?: string
|
|
30
43
|
filters?: string
|
|
31
44
|
headers?: string
|
|
@@ -54,6 +67,9 @@ class AbstractFastifyController<T, C, U> {
|
|
|
54
67
|
protected tenantAssert: boolean = false
|
|
55
68
|
protected userAssert: boolean = false
|
|
56
69
|
|
|
70
|
+
protected defaultLimit: number = 1000
|
|
71
|
+
protected maximumLimit: number = 10000
|
|
72
|
+
|
|
57
73
|
constructor(service: AbstractService<T, C, U>, permission: IDraxPermission) {
|
|
58
74
|
this.service = service
|
|
59
75
|
this.permission = permission
|
|
@@ -65,6 +81,11 @@ class AbstractFastifyController<T, C, U> {
|
|
|
65
81
|
if (!stringFilters) {
|
|
66
82
|
return []
|
|
67
83
|
}
|
|
84
|
+
|
|
85
|
+
if (!QueryFilterRegex.test(stringFilters)) {
|
|
86
|
+
throw new BadRequestError("Invalid filters format")
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
const filterArray = stringFilters.split("|")
|
|
69
90
|
const filters: IDraxFieldFilter[] = []
|
|
70
91
|
filterArray.forEach((filter) => {
|
|
@@ -73,12 +94,12 @@ class AbstractFastifyController<T, C, U> {
|
|
|
73
94
|
})
|
|
74
95
|
return filters
|
|
75
96
|
} catch (e) {
|
|
76
|
-
console.error(e)
|
|
97
|
+
console.error("parseFilters error",e)
|
|
77
98
|
throw e
|
|
78
99
|
}
|
|
79
100
|
}
|
|
80
101
|
|
|
81
|
-
private applyUserAndTenantFilters(filters: IDraxFieldFilter[], rbac:
|
|
102
|
+
private applyUserAndTenantFilters(filters: IDraxFieldFilter[], rbac: IRbac) {
|
|
82
103
|
if (this.tenantFilter && rbac.tenantId) {
|
|
83
104
|
filters.push({field: this.tenantField, operator: 'eq', value: rbac.tenantId})
|
|
84
105
|
}
|
|
@@ -88,6 +109,18 @@ class AbstractFastifyController<T, C, U> {
|
|
|
88
109
|
}
|
|
89
110
|
}
|
|
90
111
|
|
|
112
|
+
private assertUserAndTenant(item: T, rbac: IRbac) {
|
|
113
|
+
if (this.tenantAssert) {
|
|
114
|
+
const itemTenantId = item[this.tenantField] && item[this.tenantField]._id ? item[this.tenantField]._id : null
|
|
115
|
+
rbac.assertTenantId(itemTenantId)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (this.userAssert) {
|
|
119
|
+
const itemUserId = item[this.userField] && item[this.userField]._id ? item[this.userField]._id : null
|
|
120
|
+
rbac.assertUserId(itemUserId)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
91
124
|
private applyUserAndTenantSetters(payload: any, rbac: any) {
|
|
92
125
|
if (this.tenantSetter && rbac.tenantId) {
|
|
93
126
|
payload[this.tenantField] = rbac.tenantId
|
|
@@ -98,6 +131,28 @@ class AbstractFastifyController<T, C, U> {
|
|
|
98
131
|
}
|
|
99
132
|
}
|
|
100
133
|
|
|
134
|
+
handleError(e: unknown, reply: FastifyReply) {
|
|
135
|
+
console.error(e);
|
|
136
|
+
|
|
137
|
+
if (
|
|
138
|
+
e instanceof ValidationError ||
|
|
139
|
+
e instanceof NotFoundError ||
|
|
140
|
+
e instanceof BadRequestError ||
|
|
141
|
+
e instanceof UnauthorizedError ||
|
|
142
|
+
e instanceof ForbiddenError ||
|
|
143
|
+
e instanceof InvalidIdError ||
|
|
144
|
+
e instanceof SecuritySensitiveError ||
|
|
145
|
+
e instanceof UploadFileError ||
|
|
146
|
+
e instanceof LimitError
|
|
147
|
+
) {
|
|
148
|
+
reply.status(e.statusCode).send(e.body);
|
|
149
|
+
} else {
|
|
150
|
+
const serverError = new InternalServerError()
|
|
151
|
+
reply.statusCode = serverError.statusCode
|
|
152
|
+
reply.status(500).send(serverError.body);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
101
156
|
async create(request: CustomRequest, reply: FastifyReply) {
|
|
102
157
|
try {
|
|
103
158
|
request.rbac.assertPermission(this.permission.Create)
|
|
@@ -106,17 +161,7 @@ class AbstractFastifyController<T, C, U> {
|
|
|
106
161
|
let item = await this.service.create(payload as C)
|
|
107
162
|
return item
|
|
108
163
|
} catch (e) {
|
|
109
|
-
|
|
110
|
-
if (e instanceof ValidationError) {
|
|
111
|
-
reply.statusCode = e.statusCode
|
|
112
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
113
|
-
} else if (e instanceof UnauthorizedError) {
|
|
114
|
-
reply.statusCode = e.statusCode
|
|
115
|
-
reply.send({error: e.message})
|
|
116
|
-
} else {
|
|
117
|
-
reply.statusCode = 500
|
|
118
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
119
|
-
}
|
|
164
|
+
this.handleError(e, reply)
|
|
120
165
|
}
|
|
121
166
|
}
|
|
122
167
|
|
|
@@ -131,19 +176,34 @@ class AbstractFastifyController<T, C, U> {
|
|
|
131
176
|
const payload = request.body
|
|
132
177
|
//this.applyUserAndTenantSetters(payload, request.rbac)
|
|
133
178
|
let item = await this.service.update(id, payload as U)
|
|
179
|
+
|
|
180
|
+
if (!item) {
|
|
181
|
+
throw new NotFoundError()
|
|
182
|
+
}
|
|
183
|
+
|
|
134
184
|
return item
|
|
135
185
|
} catch (e) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
reply.statusCode =
|
|
145
|
-
reply.send({error: '
|
|
186
|
+
this.handleError(e, reply)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async updatePartial(request: CustomRequest, reply: FastifyReply) {
|
|
191
|
+
try {
|
|
192
|
+
request.rbac.assertPermission(this.permission.Update)
|
|
193
|
+
if (!request.params.id) {
|
|
194
|
+
reply.statusCode = 400
|
|
195
|
+
reply.send({error: 'BAD REQUEST'})
|
|
146
196
|
}
|
|
197
|
+
const id = request.params.id
|
|
198
|
+
const payload = request.body
|
|
199
|
+
//this.applyUserAndTenantSetters(payload, request.rbac)
|
|
200
|
+
let item = await this.service.updatePartial(id, payload as U)
|
|
201
|
+
if (!item) {
|
|
202
|
+
throw new NotFoundError()
|
|
203
|
+
}
|
|
204
|
+
return item
|
|
205
|
+
} catch (e) {
|
|
206
|
+
this.handleError(e, reply)
|
|
147
207
|
}
|
|
148
208
|
}
|
|
149
209
|
|
|
@@ -158,33 +218,29 @@ class AbstractFastifyController<T, C, U> {
|
|
|
158
218
|
|
|
159
219
|
let item = await this.service.findById(id)
|
|
160
220
|
|
|
161
|
-
if(!item) {
|
|
221
|
+
if (!item) {
|
|
162
222
|
reply.statusCode = 404
|
|
163
223
|
reply.send({error: 'NOT_FOUND'})
|
|
164
224
|
}
|
|
165
225
|
|
|
166
226
|
if (this.tenantAssert) {
|
|
167
|
-
|
|
227
|
+
const tenantId = item[this.tenantField] && item[this.tenantField]._id ? item[this.tenantField]._id : null
|
|
228
|
+
request.rbac.assertTenantId(tenantId)
|
|
168
229
|
}
|
|
169
230
|
|
|
170
231
|
await this.service.delete(id)
|
|
171
|
-
reply.send({
|
|
232
|
+
reply.send({
|
|
233
|
+
id: id,
|
|
234
|
+
message: 'Item deleted successfully',
|
|
235
|
+
deleted: true,
|
|
236
|
+
deletedAt: new Date(),
|
|
237
|
+
})
|
|
172
238
|
} catch (e) {
|
|
173
|
-
|
|
174
|
-
if (e instanceof ValidationError) {
|
|
175
|
-
reply.statusCode = e.statusCode
|
|
176
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
177
|
-
} else if (e instanceof UnauthorizedError) {
|
|
178
|
-
reply.statusCode = e.statusCode
|
|
179
|
-
reply.send({error: e.message})
|
|
180
|
-
} else {
|
|
181
|
-
reply.statusCode = 500
|
|
182
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
183
|
-
}
|
|
239
|
+
this.handleError(e, reply)
|
|
184
240
|
}
|
|
185
241
|
}
|
|
186
242
|
|
|
187
|
-
async findById(request: CustomRequest, reply: FastifyReply)
|
|
243
|
+
async findById(request: CustomRequest, reply: FastifyReply): Promise<T> {
|
|
188
244
|
try {
|
|
189
245
|
request.rbac.assertPermission(this.permission.View)
|
|
190
246
|
if (!request.params.id) {
|
|
@@ -196,27 +252,22 @@ class AbstractFastifyController<T, C, U> {
|
|
|
196
252
|
const id = request.params.id
|
|
197
253
|
let item = await this.service.findById(id)
|
|
198
254
|
|
|
255
|
+
if (!item) {
|
|
256
|
+
throw new NotFoundError()
|
|
257
|
+
}
|
|
258
|
+
|
|
199
259
|
if (this.tenantAssert) {
|
|
200
|
-
|
|
260
|
+
const itemTenantId = item[this.tenantField] && item[this.tenantField]._id? item[this.tenantField]._id : null
|
|
261
|
+
request.rbac.assertTenantId(itemTenantId)
|
|
201
262
|
}
|
|
202
263
|
|
|
203
264
|
return item
|
|
204
265
|
} catch (e) {
|
|
205
|
-
|
|
206
|
-
if (e instanceof ValidationError) {
|
|
207
|
-
reply.statusCode = e.statusCode
|
|
208
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
209
|
-
} else if (e instanceof UnauthorizedError) {
|
|
210
|
-
reply.statusCode = e.statusCode
|
|
211
|
-
reply.send({error: e.message})
|
|
212
|
-
} else {
|
|
213
|
-
reply.statusCode = 500
|
|
214
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
215
|
-
}
|
|
266
|
+
this.handleError(e, reply)
|
|
216
267
|
}
|
|
217
268
|
}
|
|
218
269
|
|
|
219
|
-
async findByIds(request: CustomRequest, reply: FastifyReply):Promise<T[]> {
|
|
270
|
+
async findByIds(request: CustomRequest, reply: FastifyReply): Promise<T[]> {
|
|
220
271
|
try {
|
|
221
272
|
request.rbac.assertPermission(this.permission.View)
|
|
222
273
|
if (!request.params.ids) {
|
|
@@ -225,53 +276,42 @@ class AbstractFastifyController<T, C, U> {
|
|
|
225
276
|
}
|
|
226
277
|
const ids = request.params.ids.split(",")
|
|
227
278
|
let items = await this.service.findByIds(ids)
|
|
279
|
+
|
|
280
|
+
if (!items || items.length === 0) {
|
|
281
|
+
throw new NotFoundError()
|
|
282
|
+
}
|
|
283
|
+
|
|
228
284
|
return items
|
|
229
285
|
} catch (e) {
|
|
230
|
-
|
|
231
|
-
if (e instanceof ValidationError) {
|
|
232
|
-
reply.statusCode = e.statusCode
|
|
233
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
234
|
-
} else if (e instanceof UnauthorizedError) {
|
|
235
|
-
reply.statusCode = e.statusCode
|
|
236
|
-
reply.send({error: e.message})
|
|
237
|
-
} else {
|
|
238
|
-
reply.statusCode = 500
|
|
239
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
240
|
-
}
|
|
286
|
+
this.handleError(e, reply)
|
|
241
287
|
}
|
|
242
288
|
}
|
|
243
289
|
|
|
244
|
-
async find(request: CustomRequest, reply: FastifyReply):Promise<T[]> {
|
|
290
|
+
async find(request: CustomRequest, reply: FastifyReply): Promise<T[]> {
|
|
245
291
|
try {
|
|
246
292
|
request.rbac.assertPermission(this.permission.View)
|
|
247
293
|
|
|
294
|
+
if (request.query.limit > this.maximumLimit) {
|
|
295
|
+
throw new LimitError(this.maximumLimit, request.query.limit)
|
|
296
|
+
}
|
|
297
|
+
const limit = request.query.limit ? request.query.limit : this.defaultLimit
|
|
298
|
+
const orderBy = request.query.orderBy
|
|
299
|
+
const order = request.query.order
|
|
248
300
|
const search = request.query.search ??= undefined
|
|
249
301
|
const filters = this.parseFilters(request.query.filters)
|
|
250
302
|
|
|
251
303
|
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
252
304
|
|
|
253
|
-
let items = await this.service.find({search,filters})
|
|
305
|
+
let items = await this.service.find({search, filters, order, orderBy, limit})
|
|
306
|
+
|
|
254
307
|
|
|
255
|
-
if (this.tenantAssert) {
|
|
256
|
-
items = items.filter(item => request.rbac.tenantId === item[this.tenantField].id)
|
|
257
|
-
}
|
|
258
308
|
return items
|
|
259
309
|
} catch (e) {
|
|
260
|
-
|
|
261
|
-
if (e instanceof ValidationError) {
|
|
262
|
-
reply.statusCode = e.statusCode
|
|
263
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
264
|
-
} else if (e instanceof UnauthorizedError) {
|
|
265
|
-
reply.statusCode = e.statusCode
|
|
266
|
-
reply.send({error: e.message})
|
|
267
|
-
} else {
|
|
268
|
-
reply.statusCode = 500
|
|
269
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
270
|
-
}
|
|
310
|
+
this.handleError(e, reply)
|
|
271
311
|
}
|
|
272
312
|
}
|
|
273
313
|
|
|
274
|
-
async findOne(request: CustomRequest, reply: FastifyReply):Promise<T> {
|
|
314
|
+
async findOne(request: CustomRequest, reply: FastifyReply): Promise<T> {
|
|
275
315
|
try {
|
|
276
316
|
request.rbac.assertPermission(this.permission.View)
|
|
277
317
|
|
|
@@ -280,29 +320,16 @@ class AbstractFastifyController<T, C, U> {
|
|
|
280
320
|
|
|
281
321
|
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
282
322
|
|
|
283
|
-
let item = await this.service.findOne({search,filters})
|
|
323
|
+
let item = await this.service.findOne({search, filters})
|
|
284
324
|
|
|
285
|
-
if (this.tenantAssert) {
|
|
286
|
-
request.rbac.assertTenantId(item[this.tenantField].id)
|
|
287
|
-
}
|
|
288
325
|
|
|
289
326
|
return item
|
|
290
327
|
} catch (e) {
|
|
291
|
-
|
|
292
|
-
if (e instanceof ValidationError) {
|
|
293
|
-
reply.statusCode = e.statusCode
|
|
294
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
295
|
-
} else if (e instanceof UnauthorizedError) {
|
|
296
|
-
reply.statusCode = e.statusCode
|
|
297
|
-
reply.send({error: e.message})
|
|
298
|
-
} else {
|
|
299
|
-
reply.statusCode = 500
|
|
300
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
301
|
-
}
|
|
328
|
+
this.handleError(e, reply)
|
|
302
329
|
}
|
|
303
330
|
}
|
|
304
331
|
|
|
305
|
-
async findBy(request: CustomRequest, reply: FastifyReply):Promise<T[]> {
|
|
332
|
+
async findBy(request: CustomRequest, reply: FastifyReply): Promise<T[]> {
|
|
306
333
|
try {
|
|
307
334
|
request.rbac.assertPermission(this.permission.View)
|
|
308
335
|
if (!request.params.field || !request.params.value) {
|
|
@@ -310,30 +337,22 @@ class AbstractFastifyController<T, C, U> {
|
|
|
310
337
|
reply.send({error: 'BAD REQUEST'})
|
|
311
338
|
}
|
|
312
339
|
|
|
340
|
+
const limit = this.defaultLimit
|
|
313
341
|
const field = request.params.field
|
|
314
342
|
const value = request.params.value
|
|
315
|
-
let items = await this.service.findBy(field,value)
|
|
343
|
+
let items = await this.service.findBy(field, value, limit)
|
|
316
344
|
|
|
317
|
-
|
|
318
|
-
|
|
345
|
+
for (let item of items) {
|
|
346
|
+
this.assertUserAndTenant(item, request.rbac)
|
|
319
347
|
}
|
|
348
|
+
|
|
320
349
|
return items
|
|
321
350
|
} catch (e) {
|
|
322
|
-
|
|
323
|
-
if (e instanceof ValidationError) {
|
|
324
|
-
reply.statusCode = e.statusCode
|
|
325
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
326
|
-
} else if (e instanceof UnauthorizedError) {
|
|
327
|
-
reply.statusCode = e.statusCode
|
|
328
|
-
reply.send({error: e.message})
|
|
329
|
-
} else {
|
|
330
|
-
reply.statusCode = 500
|
|
331
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
332
|
-
}
|
|
351
|
+
this.handleError(e, reply)
|
|
333
352
|
}
|
|
334
353
|
}
|
|
335
354
|
|
|
336
|
-
async findOneBy(request: CustomRequest, reply: FastifyReply):Promise<T> {
|
|
355
|
+
async findOneBy(request: CustomRequest, reply: FastifyReply): Promise<T> {
|
|
337
356
|
try {
|
|
338
357
|
request.rbac.assertPermission(this.permission.View)
|
|
339
358
|
if (!request.params.field || !request.params.value) {
|
|
@@ -343,59 +362,44 @@ class AbstractFastifyController<T, C, U> {
|
|
|
343
362
|
|
|
344
363
|
const field = request.params.field
|
|
345
364
|
const value = request.params.value
|
|
346
|
-
let item = await this.service.findOneBy(field,value)
|
|
347
|
-
|
|
348
|
-
if (this.tenantAssert) {
|
|
349
|
-
request.rbac.assertTenantId(item[this.tenantField].id)
|
|
350
|
-
}
|
|
365
|
+
let item = await this.service.findOneBy(field, value)
|
|
366
|
+
this.assertUserAndTenant(item, request.rbac);
|
|
351
367
|
|
|
352
368
|
return item
|
|
353
369
|
} catch (e) {
|
|
354
|
-
|
|
355
|
-
if (e instanceof ValidationError) {
|
|
356
|
-
reply.statusCode = e.statusCode
|
|
357
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
358
|
-
} else if (e instanceof UnauthorizedError) {
|
|
359
|
-
reply.statusCode = e.statusCode
|
|
360
|
-
reply.send({error: e.message})
|
|
361
|
-
} else {
|
|
362
|
-
reply.statusCode = 500
|
|
363
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
364
|
-
}
|
|
370
|
+
this.handleError(e, reply)
|
|
365
371
|
}
|
|
366
372
|
}
|
|
367
373
|
|
|
374
|
+
|
|
375
|
+
|
|
368
376
|
async search(request: CustomRequest, reply: FastifyReply) {
|
|
369
377
|
try {
|
|
370
378
|
request.rbac.assertPermission(this.permission.View)
|
|
371
379
|
const search = request.query.search
|
|
372
|
-
const
|
|
373
|
-
const
|
|
380
|
+
const filters = []
|
|
381
|
+
const limit = this.defaultLimit
|
|
374
382
|
|
|
375
383
|
this.applyUserAndTenantFilters(filters, request.rbac);
|
|
376
384
|
|
|
377
385
|
let item = await this.service.search(search, limit, filters)
|
|
378
386
|
return item
|
|
379
387
|
} catch (e) {
|
|
380
|
-
|
|
381
|
-
if (e instanceof ValidationError) {
|
|
382
|
-
reply.statusCode = e.statusCode
|
|
383
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
384
|
-
} else if (e instanceof UnauthorizedError) {
|
|
385
|
-
reply.statusCode = e.statusCode
|
|
386
|
-
reply.send({error: e.message})
|
|
387
|
-
} else {
|
|
388
|
-
reply.statusCode = 500
|
|
389
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
390
|
-
}
|
|
388
|
+
this.handleError(e, reply)
|
|
391
389
|
}
|
|
392
390
|
}
|
|
393
391
|
|
|
394
392
|
async paginate(request: CustomRequest, reply: FastifyReply) {
|
|
395
393
|
try {
|
|
396
394
|
request.rbac.assertPermission(this.permission.View)
|
|
397
|
-
|
|
398
|
-
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
if (request.query.limit > this.maximumLimit) {
|
|
398
|
+
throw new LimitError(this.maximumLimit, request.query.limit)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const page = request.query.page ? request.query.page : 1
|
|
402
|
+
const limit = request.query.limit ? request.query.limit : 10
|
|
399
403
|
const orderBy = request.query.orderBy
|
|
400
404
|
const order = request.query.order
|
|
401
405
|
const search = request.query.search
|
|
@@ -407,17 +411,7 @@ class AbstractFastifyController<T, C, U> {
|
|
|
407
411
|
let paginateResult = await this.service.paginate({page, limit, orderBy, order, search, filters})
|
|
408
412
|
return paginateResult
|
|
409
413
|
} catch (e) {
|
|
410
|
-
|
|
411
|
-
if (e instanceof ValidationError) {
|
|
412
|
-
reply.statusCode = e.statusCode
|
|
413
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
414
|
-
} else if (e instanceof UnauthorizedError) {
|
|
415
|
-
reply.statusCode = e.statusCode
|
|
416
|
-
reply.send({error: e.message})
|
|
417
|
-
} else {
|
|
418
|
-
reply.statusCode = 500
|
|
419
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
420
|
-
}
|
|
414
|
+
this.handleError(e, reply)
|
|
421
415
|
}
|
|
422
416
|
}
|
|
423
417
|
|
|
@@ -465,17 +459,7 @@ class AbstractFastifyController<T, C, U> {
|
|
|
465
459
|
}
|
|
466
460
|
|
|
467
461
|
} catch (e) {
|
|
468
|
-
|
|
469
|
-
if (e instanceof ValidationError) {
|
|
470
|
-
reply.statusCode = e.statusCode
|
|
471
|
-
reply.send({error: e.message, inputErrors: e.errors})
|
|
472
|
-
} else if (e instanceof UnauthorizedError) {
|
|
473
|
-
reply.statusCode = e.statusCode
|
|
474
|
-
reply.send({error: e.message})
|
|
475
|
-
} else {
|
|
476
|
-
reply.statusCode = 500
|
|
477
|
-
reply.send({error: 'INTERNAL_SERVER_ERROR'})
|
|
478
|
-
}
|
|
462
|
+
this.handleError(e, reply)
|
|
479
463
|
}
|
|
480
464
|
}
|
|
481
465
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,17 @@ import AbstractSqliteRepository from "./repository/AbstractSqliteRepository.js";
|
|
|
4
4
|
import AbstractService from "./services/AbstractService.js";
|
|
5
5
|
import AbstractFastifyController from "./controllers/AbstractFastifyController.js";
|
|
6
6
|
|
|
7
|
+
//schemas
|
|
8
|
+
import {IdParamSchema} from "./schemas/IdParamSchema.js"
|
|
9
|
+
import {DeleteBodyResponseSchema} from "./schemas/DeleteBodyResponseSchema.js"
|
|
10
|
+
import {PaginateBodyResponseSchema, PaginateQuerySchema} from "./schemas/PaginateSchema.js"
|
|
11
|
+
import {FindQuerySchema} from "./schemas/FindSchema.js"
|
|
12
|
+
import {SearchQuerySchema} from "./schemas/SearchSchema.js"
|
|
13
|
+
import {FindByParamSchema} from "./schemas/FindBySchema.js"
|
|
14
|
+
import {ExportBodyResponseSchema} from "./schemas/ExportBodyResponseSchema.js"
|
|
15
|
+
import {ErrorBodyResponseSchema, ValidationErrorBodyResponseSchema} from "./schemas/ErrorBodyResponseSchema.js"
|
|
16
|
+
import {CrudSchemaBuilder} from "./builders/CrudSchemaBuilder.js";
|
|
17
|
+
|
|
7
18
|
|
|
8
19
|
export {
|
|
9
20
|
|
|
@@ -13,4 +24,21 @@ export {
|
|
|
13
24
|
AbstractService,
|
|
14
25
|
AbstractFastifyController,
|
|
15
26
|
|
|
27
|
+
|
|
28
|
+
//Schemas
|
|
29
|
+
IdParamSchema,
|
|
30
|
+
DeleteBodyResponseSchema,
|
|
31
|
+
PaginateBodyResponseSchema,
|
|
32
|
+
PaginateQuerySchema,
|
|
33
|
+
FindQuerySchema,
|
|
34
|
+
SearchQuerySchema,
|
|
35
|
+
FindByParamSchema,
|
|
36
|
+
ErrorBodyResponseSchema,
|
|
37
|
+
ValidationErrorBodyResponseSchema,
|
|
38
|
+
ExportBodyResponseSchema,
|
|
39
|
+
|
|
40
|
+
//Builder
|
|
41
|
+
CrudSchemaBuilder,
|
|
42
|
+
|
|
43
|
+
|
|
16
44
|
}
|