identity-admin 1.9.1 → 1.11.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.
Files changed (37) hide show
  1. package/lib/controllers/DashboardController.d.ts +1 -1
  2. package/lib/controllers/DashboardController.js +94 -15
  3. package/lib/controllers/ResourceController.js +15 -10
  4. package/lib/helpers/ActionsGenerator.d.ts +2 -1
  5. package/lib/helpers/ActionsGenerator.js +12 -4
  6. package/lib/helpers/ResourceGenerator.d.ts +2 -1
  7. package/lib/helpers/ResourceGenerator.js +2 -2
  8. package/lib/helpers/ResourceHelper.d.ts +4 -0
  9. package/lib/helpers/ResourceHelper.js +75 -12
  10. package/lib/locales/en.json +2 -1
  11. package/lib/router/index.js +3 -0
  12. package/lib/types/IResourceFile.d.ts +281 -80
  13. package/lib/types/IResourceResponse.d.ts +99 -0
  14. package/lib/types/IResourceResponse.js +2 -0
  15. package/lib/types/helpers.d.ts +12 -0
  16. package/lib/types/helpers.js +14 -1
  17. package/lib/utils/ResponseUtils.d.ts +1 -0
  18. package/lib/utils/ResponseUtils.js +3 -0
  19. package/lib/view/asset-manifest.json +13 -8
  20. package/lib/view/index.html +52 -1
  21. package/lib/view/static/css/main.54de06ef.css +2 -0
  22. package/lib/view/static/css/main.54de06ef.css.map +1 -0
  23. package/lib/view/static/js/{148.b05fe2c8.chunk.js → 574.778b5963.chunk.js} +2 -1
  24. package/lib/view/static/js/574.778b5963.chunk.js.map +1 -0
  25. package/lib/view/static/js/678.521704a3.chunk.js +2 -0
  26. package/lib/view/static/js/678.521704a3.chunk.js.map +1 -0
  27. package/lib/view/static/js/798.54856416.chunk.js +2 -0
  28. package/lib/view/static/js/798.54856416.chunk.js.map +1 -0
  29. package/lib/view/static/js/admin.js +1 -0
  30. package/lib/view/static/js/main.4687f255.js +3 -0
  31. package/lib/view/static/js/{main.da8f09ec.js.LICENSE.txt → main.4687f255.js.LICENSE.txt} +4 -15
  32. package/lib/view/static/js/main.4687f255.js.map +1 -0
  33. package/package.json +1 -1
  34. package/lib/view/static/css/main.18dca458.css +0 -1
  35. package/lib/view/static/js/705.f86db82e.chunk.js +0 -1
  36. package/lib/view/static/js/802.3f287a2c.chunk.js +0 -1
  37. package/lib/view/static/js/main.da8f09ec.js +0 -2
@@ -1,71 +1,79 @@
1
1
  import { Request } from "express";
2
2
  import { Document, Model } from "mongoose";
3
3
  import { IRequest } from "../middlewares/isAuth";
4
- import { ActionTypes, FieldTypes, Virtuals } from "./helpers";
4
+ import { IRepository } from "../repositories/Repository";
5
+ import { ActionNames, ActionTypes, FieldTypes, FileTypes, Virtuals } from "./helpers";
5
6
  declare type orderTypes = 'asc' | 'desc';
6
7
  declare type VirtualFieldTypes = 'password' | 'ref' | 'Array';
7
8
  declare type Severity = 'success' | 'info' | 'warning' | 'error';
8
- interface IAutoScope {
9
- /**
10
- * Key of property as specified in the database
11
- */
12
- key: string;
13
- /**
14
- * Array of values that this key can have
15
- */
16
- options: string[];
17
- }
18
- interface IManualScope {
19
- /**
20
- * Array of values that will be appeared in the scope
21
- */
22
- options: string[];
23
- /**
24
- * A handler that will be called when scope filter is used. This handler should perform a switch case on the specified options values, each case set the filter on its way.
25
- */
26
- handler: (filter: {
27
- [key: string]: any;
28
- }, scope: string) => {
29
- [key: string]: any;
30
- };
31
- }
32
9
  interface Parent {
33
10
  /**
34
- * Name of the parent
35
- */
11
+ * Name of the parent
12
+ */
36
13
  name: string;
37
14
  /**
38
- * Icon of the parent. You can get the icons from
39
- * @link https://mui.com/material-ui/material-icons/
40
- */
15
+ * Icon of the parent. You can get the icons from
16
+ * {@link https://mui.com/material-ui/material-icons/}
17
+ */
41
18
  icon: string;
42
19
  }
43
20
  interface Action {
44
21
  /**
45
- * Specify if this action is accessible or not.
46
- * @default True is the default for show, edit, delete, and new while false for bulk delete. You can ovveride any of these values here.
47
- */
22
+ * Specify if this action is accessible or not.
23
+ * @default True for show, edit, delete, and new.
24
+ * @default false for bulk delete.
25
+ * You can ovveride any of these values here.
26
+ */
48
27
  isAccessible?: boolean;
28
+ /**
29
+ * The property that manages which admin role can use this action.
30
+ * This function's result alters the isAccessible value. So no need to use both properties.
31
+ * If both are used then isAccessible has the higher priority.
32
+ * @default 'Same as isAccessible'
33
+ */
34
+ isAllowed?: (currentUser: Document) => boolean;
49
35
  }
50
36
  interface ICrudOperations {
51
37
  index?: {
52
38
  /**
53
- * Before handler that gives you the access to the filter object. You can add to the filter object any key and value that will be used in the filter query before getting the records for list. You should return the filter object
54
- */
55
- before: (req: IRequest, filter: {
39
+ * Before handler that gives you the access to the filter object.
40
+ * You can add to the filter object any key and value that will be used in the filter query before getting the records for list.
41
+ * @returns the filter object
42
+ */
43
+ before?: (req: IRequest, filter: {
56
44
  [key: string]: any;
57
- }, currentUser: Document) => {
45
+ }, currentUser: Document) => Promise<{
58
46
  [key: string]: any;
59
- };
47
+ }>;
48
+ /**
49
+ * After handler that gives you the access to the array of documents.
50
+ * @returns the array of documents
51
+ */
52
+ after?: (req: IRequest, documents: Document[], currentUser: Document) => Promise<Document[]>;
60
53
  };
61
54
  create?: {
62
55
  /**
63
- * Before handler that is called before creating a new record. This function gives you the access to the record params before saving it, you can perform any update to the params before saving it. This function should return the params
64
- */
65
- before: (req: IRequest, params: any, currentUser: Document) => any;
56
+ * Before handler that is called before creating a new record.
57
+ * This function gives you the access to the record params before saving it, you can perform any update to the params before saving it.
58
+ * @returns the params
59
+ */
60
+ before?: (req: IRequest, params: any, currentUser: Document) => Promise<any>;
61
+ /**
62
+ * After handler that gives you the access to the saved document.
63
+ * @returns the saved document
64
+ */
65
+ after?: (req: IRequest, document: Document, currentUser: Document) => Promise<Document>;
66
+ };
67
+ update?: {
68
+ /**
69
+ * Before handler that is called before updating a record.
70
+ * This function gives you the access to the record params before saving it, you can perform any update to the params before saving it.
71
+ * @returns the params
72
+ */
73
+ before?: (req: IRequest, params: any, currentUser: Document) => Promise<any>;
66
74
  };
67
75
  show?: {
68
- after: (req: IRequest, record: Document) => Promise<{
76
+ after?: (req: IRequest, record: Document) => Promise<{
69
77
  record: Document;
70
78
  [key: string]: any;
71
79
  }>;
@@ -73,74 +81,154 @@ interface ICrudOperations {
73
81
  }
74
82
  export interface ActionData {
75
83
  /**
76
- * Record document
77
- */
84
+ * Record document
85
+ */
78
86
  record: any;
79
87
  /**
80
- * Current user data
81
- */
88
+ * Current user data
89
+ */
82
90
  currentUser: Document;
83
91
  /**
84
- * Resource data to which this record belongs
85
- */
92
+ * Resource data to which this record belongs
93
+ */
86
94
  resource: {
87
95
  /**
88
- * Model name of this table.
89
- */
96
+ * Model name of this table.
97
+ */
90
98
  name: string;
91
99
  /**
92
- * Path of the resource to which you can redirect.
93
- */
100
+ * Path of the resource to which you can redirect.
101
+ */
94
102
  path: string;
95
103
  /**
96
- * Repository of this resource.
97
- */
98
- repository: any;
104
+ * Repository of this resource.
105
+ */
106
+ repository: IRepository<Document>;
99
107
  };
100
108
  }
101
109
  interface IFilters {
102
110
  /**
103
- * Scope filter props. If used you should override the scope filter function in the controller of this resource. This filter is not accessible by default
104
- */
111
+ * Scope filter props.
112
+ * Can be either auto or manual. It cannot be both.
113
+ * This filter is not accessible by default
114
+ */
105
115
  scopes?: {
106
116
  /**
107
117
  * Specify if this filter is accessible or not
118
+ * @default false
108
119
  */
109
120
  isAccessible: boolean;
110
121
  /**
111
- * Automatic scope that filters by the specified key with one of the given options
112
- */
122
+ * Automatic scope that filters by the specified key with one of the given options
123
+ * This filter works automatically by mentioning the key as saved in the database along with the values that this key can has.
124
+ * It doesn't need a handler
125
+ */
113
126
  auto?: IAutoScope;
114
127
  /**
115
- * Manual scope by using a handler
116
- */
128
+ * Manual scope by using a handler.
129
+ * In this case you can put the options you like with specifying in the handler what to do with each option.
130
+ */
117
131
  manual?: IManualScope;
118
132
  };
133
+ /**
134
+ * Search bar filter props
135
+ */
119
136
  searchBar?: {
137
+ /**
138
+ * Specify if this filter is accessible or not
139
+ * @default true
140
+ */
120
141
  isAccessible: boolean;
121
142
  };
122
143
  }
144
+ interface IAutoScope {
145
+ /**
146
+ * Key of property as specified in the database
147
+ */
148
+ key: string;
149
+ /**
150
+ * Array of values that this key can have
151
+ */
152
+ options: string[];
153
+ }
154
+ interface IManualScope {
155
+ /**
156
+ * Array of values that will be appeared in the scope
157
+ */
158
+ options: string[];
159
+ /**
160
+ * A handler that will be called when scope filter is used.
161
+ * This handler should perform a switch case on the specified options values, each case set the filter on its way.
162
+ */
163
+ handler: (filter: {
164
+ [key: string]: any;
165
+ }, scope: string) => Promise<{
166
+ [key: string]: any;
167
+ }>;
168
+ }
123
169
  export interface IFieldValue {
170
+ /**
171
+ * If the field is required in the schema and you don't want it to be required in the form, you can override this here.
172
+ * @default 'same as schema'
173
+ */
124
174
  required?: boolean;
175
+ /**
176
+ * Specify either this field can be edited or not.
177
+ * @default true
178
+ */
125
179
  isEditable?: boolean;
126
- type?: string;
127
180
  /**
128
- * Specify the allowed country codes. Only mandatory if the type is phone number
129
- * Alert message appear after executing this action.
130
- * ex: ["sa", "eg", ...]
131
- */
181
+ * Specify the type of the field. Can be used for specifying localized string, image,... etc.
182
+ * @default 'Same as schema''
183
+ */
184
+ type?: FieldTypes;
185
+ /**
186
+ * Specify the allowed country codes.
187
+ * @required if the type is phone number
188
+ * ex: ["sa", "eg", ...]
189
+ */
132
190
  countryCodes?: string[];
191
+ /**
192
+ * Specify the array type if the field is of type array.
193
+ * @default 'Same as schema''
194
+ */
133
195
  arrayType?: FieldTypes;
196
+ /**
197
+ * Can be used only if this field is a reference to the Image collection
198
+ */
134
199
  mediaUploader?: boolean;
200
+ /**
201
+ * Specify the type of the file to be uploaded. Only required if the media uploader is true.
202
+ * @default image
203
+ */
204
+ fileType?: FileTypes;
135
205
  }
136
206
  export interface IVirtualValue {
207
+ /**
208
+ * For now we have some virtual fields that can be added
209
+ * 1) Password: If you want to add password field in the creation form for example
210
+ * 2) ref: If it is a one to many realtion. For example, if you want to get all subCatogeries that belong to a category when you show the category record
211
+ * 3) array: If this field is an array
212
+ */
137
213
  type: VirtualFieldTypes;
214
+ /**
215
+ * Array type exists only if the type is array
216
+ */
138
217
  arrayType?: string;
218
+ /**
219
+ * Defines where this virtaul field need to be appeared
220
+ */
139
221
  showIn: Virtuals;
140
222
  required: boolean;
223
+ /**
224
+ * Define Virtual field's resource in case of ref type or array of ref type
225
+ */
141
226
  resource?: Model<any, any>;
142
227
  }
143
228
  interface IModel {
229
+ /**
230
+ * virtual data props
231
+ */
144
232
  virtuals?: {
145
233
  [key: string]: IVirtualValue;
146
234
  };
@@ -151,62 +239,175 @@ interface ActionOptions {
151
239
  edit?: Action;
152
240
  delete?: Action;
153
241
  bulkDelete?: Action;
242
+ /**
243
+ * Any extra action to be added.
244
+ */
154
245
  extras?: ExtraAction[];
155
246
  }
156
247
  interface ExtraAction {
248
+ /**
249
+ * Key of this action.
250
+ * Should be unique in the same resource file
251
+ */
157
252
  key: string;
253
+ /**
254
+ * Name of this action
255
+ */
158
256
  name: string;
159
257
  /**
160
- * Icon of this action.
161
- * @reference 'https://mui.com/material-ui/material-icons/'
162
- */
258
+ * Icon of this action.
259
+ * {@link https://mui.com/material-ui/material-icons/}
260
+ */
163
261
  icon: string;
262
+ /**
263
+ * Action type if it is record action or resource action.
264
+ */
164
265
  actionType: ActionTypes;
165
266
  /**
166
- * Guard message that appears before executing the action to confirm execution.
167
- * @default 'No guard message'
168
- */
267
+ * Guard message that appears before executing the action to confirm execution.
268
+ * @default 'No guard message'
269
+ */
169
270
  guard?: string;
170
271
  /**
171
- * Alert message appear after executing this action.
172
- * @default 'Action was executed successfully'
272
+ * Alert message appear after executing this action.
273
+ * @default 'Action was executed successfully'
173
274
  */
174
275
  message?: string;
175
276
  /**
176
- * The severity of the alert. This defines the color and icon used.
177
- * @default 'success'
178
- */
277
+ * The severity of the alert. This defines the color and icon used.
278
+ * @default 'success'
279
+ */
179
280
  severity?: Severity;
180
- isVisible?: (data: ActionData) => boolean;
181
- handler: (req: Request, res: any, data: ActionData) => Promise<any>;
281
+ /**
282
+ * @returns boolean value.
283
+ * This value Specifies to which records should this action appears.
284
+ * @default 'Action is shown to all records'
285
+ */
286
+ isVisible?: (data: ActionData) => Promise<boolean>;
287
+ /**
288
+ * Handler function that is executed after clicking the action.
289
+ */
290
+ handler: (req: Request, res: any, data: ActionData) => Promise<IActionHandlerResponse>;
291
+ }
292
+ export interface IActionHandlerResponse {
293
+ /**
294
+ * The action taken after executing the action.
295
+ * For example, if you would like to go to list after executing the action, just set this value by list
296
+ */
297
+ action: ActionNames;
298
+ /**
299
+ * Path of the resource that is intended to redirect.
300
+ * Is set to resource.path if you would like to be in the same table
301
+ */
302
+ path: string;
303
+ /**
304
+ * Id of the record that is used in actions that needs record id like show or edit
305
+ */
306
+ recordId?: string;
182
307
  }
183
308
  export interface IResourceFile {
184
309
  properties: {
310
+ /**
311
+ * The model
312
+ */
185
313
  resource: Model<any, any>;
314
+ /**
315
+ * Model name as saved in the data base.
316
+ */
186
317
  modelName: string;
318
+ /**
319
+ * Name of this model appeared on the nav bar.
320
+ * @default 'Model name'
321
+ */
187
322
  name?: string;
323
+ /**
324
+ * Property of this table that is shown as the link for the record.
325
+ * Used to be searched by in the search bar.
326
+ * If not mentioned explicitly, a search is done on the schema to check for property title, name, or email.
327
+ * If these properties are not found, _id is taken.
328
+ */
188
329
  title?: string;
330
+ /**
331
+ * The property to be sorted by the documents.
332
+ * @default 'The schema title'
333
+ */
189
334
  defaultOrderBy?: string;
190
- defaultrowsPerPage?: number;
335
+ /**
336
+ * The property that controls the permission of this model according to the current user role.
337
+ * Specify either this user is allowed to see this model or not.
338
+ * @default true
339
+ */
340
+ isAllowed?: (currentUser: Document) => Promise<boolean>;
341
+ /**
342
+ * The default order
343
+ * @default asc
344
+ */
191
345
  defaultOrder?: orderTypes;
346
+ /**
347
+ * Number of rows per page
348
+ * @default 10
349
+ */
350
+ defaultrowsPerPage?: number;
351
+ /**
352
+ * The parent that this model is belong to in the nav bar.
353
+ * @default 'Set up parent'
354
+ */
192
355
  parent?: Parent;
356
+ /**
357
+ * Array of fields that are completely hidden from all pages
358
+ */
193
359
  hiddenProperties?: string[];
360
+ /**
361
+ * Action options for overriding existing actions accessibility or adding custom actions
362
+ */
194
363
  actions?: ActionOptions;
364
+ /**
365
+ * Filters options
366
+ */
195
367
  filters?: IFilters;
368
+ /**
369
+ * Using before or after handlers of any crud operation
370
+ */
196
371
  crudOperations?: ICrudOperations;
372
+ /**
373
+ * Translation object of the fields' names.
374
+ */
197
375
  keysTranslations?: {
198
376
  [key: string]: any;
199
377
  };
378
+ /**
379
+ * Translation object of the actions' names.
380
+ */
200
381
  actionsTranslations?: {
201
382
  [key: string]: any;
202
383
  };
384
+ /**
385
+ * Override some props of a field's schema structure
386
+ * Add a new virtual property
387
+ */
203
388
  model?: {
204
389
  [key: string]: IFieldValue;
205
390
  } | IModel;
206
391
  };
392
+ /**
393
+ * Array of properties that should be appeared in the list action.
394
+ * @default 'The whole fields'
395
+ */
207
396
  listProperties?: string[];
397
+ /**
398
+ * Arrays of properties that should be appeared in the show action.
399
+ * @default 'The whole fields'
400
+ */
208
401
  showProperties?: string[];
402
+ /**
403
+ * Array of properties that should be appeared in the create/edit form.
404
+ * @default 'The whole fields'
405
+ */
209
406
  formProperties?: string[];
407
+ /**
408
+ * Array of properties that should be appeared in the filter.
409
+ * @default 'The whole fields'
410
+ */
210
411
  filterProperties?: string[];
211
412
  }
212
413
  export {};
@@ -0,0 +1,99 @@
1
+ import { ActionTypes } from "./helpers";
2
+ export default interface IResourceResponse {
3
+ filterProperties: string[];
4
+ formProperties: string[];
5
+ listProperties: IProperty[];
6
+ showProperties: IProperty[];
7
+ properties: IMainProperty;
8
+ }
9
+ interface IProperty {
10
+ key: string;
11
+ value: string;
12
+ path?: string;
13
+ }
14
+ interface IMainProperty {
15
+ title: string;
16
+ path: string;
17
+ name: string;
18
+ modelName: string;
19
+ parent: IParent;
20
+ defaultOrder: orderTypes;
21
+ defaultOrderBy: string;
22
+ defaultrowsPerPage: number;
23
+ filters: IFilter;
24
+ actions: IAction;
25
+ model: {
26
+ [key: string]: any;
27
+ };
28
+ }
29
+ interface IParent {
30
+ icon: string;
31
+ name: string;
32
+ value: string;
33
+ }
34
+ interface IFilter {
35
+ scopes: {
36
+ isAccessible: boolean;
37
+ options?: {
38
+ key: string;
39
+ value: string;
40
+ }[];
41
+ manual?: {
42
+ options: string[];
43
+ };
44
+ auto?: {
45
+ key: string;
46
+ options: string[];
47
+ };
48
+ };
49
+ searchBar: {
50
+ isAccessible: boolean;
51
+ };
52
+ }
53
+ interface IAction {
54
+ bulkDelete: {
55
+ cancelDeleteOption: string;
56
+ confirmDeleteOption: string;
57
+ confirmationMessageBody: string;
58
+ confirmationMessageTitle: string;
59
+ isAccessible: boolean;
60
+ value: string;
61
+ };
62
+ delete: {
63
+ cancelDeleteOption: string;
64
+ confirmDeleteOption: string;
65
+ confirmationMessageBody: string;
66
+ confirmationMessageTitle: string;
67
+ isAccessible: boolean;
68
+ value: string;
69
+ };
70
+ edit: IActionMin;
71
+ new: IActionMin;
72
+ show: IActionMin;
73
+ extras?: IExtras;
74
+ }
75
+ interface IExtras {
76
+ record: {
77
+ [key: string]: IExtarAction;
78
+ };
79
+ resource: {
80
+ [key: string]: IExtarAction;
81
+ };
82
+ }
83
+ interface IExtarAction {
84
+ actionType: ActionTypes;
85
+ guard?: string;
86
+ icon: string;
87
+ key: string;
88
+ keys?: string[];
89
+ name: string;
90
+ severity?: Severity;
91
+ message?: string;
92
+ }
93
+ interface IActionMin {
94
+ isAccessible: boolean;
95
+ value?: string;
96
+ }
97
+ declare type orderTypes = 'asc' | 'desc';
98
+ declare type Severity = 'success' | 'info' | 'warning' | 'error';
99
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -30,3 +30,15 @@ export declare enum FieldTypes {
30
30
  COLOR = "color",
31
31
  TIMEPICKER = "timePicker"
32
32
  }
33
+ export declare enum FileTypes {
34
+ IMAGE = "IMAGE",
35
+ _3D = "3D",
36
+ PDF = "PDF",
37
+ EXCEL = "EXCEL",
38
+ WORD = "WORD",
39
+ VIDEO = "VIDEO",
40
+ TEXT = "TEXT",
41
+ ZIP = "ZIP",
42
+ POWER_POINT = "POWER_POINT",
43
+ AUDIO = "AUDIO"
44
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FieldTypes = exports.ActionTypes = exports.ActionNames = exports.Virtuals = void 0;
3
+ exports.FileTypes = exports.FieldTypes = exports.ActionTypes = exports.ActionNames = exports.Virtuals = void 0;
4
4
  var Virtuals;
5
5
  (function (Virtuals) {
6
6
  Virtuals["SHOW"] = "SHOW";
@@ -37,3 +37,16 @@ var FieldTypes;
37
37
  FieldTypes["COLOR"] = "color";
38
38
  FieldTypes["TIMEPICKER"] = "timePicker";
39
39
  })(FieldTypes = exports.FieldTypes || (exports.FieldTypes = {}));
40
+ var FileTypes;
41
+ (function (FileTypes) {
42
+ FileTypes["IMAGE"] = "IMAGE";
43
+ FileTypes["_3D"] = "3D";
44
+ FileTypes["PDF"] = "PDF";
45
+ FileTypes["EXCEL"] = "EXCEL";
46
+ FileTypes["WORD"] = "WORD";
47
+ FileTypes["VIDEO"] = "VIDEO";
48
+ FileTypes["TEXT"] = "TEXT";
49
+ FileTypes["ZIP"] = "ZIP";
50
+ FileTypes["POWER_POINT"] = "POWER_POINT";
51
+ FileTypes["AUDIO"] = "AUDIO";
52
+ })(FileTypes = exports.FileTypes || (exports.FileTypes = {}));
@@ -5,6 +5,7 @@ export default class ResponseUtils {
5
5
  static created(res: Response, data: object): void;
6
6
  static ok(res: Response, data: object): void;
7
7
  static unauthorized(res: Response): void;
8
+ static forbidden(res: Response): void;
8
9
  static unprocessable(res: Response, message: string, errors: ISaveError[]): void;
9
10
  static notFound(res: Response, message: string, errors: ISaveError[]): void;
10
11
  }
@@ -28,6 +28,9 @@ class ResponseUtils {
28
28
  static unauthorized(res) {
29
29
  this.send(res, 401, 'Unauthenticated');
30
30
  }
31
+ static forbidden(res) {
32
+ this.send(res, 403, 'Not allowed to access this resource');
33
+ }
31
34
  static unprocessable(res, message, errors) {
32
35
  this.send(res, 422, message, {}, errors);
33
36
  }
@@ -1,14 +1,19 @@
1
1
  {
2
2
  "files": {
3
- "main.css": "/static/css/main.18dca458.css",
4
- "main.js": "/static/js/main.da8f09ec.js",
5
- "static/js/148.b05fe2c8.chunk.js": "/static/js/148.b05fe2c8.chunk.js",
6
- "static/js/705.f86db82e.chunk.js": "/static/js/705.f86db82e.chunk.js",
7
- "static/js/802.3f287a2c.chunk.js": "/static/js/802.3f287a2c.chunk.js",
8
- "index.html": "/index.html"
3
+ "main.css": "/static/css/main.54de06ef.css",
4
+ "main.js": "/static/js/main.7ca1e0c1.js",
5
+ "static/js/574.778b5963.chunk.js": "/static/js/574.778b5963.chunk.js",
6
+ "static/js/678.521704a3.chunk.js": "/static/js/678.521704a3.chunk.js",
7
+ "static/js/798.54856416.chunk.js": "/static/js/798.54856416.chunk.js",
8
+ "index.html": "/index.html",
9
+ "main.54de06ef.css.map": "/static/css/main.54de06ef.css.map",
10
+ "main.7ca1e0c1.js.map": "/static/js/main.7ca1e0c1.js.map",
11
+ "574.778b5963.chunk.js.map": "/static/js/574.778b5963.chunk.js.map",
12
+ "678.521704a3.chunk.js.map": "/static/js/678.521704a3.chunk.js.map",
13
+ "798.54856416.chunk.js.map": "/static/js/798.54856416.chunk.js.map"
9
14
  },
10
15
  "entrypoints": [
11
- "static/css/main.18dca458.css",
12
- "static/js/main.da8f09ec.js"
16
+ "static/css/main.54de06ef.css",
17
+ "static/js/main.7ca1e0c1.js"
13
18
  ]
14
19
  }