identity-admin 1.10.0 → 1.12.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.
@@ -23,18 +23,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
23
23
  var DashboardController_1;
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  const inversify_express_utils_1 = require("inversify-express-utils");
26
- const mongoose_1 = require("mongoose");
27
26
  const ResponseUtils_1 = __importDefault(require("../utils/ResponseUtils"));
28
27
  const express_validator_1 = require("express-validator");
29
28
  const ResourceGenerator_1 = __importDefault(require("../helpers/ResourceGenerator"));
30
29
  const ResourceHelper_1 = __importDefault(require("../helpers/ResourceHelper"));
31
30
  const StringUtils_1 = __importDefault(require("../utils/StringUtils"));
32
- const mongoose_2 = __importDefault(require("mongoose"));
31
+ const mongoose_1 = __importDefault(require("mongoose"));
33
32
  const inversify_1 = require("inversify");
34
33
  const Repository_1 = __importDefault(require("../repositories/Repository"));
35
34
  const ResourceUtils_1 = require("../utils/ResourceUtils");
36
35
  const FiltersHelper_1 = __importDefault(require("../helpers/FiltersHelper"));
37
36
  const LocalizedStringHelper_1 = __importDefault(require("../helpers/LocalizedStringHelper"));
37
+ const ActionsGenerator_1 = __importDefault(require("../helpers/ActionsGenerator"));
38
38
  let DashboardController = DashboardController_1 = class DashboardController {
39
39
  constructor(resource, repository, resources) {
40
40
  this.resource = resource;
@@ -61,7 +61,7 @@ let DashboardController = DashboardController_1 = class DashboardController {
61
61
  const schema = resource.properties.resource.schema.paths;
62
62
  const searchBy = ResourceHelper_1.default.getSchemaTitle(schema, this.resource);
63
63
  if (searchBy === '_id') {
64
- if (!mongoose_2.default.isValidObjectId(subString.source)) {
64
+ if (!mongoose_1.default.isValidObjectId(subString.source)) {
65
65
  return filter;
66
66
  }
67
67
  filter[searchBy] = subString.source;
@@ -127,8 +127,15 @@ let DashboardController = DashboardController_1 = class DashboardController {
127
127
  if (!resource) {
128
128
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
129
129
  }
130
+ if (!currentUser) {
131
+ return ResponseUtils_1.default.unauthorized(res);
132
+ }
133
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
134
+ if (!permissionCheck) {
135
+ return ResponseUtils_1.default.forbidden(res);
136
+ }
130
137
  const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
131
- const modifiedResource = ResourceGenerator_1.default.generate(resource);
138
+ const modifiedResource = ResourceGenerator_1.default.generate(resource, currentUser);
132
139
  const sort = req.query.order;
133
140
  const sortBy = req.query.orderBy;
134
141
  const sortQuery = {};
@@ -207,13 +214,24 @@ let DashboardController = DashboardController_1 = class DashboardController {
207
214
  }
208
215
  const modelName = req.params.resource;
209
216
  const resource = (_a = this.resource) !== null && _a !== void 0 ? _a : (0, ResourceUtils_1.getResource)(modelName, (_b = this.resources) !== null && _b !== void 0 ? _b : []);
217
+ const currentUser = req.user;
210
218
  if (!resource) {
211
219
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
212
220
  }
221
+ if (!currentUser) {
222
+ return ResponseUtils_1.default.unauthorized(res);
223
+ }
224
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
225
+ if (!permissionCheck) {
226
+ return ResponseUtils_1.default.forbidden(res);
227
+ }
228
+ const actions = ActionsGenerator_1.default.generateActions(resource.properties.actions, resource, currentUser);
229
+ const createPermission = actions.new.isAccessible;
230
+ if (!createPermission) {
231
+ return ResponseUtils_1.default.forbidden(res);
232
+ }
213
233
  const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
214
- const modifiedResource = ResourceGenerator_1.default.generate(resource);
215
234
  var recordParams = req.body;
216
- const currentUser = req.user;
217
235
  recordParams = LocalizedStringHelper_1.default.mapLocalizableString(recordParams, resource);
218
236
  const crudOperations = resource.properties.crudOperations;
219
237
  if (crudOperations && crudOperations.create && crudOperations.create.before) {
@@ -221,7 +239,8 @@ let DashboardController = DashboardController_1 = class DashboardController {
221
239
  }
222
240
  var record;
223
241
  if (recordParams.password) {
224
- const user = new mongoose_1.Mongoose.prototype.model(modifiedResource.properties.modelName)(recordParams);
242
+ //const user = new Mongoose.prototype.model(modifiedResource.properties.modelName)(recordParams);
243
+ const user = new resource.properties.resource(recordParams);
225
244
  const set = yield user.setPassword(recordParams.password);
226
245
  record = yield repository.saveInstance(user);
227
246
  }
@@ -232,7 +251,7 @@ let DashboardController = DashboardController_1 = class DashboardController {
232
251
  return ResponseUtils_1.default.unprocessable(res, 'Invalid Data', record.getErrors());
233
252
  }
234
253
  if (crudOperations && crudOperations.create && crudOperations.create.after) {
235
- record = yield crudOperations.create.after(req, record, currentUser);
254
+ record = yield crudOperations.create.after(req, record, currentUser, recordParams);
236
255
  }
237
256
  return ResponseUtils_1.default.created(res, {
238
257
  record
@@ -250,10 +269,22 @@ let DashboardController = DashboardController_1 = class DashboardController {
250
269
  if (!resource) {
251
270
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
252
271
  }
253
- const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
254
- const recordId = req.params.id;
255
272
  var recordParams = req.body;
256
273
  const currentUser = req.user;
274
+ if (!currentUser) {
275
+ return ResponseUtils_1.default.unauthorized(res);
276
+ }
277
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
278
+ if (!permissionCheck) {
279
+ return ResponseUtils_1.default.forbidden(res);
280
+ }
281
+ const actions = ActionsGenerator_1.default.generateActions(resource.properties.actions, resource, currentUser);
282
+ const editPermission = actions.edit.isAccessible;
283
+ if (!editPermission) {
284
+ return ResponseUtils_1.default.forbidden(res);
285
+ }
286
+ const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
287
+ const recordId = req.params.id;
257
288
  var record = yield repository.findById(recordId);
258
289
  if (!record) {
259
290
  return ResponseUtils_1.default.send(res, 404, 'record Not Found');
@@ -286,11 +317,19 @@ let DashboardController = DashboardController_1 = class DashboardController {
286
317
  const modelName = req.params.resource;
287
318
  const recordId = req.params.id;
288
319
  const resource = (_a = this.resource) !== null && _a !== void 0 ? _a : (0, ResourceUtils_1.getResource)(modelName, (_b = this.resources) !== null && _b !== void 0 ? _b : []);
320
+ const currentUser = req.user;
289
321
  if (!resource) {
290
322
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
291
323
  }
324
+ if (!currentUser) {
325
+ return ResponseUtils_1.default.unauthorized(res);
326
+ }
327
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
328
+ if (!permissionCheck) {
329
+ return ResponseUtils_1.default.forbidden(res);
330
+ }
292
331
  const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
293
- const modifiedResource = ResourceGenerator_1.default.generate(resource);
332
+ const modifiedResource = ResourceGenerator_1.default.generate(resource, currentUser);
294
333
  var record = yield repository.findOne({
295
334
  filter: {
296
335
  _id: recordId
@@ -323,6 +362,19 @@ let DashboardController = DashboardController_1 = class DashboardController {
323
362
  if (!resource) {
324
363
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
325
364
  }
365
+ const currentUser = req.user;
366
+ if (!currentUser) {
367
+ return ResponseUtils_1.default.unauthorized(res);
368
+ }
369
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
370
+ if (!permissionCheck) {
371
+ return ResponseUtils_1.default.forbidden(res);
372
+ }
373
+ const actions = ActionsGenerator_1.default.generateActions(resource.properties.actions, resource, currentUser);
374
+ const bulkDeletePermission = actions.bulkDelete.isAccessible;
375
+ if (!bulkDeletePermission) {
376
+ return ResponseUtils_1.default.forbidden(res);
377
+ }
326
378
  const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
327
379
  for (var i = 0; i < recordIds.length; i++) {
328
380
  const recordId = recordIds[i];
@@ -347,6 +399,19 @@ let DashboardController = DashboardController_1 = class DashboardController {
347
399
  if (!resource) {
348
400
  return ResponseUtils_1.default.notFound(res, 'Resource not found', []);
349
401
  }
402
+ const currentUser = req.user;
403
+ if (!currentUser) {
404
+ return ResponseUtils_1.default.unauthorized(res);
405
+ }
406
+ const permissionCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
407
+ if (!permissionCheck) {
408
+ return ResponseUtils_1.default.forbidden(res);
409
+ }
410
+ const actions = ActionsGenerator_1.default.generateActions(resource.properties.actions, resource, currentUser);
411
+ const deletePermission = actions.delete.isAccessible;
412
+ if (!deletePermission) {
413
+ return ResponseUtils_1.default.forbidden(res);
414
+ }
350
415
  const repository = (_c = this.repository) !== null && _c !== void 0 ? _c : new Repository_1.default(resource.properties.resource);
351
416
  const record = yield repository.findById(recordId);
352
417
  if (!record) {
@@ -58,20 +58,24 @@ let ResourceController = class ResourceController {
58
58
  return __awaiter(this, void 0, void 0, function* () {
59
59
  var modifiedResource = {};
60
60
  modifiedResource.modelParents = {};
61
+ const currentUser = req.user;
61
62
  if (this.configurations) {
62
63
  modifiedResource.appConfigurations = this.configurations;
63
64
  }
64
65
  for (var i = 0; i < this.resourceFiles.length; i++) {
65
66
  const resource = this.resourceFiles[i];
66
- const adaptedResource = ResourceGenerator_1.default.generate(resource);
67
- const modelName = StringUtils_1.default.lowerCaseFirstLetter(adaptedResource.properties.modelName);
68
- modifiedResource[modelName] = adaptedResource;
69
- if (modifiedResource.modelParents[adaptedResource.properties.parent.name]) {
70
- modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName);
71
- }
72
- else {
73
- modifiedResource.modelParents[adaptedResource.properties.parent.name] = [];
74
- modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName);
67
+ const visibiltyCheck = resource.properties.isAllowed ? yield resource.properties.isAllowed(currentUser) : true;
68
+ if (visibiltyCheck) {
69
+ const adaptedResource = ResourceGenerator_1.default.generate(resource, currentUser);
70
+ const modelName = StringUtils_1.default.lowerCaseFirstLetter(adaptedResource.properties.modelName);
71
+ modifiedResource[modelName] = adaptedResource;
72
+ if (modifiedResource.modelParents[adaptedResource.properties.parent.name]) {
73
+ modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName);
74
+ }
75
+ else {
76
+ modifiedResource.modelParents[adaptedResource.properties.parent.name] = [];
77
+ modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName);
78
+ }
75
79
  }
76
80
  }
77
81
  return ResponseUtils_1.default.send(res, 200, 'OK', {
@@ -85,8 +89,9 @@ let ResourceController = class ResourceController {
85
89
  const resourceName = modelName + 'Resource';
86
90
  const resourceFilePath = '@pbb/materialUi/' + resourceName;
87
91
  const resource = yield Promise.resolve().then(() => __importStar(require(resourceFilePath)));
92
+ const currentUser = req.user;
88
93
  return ResponseUtils_1.default.send(res, 200, 'OK', {
89
- options: ResourceGenerator_1.default.generate(resource[resourceName])
94
+ options: ResourceGenerator_1.default.generate(resource[resourceName], currentUser)
90
95
  });
91
96
  });
92
97
  }
@@ -1,6 +1,7 @@
1
+ import { Document } from "mongoose";
1
2
  import { IResourceFile } from "../types/IResourceFile";
2
3
  export default class ActionsGenerator {
3
- static generateActions(actionsCheck: any, resource: IResourceFile): {
4
+ static generateActions(actionsCheck: any, resource: IResourceFile, currentUser: Document): {
4
5
  [key: string]: any;
5
6
  };
6
7
  private static addExtraActions;
@@ -30,8 +30,8 @@ const i18n_1 = __importStar(require("i18n"));
30
30
  const ResourceHelper_1 = __importDefault(require("./ResourceHelper"));
31
31
  var pluralize = require('pluralize');
32
32
  class ActionsGenerator {
33
- static generateActions(actionsCheck, resource) {
34
- const actions = this.getActions(actionsCheck ? JSON.parse(JSON.stringify(resource.properties.actions)) : undefined); //resource.properties.actions? ResourcesHelper.getActions(JSON.parse(JSON.stringify(resource.properties.actions))): ResourcesHelper.getActions(undefined)
33
+ static generateActions(actionsCheck, resource, currentUser) {
34
+ const actions = this.getActions(actionsCheck ? resource.properties.actions : undefined, currentUser); //resource.properties.actions? ResourcesHelper.getActions(JSON.parse(JSON.stringify(resource.properties.actions))): ResourcesHelper.getActions(undefined)
35
35
  for (const key in actions) {
36
36
  if (key === 'extras') {
37
37
  actions.extras = actions.extras ? this.addExtraActions(JSON.parse(JSON.stringify(resource.properties.actions.extras))) : actions.extras;
@@ -54,7 +54,7 @@ class ActionsGenerator {
54
54
  });
55
55
  return extraActionsObject;
56
56
  }
57
- static getActions(actions) {
57
+ static getActions(actions, currentUser) {
58
58
  var actionObject = {
59
59
  show: { isAccessible: true },
60
60
  new: { isAccessible: true },
@@ -66,7 +66,15 @@ class ActionsGenerator {
66
66
  return actionObject;
67
67
  }
68
68
  for (const key in actions) {
69
- if (actions[key].hasOwnProperty('isAccessible') || key === 'extras') {
69
+ if (actions[key].hasOwnProperty('isAccessible') && key !== 'extras') {
70
+ actionObject[key] = actions[key];
71
+ }
72
+ else if (actions[key].isAllowed && key !== 'extras') {
73
+ actionObject[key] = {
74
+ isAccessible: actions[key].isAllowed(currentUser)
75
+ };
76
+ }
77
+ else if (key === 'extras') {
70
78
  actionObject[key] = actions[key];
71
79
  }
72
80
  }
@@ -1,4 +1,5 @@
1
+ import { Document } from "mongoose";
1
2
  import { IResourceFile } from "../types/IResourceFile";
2
3
  export default class ResourceGenerator {
3
- static generate(resource: IResourceFile): any;
4
+ static generate(resource: IResourceFile, currentUser: Document): any;
4
5
  }
@@ -37,7 +37,7 @@ const SetupParent = {
37
37
  //value: __({phrase: "Setup", locale: i18n.getLocale()})
38
38
  };
39
39
  class ResourceGenerator {
40
- static generate(resource) {
40
+ static generate(resource, currentUser) {
41
41
  var _a, _b, _c, _d, _e, _f, _g;
42
42
  const SetupParent = {
43
43
  name: 'Setup',
@@ -102,7 +102,7 @@ class ResourceGenerator {
102
102
  const options = ((_b = (_a = resource.properties.filters) === null || _a === void 0 ? void 0 : _a.scopes) === null || _b === void 0 ? void 0 : _b.auto) ? (_d = (_c = resource.properties.filters) === null || _c === void 0 ? void 0 : _c.scopes) === null || _d === void 0 ? void 0 : _d.auto.options : (_g = (_f = (_e = resource.properties.filters) === null || _e === void 0 ? void 0 : _e.scopes) === null || _f === void 0 ? void 0 : _f.manual) === null || _g === void 0 ? void 0 : _g.options;
103
103
  modifiedResource.properties.filters.scopes.options = ResourceHelper_1.default.setScopeFilterOptions(modelName, options);
104
104
  }
105
- const actions = ActionsGenerator_1.default.generateActions(actionsCheck, resource);
105
+ const actions = ActionsGenerator_1.default.generateActions(actionsCheck, resource, currentUser);
106
106
  modifiedResource.properties.actions = actions;
107
107
  return modifiedResource;
108
108
  }
@@ -33,6 +33,9 @@ class SchemaGenerator {
33
33
  model = modelAndPopulatedString[0];
34
34
  populatedString = modelAndPopulatedString[1];
35
35
  }
36
+ if (fieldType === helpers_1.FieldTypes.DATE) {
37
+ model[field].withTime = model[field].withTime ? model[field].withTime : false;
38
+ }
36
39
  else if (fieldType === helpers_1.FieldTypes.ARRAY) {
37
40
  model[field].required = schema[field].caster.isRequired;
38
41
  if (schema[field].schema) {
@@ -25,6 +25,13 @@ interface Action {
25
25
  * You can ovveride any of these values here.
26
26
  */
27
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;
28
35
  }
29
36
  interface ICrudOperations {
30
37
  index?: {
@@ -55,7 +62,7 @@ interface ICrudOperations {
55
62
  * After handler that gives you the access to the saved document.
56
63
  * @returns the saved document
57
64
  */
58
- after?: (req: IRequest, document: Document, currentUser: Document) => Promise<Document>;
65
+ after?: (req: IRequest, document: Document, currentUser: Document, params: any) => Promise<Document>;
59
66
  };
60
67
  update?: {
61
68
  /**
@@ -195,6 +202,11 @@ export interface IFieldValue {
195
202
  * @default image
196
203
  */
197
204
  fileType?: FileTypes;
205
+ /**
206
+ * Specify if the date is shown with time or not. Only used if the field type is Date
207
+ * @default false
208
+ */
209
+ withTime?: boolean;
198
210
  }
199
211
  export interface IVirtualValue {
200
212
  /**
@@ -325,6 +337,12 @@ export interface IResourceFile {
325
337
  * @default 'The schema title'
326
338
  */
327
339
  defaultOrderBy?: string;
340
+ /**
341
+ * The property that controls the permission of this model according to the current user role.
342
+ * Specify either this user is allowed to see this model or not.
343
+ * @default true
344
+ */
345
+ isAllowed?: (currentUser: Document) => Promise<boolean>;
328
346
  /**
329
347
  * The default order
330
348
  * @default asc
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "identity-admin",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "",
5
5
  "main": "lib/Dashboard.js",
6
6
  "types": "lib/Dashbord.d.ts",