identity-admin 1.0.0 → 1.2.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.
@@ -86,8 +86,6 @@ const createRouter = (dashboardController, resourceController, ActionController,
86
86
  const createViewRoute = (router, appPath) => {
87
87
  router
88
88
  .get(`(/*)?`, (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
89
- console.log(req.path);
90
- console.log(appPath);
91
89
  return res.sendFile(path_1.default.join(appPath, "index.html"));
92
90
  }));
93
91
  };
@@ -45,6 +45,7 @@ interface IFilters {
45
45
  interface IFieldValue {
46
46
  required?: boolean;
47
47
  isEditable?: boolean;
48
+ type?: string;
48
49
  }
49
50
  interface IVirtualValue {
50
51
  type: VirtualFieldTypes;
@@ -1,12 +1,10 @@
1
1
  import { ISaveError } from '../repositories/SaveResult';
2
2
  import { Response } from 'express';
3
3
  export default class ResponseUtils {
4
- private static logRepository;
5
4
  static send(res: Response, status: number, message: string, data?: object, errors?: ISaveError[]): Response<any, Record<string, any>>;
6
5
  static created(res: Response, data: object): void;
7
6
  static ok(res: Response, data: object): void;
8
7
  static unauthorized(res: Response): void;
9
8
  static unprocessable(res: Response, message: string, errors: ISaveError[]): void;
10
9
  static notFound(res: Response, message: string, errors: ISaveError[]): void;
11
- private static log;
12
10
  }
@@ -1,21 +1,7 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const RequestLogRepository_1 = __importDefault(require("../repositories/RequestLogRepository"));
16
3
  class ResponseUtils {
17
4
  static send(res, status, message, data, errors) {
18
- this.log(res.req, status, message);
19
5
  const splittedMessage = message.split(', ');
20
6
  return res.format({
21
7
  json: () => {
@@ -48,25 +34,5 @@ class ResponseUtils {
48
34
  static notFound(res, message, errors) {
49
35
  this.send(res, 404, message, {}, errors);
50
36
  }
51
- static log(req, status, message) {
52
- return __awaiter(this, void 0, void 0, function* () {
53
- const duration = new Date().getTime() - req.startTime.getTime();
54
- const logProps = {
55
- method: req.method,
56
- endpoint: req.route.path,
57
- url: req.originalUrl.split('?')[0],
58
- startTime: req.startTime,
59
- durationInMilliseconds: duration,
60
- query: JSON.stringify(req.query),
61
- body: JSON.stringify(req.body),
62
- userAgent: req.headers['user-agent'],
63
- headers: JSON.stringify(req.headers),
64
- status: status,
65
- message: message
66
- };
67
- yield ResponseUtils.logRepository.save(logProps);
68
- });
69
- }
70
37
  }
71
38
  exports.default = ResponseUtils;
72
- ResponseUtils.logRepository = new RequestLogRepository_1.default();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "identity-admin",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "lib/Dashboard.js",
6
6
  "types": "lib/Dashbord.d.ts",
@@ -14,7 +14,14 @@
14
14
  "postversion": "git push && git push --tags",
15
15
  "test": "jest --config jestconfig.json --runInBand"
16
16
  },
17
- "author": "",
17
+ "files": [
18
+ "lib/**/*"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/identity-skeleton/identity-admin.git"
23
+ },
24
+ "author": "mismail",
18
25
  "license": "ISC",
19
26
  "devDependencies": {
20
27
  "@types/express": "^4.17.14",
package/src/Dashboard.ts DELETED
@@ -1,74 +0,0 @@
1
- import { IResourceFile } from "./types/IResourceFile";
2
- import express, { Application, NextFunction, Request, Response, Router } from "express";
3
- import { Container } from "inversify";
4
- import DashboardController from "./controllers/DashboardController";
5
- import createRouter, { createViewRoute } from "./router";
6
- import i18n from "i18n";
7
- import ResourceController from "./controllers/ResourceController";
8
- import path from 'path';
9
- import MongoStore from 'connect-mongo';
10
- import mongoose from "mongoose";
11
- import DashboardConfig, { AdminCredentials, CookieConfiguration } from "./types/DashbordConfig";
12
- import ActionController from "./controllers/ActionController";
13
-
14
- var session = require('express-session');
15
- var cookieParser = require('cookie-parser');
16
-
17
-
18
-
19
- export default class Dashboard {
20
- private DEFAULT_ROOT_PATH = "/dashboard";
21
-
22
- constructor(private dashBoardConfig: DashboardConfig) {}
23
-
24
- public build(app: Application) {
25
- this.configureLocalization();
26
- this.configureAuthentication(app);
27
- this.buildRouter(app);
28
-
29
- }
30
-
31
-
32
- private configureLocalization() {
33
- i18n.configure(this.dashBoardConfig.localesOptions ?? {
34
- locales: ["en"],
35
- directory:__dirname+'/locales',
36
- });
37
- }
38
-
39
- private buildRouter(app: Application) {
40
- const dashboardController = new DashboardController(undefined, undefined, this.dashBoardConfig.resources);
41
- const resourceController = new ResourceController(this.dashBoardConfig.resources);
42
- const actionController = new ActionController(this.dashBoardConfig.resources)
43
-
44
- const appPath = path.normalize(path.join(__dirname, '/view'));
45
- const router = createRouter(dashboardController, resourceController, actionController, this.dashBoardConfig.authenticate);
46
- app.use(express.static(appPath));
47
- createViewRoute(router, appPath);
48
-
49
- app.use(this.dashBoardConfig.rootPath ?? this.DEFAULT_ROOT_PATH, router);
50
- }
51
-
52
- private configureAuthentication (app: Application) {
53
- if(!this.dashBoardConfig.authenticate || !this.dashBoardConfig.cookiesConfiguration){
54
- return;
55
- }
56
- app.use(cookieParser());
57
- this.configureSession(app, this.dashBoardConfig.cookiesConfiguration);
58
- }
59
-
60
- private configureSession(app: Application, cookiesConfiguration: CookieConfiguration) {
61
- const rootPath = this.dashBoardConfig.rootPath ?? this.DEFAULT_ROOT_PATH;
62
- app.use(`${rootPath}`,session({
63
- secret: cookiesConfiguration.cookiesSecret,
64
- resave: false,
65
- saveUninitialized: false,
66
- name: cookiesConfiguration.cookieName,
67
- cookie: { path: `${rootPath}`, httpOnly: true}
68
- }));
69
- }
70
-
71
- public static configurBaseLocalization(options: i18n.ConfigurationOptions) {
72
- i18n.configure(options);
73
- }
74
- }
@@ -1,64 +0,0 @@
1
- import { Request, Response } from 'express';
2
- import { controller, httpDelete, httpGet, httpPatch, httpPost, request, response } from 'inversify-express-utils';
3
- import { inject } from 'inversify';
4
- import isAuth, { defaultHeaders, IRequest } from '../middlewares/isAuth';
5
- import ResponseUtils from '../utils/ResponseUtils';
6
- import { __ } from 'i18n';
7
- import StringUtils from '../utils/StringUtils';
8
- import Repository, { IDashboardRepository } from '../repositories/Repository';
9
- import { IResourceFile } from '../types/IResourceFile';
10
- import { Document } from 'mongoose';
11
- import { getResource } from '../utils/ResourceUtils';
12
-
13
-
14
-
15
- export default class ActionController {
16
-
17
- constructor(private resources: IResourceFile[]) {
18
- }
19
-
20
- @httpPost('/execute/:actionKey')
21
- public async execute(@request() req: IRequest, @response() res: Response) {
22
-
23
- const record = req.body.record
24
- const modelName = req.body.modelName
25
- const resource: IResourceFile | undefined= getResource(modelName, this.resources);
26
-
27
- if(!resource) {
28
- return ResponseUtils.notFound(res, 'Resource not found', []);
29
- }
30
- const repository = new Repository(resource.properties.resource);
31
-
32
- const actionKey = req.params.actionKey
33
- const currentUser = req.user
34
-
35
- var response = {}
36
-
37
- const data = {
38
- record,
39
- currentUser,
40
- resource: {
41
- name: modelName,
42
- path: StringUtils.lowerCaseFirstLetter(modelName),
43
- repository
44
- }
45
- }
46
-
47
- const extraActions = resource.properties.actions?.extras ?? []
48
-
49
- for (var i = 0; i < extraActions.length; i++) {
50
-
51
- const extraAction = extraActions[i]
52
-
53
- if (extraAction.key === actionKey) {
54
- response = await extraAction.handler(req, res, data)
55
- break
56
- }
57
- }
58
-
59
- return ResponseUtils.send(res, 200, 'Ok', {
60
- response
61
- });
62
-
63
- }
64
- }
@@ -1,388 +0,0 @@
1
- import { Request, Response } from 'express';
2
- import { controller, httpDelete, httpGet, httpPatch, httpPost, interfaces, request, response } from 'inversify-express-utils';
3
- import { Document, Mongoose } from 'mongoose';
4
- import ResponseUtils from '../utils/ResponseUtils';
5
- import { validationResult } from 'express-validator';
6
-
7
- import ResourceGenerator from '../helpers/ResourceGenerator';
8
- import ResourcesHelper from '../helpers/ResourceHelper';
9
- import StringUtils from '../utils/StringUtils';
10
- import mongoose from 'mongoose'
11
- import { injectable, unmanaged } from 'inversify';
12
- import { IResourceFile } from '../types/IResourceFile';
13
- import Repository, { IDashboardRepository } from '../repositories/Repository';
14
- import { getResource } from '../utils/ResourceUtils';
15
- import { IRequest } from '../middlewares/isAuth';
16
-
17
-
18
- export interface PaginateParams {
19
- page: number;
20
- perPage: number;
21
- }
22
- @injectable()
23
- export default class DashboardController {
24
-
25
- protected static DEFAULT_PAGE = 1;
26
- protected static DEFAULT_PER_PAGE = 30;
27
-
28
- constructor(resource?: IResourceFile, repository?: IDashboardRepository);
29
- constructor(resource?: IResourceFile, repository?: IDashboardRepository, resources?: IResourceFile[]);
30
- constructor(@unmanaged() private resource?: IResourceFile, @unmanaged() private repository?: IDashboardRepository, @unmanaged() private resources?: IResourceFile[]) {
31
- if(!repository && resource) {
32
- this.repository = new Repository(resource.properties.resource)
33
- }
34
- }
35
-
36
-
37
-
38
-
39
-
40
- protected validateRequest(@request() req: IRequest, @response() res: Response): boolean {
41
-
42
- const errors = validationResult(req);
43
-
44
- if (!errors.isEmpty()) {
45
- ResponseUtils.send(res, 422, errors.array()[0].msg, errors);
46
- return false;
47
- }
48
-
49
- return true;
50
- }
51
-
52
- protected paginateParams(request: IRequest): PaginateParams {
53
-
54
- const page = request.query.page ? + request.query.page : DashboardController.DEFAULT_PAGE;
55
- const perPage = request.query.perPage ? + request.query.perPage : DashboardController.DEFAULT_PER_PAGE;
56
-
57
- return { page, perPage };
58
- }
59
-
60
- protected getSearchableSubStringFilter(resource: IResourceFile, filter: { [key: string]: any; }, subString: RegExp): { [key: string]: any; } {
61
-
62
-
63
- const schema = resource.properties.resource.schema.paths
64
- const searchBy = ResourcesHelper.getSchemaTitle(schema, this.resource)
65
-
66
- if (searchBy === '_id') {
67
-
68
- if (!mongoose.isValidObjectId(subString.source)) {
69
- return filter
70
- }
71
-
72
- filter[searchBy] = subString.source
73
-
74
- return filter
75
- }
76
-
77
- filter[searchBy] = subString
78
-
79
- return filter
80
- }
81
-
82
-
83
- protected getScopeFilter(filter: {[key:string]: any}, scope: string): {[key:string]: any} {
84
- return {}
85
- }
86
-
87
- protected async getVisibileExtrsActions(currentUser: Document, record: any, resource: any, repository: any, modelName: string) {
88
-
89
- const data = {
90
- record: record.toObject(),
91
- currentUser,
92
- resource: {
93
- name: modelName,
94
- path: StringUtils.lowerCaseFirstLetter(modelName),
95
- repository
96
- }
97
- }
98
-
99
- if (!resource.properties.actions || !resource.properties.actions.extras) {
100
- return undefined
101
- }
102
-
103
- var extraActionsArray = []
104
- const extraActions = resource.properties.actions.extras
105
-
106
- for (var i = 0; i < extraActions.length; i++) {
107
-
108
- const extraAction = extraActions[i]
109
-
110
- if (!extraAction.isVisible) {
111
- break
112
- }
113
-
114
- const isVisible = extraAction.isVisible(data)
115
-
116
- if (isVisible) {
117
- extraActionsArray.push(extraAction.key)
118
- }
119
-
120
- }
121
-
122
-
123
- return extraActionsArray
124
-
125
- }
126
-
127
- @httpGet('/')
128
- public async index(@request() req: IRequest, @response() res: Response) {
129
-
130
- if (!this.validateRequest(req, res)) {
131
- return
132
- }
133
-
134
- const paginateParams = this.paginateParams(req);
135
- const searchableSubString = req.query.filter? new RegExp(req.query.filter as string, 'i'): undefined
136
- const scope = req.query.scope as string
137
- const currentUser = req.user
138
- const modelName = req.params.resource;
139
-
140
- const resource = this.resource ?? getResource(modelName, this.resources ?? []);
141
- if(!resource) {
142
- return ResponseUtils.notFound(res, 'Resource not found', []);
143
- }
144
- const repository = this.repository as Repository<Document> ?? new Repository(resource.properties.resource);
145
- const modifiedResource = ResourceGenerator.generate(resource)
146
-
147
- const sort = req.query.order
148
- const sortBy = req.query.orderBy as string
149
-
150
- const sortQuery: {[key:string]: any} = {}
151
- sortQuery[sortBy] = sort
152
-
153
- if (sortBy !== '_id') {
154
- sortQuery._id = 'asc'
155
- }
156
-
157
- const populate = req.query.populate as string | undefined;
158
-
159
- var filter: {[key:string]: any} = {}
160
-
161
-
162
-
163
- const crudOperations = resource.properties.crudOperations
164
-
165
- if (crudOperations && crudOperations.index) {
166
- filter = crudOperations.index.before(filter, currentUser)
167
- }
168
-
169
- if (scope) {
170
- filter = this.getScopeFilter(filter, scope)
171
- }
172
-
173
- if (searchableSubString) {
174
- filter = this.getSearchableSubStringFilter(resource, filter, searchableSubString)
175
- }
176
-
177
- var records: any[] = []
178
- var pageInfo = undefined
179
-
180
- if (!req.query.page && !req.query.perPage) {
181
-
182
- records = await repository.findMany({
183
- sort: sortQuery,
184
- filter,
185
- populate: modifiedResource.properties.populatedString
186
- })
187
- }
188
-
189
- else {
190
-
191
- const page = await repository.paginate({
192
- sort: sortQuery,
193
- filter,
194
- paginateParams: paginateParams,
195
- populate: modifiedResource.properties.populatedString
196
- });
197
-
198
- records = page.records
199
- pageInfo = page.pageInfo
200
- }
201
-
202
-
203
- var documents: any[] = []
204
-
205
- for (var i = 0; i < records.length; i++) {
206
-
207
- const record = records[i]
208
-
209
- const extraActionKeys = await this.getVisibileExtrsActions(currentUser, record, resource, repository, modifiedResource.properties.modelName)
210
-
211
- if (extraActionKeys) {
212
-
213
- const recordFlatten = record.toObject()
214
- recordFlatten.extraActionKeys = extraActionKeys
215
- documents.push(recordFlatten)
216
- }
217
-
218
- else {
219
- documents.push(record)
220
- }
221
- }
222
-
223
-
224
- return ResponseUtils.send(res, 200, 'OK', {
225
- records: documents,
226
- pageInfo,
227
- //options: modifiedResource
228
- });
229
-
230
- }
231
-
232
- @httpPost('/')
233
- public async create(@request() req: IRequest, @response() res: Response) {
234
-
235
- if (!this.validateRequest(req, res)) {
236
- return
237
- }
238
- const modelName = req.params.resource;
239
- const resource = this.resource ?? getResource(modelName, this.resources ?? []);
240
-
241
- if(!resource) {
242
- return ResponseUtils.notFound(res, 'Resource not found', []);
243
- }
244
-
245
- const repository = this.repository! as Repository<Document> ?? new Repository(resource.properties.resource);
246
- const modifiedResource = ResourceGenerator.generate(resource)
247
-
248
- var recordParams = req.body;
249
- const currentUser = req.user
250
-
251
- const crudOperations = resource.properties.crudOperations
252
-
253
- if (crudOperations && crudOperations.create) {
254
- recordParams = crudOperations.create.before(recordParams, currentUser)
255
- }
256
-
257
- var record: any
258
-
259
- if (recordParams.password) {
260
-
261
- const user = new Mongoose.prototype.model(modifiedResource.properties.modelName)(recordParams);
262
- const set = await user.setPassword(recordParams.password);
263
- record = await repository.saveInstance(user);
264
- }
265
-
266
- else {
267
- record = await repository.save(recordParams);
268
- }
269
-
270
-
271
- if (!record.isValid() || !record.document) {
272
- return ResponseUtils.unprocessable(res, 'Invalid Data', record.getErrors());
273
- }
274
-
275
- return ResponseUtils.created(res, {
276
- record
277
- });
278
-
279
- }
280
-
281
- @httpPatch('/:id')
282
- public async update(@request() req: IRequest, @response() res: Response) {
283
-
284
- if (!this.validateRequest(req, res)) {
285
- return
286
- }
287
- const modelName = req.params.resource;
288
- const resource = this.resource ?? getResource(modelName, this.resources ?? []);
289
-
290
- if(!resource) {
291
- return ResponseUtils.notFound(res, 'Resource not found', []);
292
- }
293
- const repository = this.repository! as Repository<Document> ?? new Repository(resource.properties.resource);
294
- const recordId = req.params.id as string;
295
- var recordParams = req.body ;
296
-
297
- var record = await repository.findById(recordId);
298
-
299
- if (!record) {
300
- return ResponseUtils.send(res, 404, 'record Not Found');
301
- }
302
-
303
- const recordSaveResult = await repository.update(record, recordParams);
304
-
305
- if (!recordSaveResult.isValid()) {
306
- return ResponseUtils.unprocessable(res, 'Invalid Data', recordSaveResult.getErrors());
307
- }
308
-
309
- // if (resource.properties.modelName === ModelNames.Settings) {
310
- // await AppSettings.run()
311
- // }
312
-
313
- return ResponseUtils.ok(res, {
314
- record: recordSaveResult
315
- });
316
-
317
- }
318
-
319
- @httpGet('/:id')
320
- public async show(@request() req: IRequest, @response() res: Response) {
321
-
322
- if (!this.validateRequest(req, res)) {
323
- return
324
- }
325
- const modelName = req.params.resource
326
- const recordId = req.params.id as string;
327
- const resource = this.resource ?? getResource(modelName, this.resources ?? []);
328
-
329
- if(!resource) {
330
- return ResponseUtils.notFound(res, 'Resource not found', []);
331
- }
332
-
333
- const repository = this.repository! as Repository<Document> ?? new Repository(resource.properties.resource)
334
- const modifiedResource = ResourceGenerator.generate(resource)
335
-
336
- var record = await repository.findOne({
337
-
338
- filter: {
339
- _id: recordId
340
- },
341
- populate: modifiedResource.properties.populatedString
342
- })
343
-
344
- if (!record) {
345
- return ResponseUtils.send(res, 404, 'record not found');
346
- }
347
-
348
- record = record.toObject()
349
- //record = await this.getExtras(record._id.toString(), record, this.getExtraRepository())
350
- record = await ResourcesHelper.addExtraFields(modifiedResource.showProperties, modifiedResource.properties.model, record, StringUtils.lowerCaseFirstLetter(modifiedResource.properties.modelName), repository)
351
-
352
- return ResponseUtils.ok(res, {
353
- record: record ? record : null,
354
- // options: modifiedResource
355
- });
356
-
357
- }
358
-
359
- @httpDelete('/:id')
360
- public async delete(@request() req: IRequest, @response() res: Response) {
361
-
362
- if (!this.validateRequest(req, res)) {
363
- return
364
- }
365
- const modelName = req.params.resource
366
- const recordId = req.params.id as string;
367
- const resource = this.resource ?? getResource(modelName, this.resources ?? []);
368
-
369
- if(!resource) {
370
- return ResponseUtils.notFound(res, 'Resource not found', []);
371
- }
372
-
373
- const repository = this.repository! as Repository<Document> ?? new Repository(resource.properties.resource);
374
-
375
- const record = await repository.findById(recordId);
376
-
377
- if (!record) {
378
- return ResponseUtils.send(res, 404, 'record Not Found');
379
- }
380
-
381
- await repository.remove({ _id: record._id });
382
-
383
- return ResponseUtils.send(res, 200, 'OK');
384
-
385
- }
386
-
387
-
388
- }
@@ -1,62 +0,0 @@
1
- import { Request, Response } from 'express';
2
- import { httpGet, request, response } from 'inversify-express-utils';
3
-
4
-
5
- import ResponseUtils from '../utils/ResponseUtils';
6
-
7
- import { __ } from 'i18n';
8
- import StringUtils from '../utils/StringUtils';
9
- import { IResourceFile } from '../types/IResourceFile';
10
- import ResourceGenerator from '../helpers/ResourceGenerator';
11
- import { inject, injectable } from 'inversify';
12
- import { IRequest } from '../middlewares/isAuth';
13
-
14
- export default class ResourceController {
15
-
16
- constructor(private resourceFiles: IResourceFile[]) {
17
-
18
- }
19
-
20
- @httpGet('/')
21
- public async index(@request() req: IRequest, @response() res: Response) {
22
-
23
- var modifiedResource : {[key:string]: any} = {}
24
- modifiedResource.modelParents = {}
25
-
26
- for (var i = 0; i < this.resourceFiles.length; i++) {
27
-
28
- const resource = this.resourceFiles[i]
29
-
30
- const adaptedResource = ResourceGenerator.generate(resource)
31
- const modelName = StringUtils.lowerCaseFirstLetter(adaptedResource.properties.modelName)
32
- modifiedResource[modelName] = adaptedResource
33
-
34
- if (modifiedResource.modelParents[adaptedResource.properties.parent.name]) {
35
- modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName)
36
- }
37
-
38
- else {
39
- modifiedResource.modelParents[adaptedResource.properties.parent.name] = []
40
- modifiedResource.modelParents[adaptedResource.properties.parent.name].push(modelName)
41
- }
42
- }
43
-
44
- return ResponseUtils.send(res, 200, 'OK', {
45
- resources: modifiedResource
46
- });
47
- }
48
-
49
- @httpGet('/:modelName')
50
- public async getOne(@request() req: IRequest, @response() res: Response) {
51
-
52
- const modelName = req.params.modelName as string;
53
- const resourceName = modelName + 'Resource'
54
- const resourceFilePath = '@pbb/materialUi/' + resourceName
55
- const resource = await import(resourceFilePath)
56
-
57
- return ResponseUtils.send(res, 200, 'OK', {
58
- options: ResourceGenerator.generate(resource[resourceName])
59
- });
60
- }
61
-
62
- }