identity-admin 1.28.30 → 1.28.32

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.
@@ -36,7 +36,7 @@ export default class DashboardController {
36
36
  index(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
37
37
  create(req: IRequest, res: Response): Promise<void>;
38
38
  update(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
39
- report(req: IRequest, res: Response): Promise<void>;
39
+ report(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
40
40
  show(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
41
41
  deleteAll(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
42
42
  delete(req: IRequest, res: Response): Promise<void | Response<any, Record<string, any>>>;
@@ -479,21 +479,27 @@ let DashboardController = DashboardController_1 = class DashboardController {
479
479
  if (crudOperations && crudOperations.index && crudOperations.index.before) {
480
480
  filter = yield crudOperations.index.before(req, filter, currentUser);
481
481
  }
482
+ const fields = ReportsGenerator_1.default.parseFields(req.query.fields);
483
+ if (fields.length === 0) {
484
+ return ResponseUtils_1.default.send(res, 400, 'fields query parameter is required');
485
+ }
486
+ const select = ReportsGenerator_1.default.buildSelect(fields);
487
+ const columnFieldKeys = ReportsGenerator_1.default.getColumnFieldKeys(fields);
482
488
  var records = [];
483
- const populatedString = modifiedResource.properties.populatedString;
484
- const populationHelper = new PopulationHelper_1.PopulationHelper(resource, PopulationHelper_1.PopulationType.LIST, populatedString);
489
+ const populatedString = modifiedResource.properties.populatedString
490
+ .split(' ')
491
+ .filter((field) => columnFieldKeys.some((key) => field === key || field.startsWith(key + '.')))
492
+ .join(' ');
493
+ const populationHelper = new PopulationHelper_1.PopulationHelper(resource, PopulationHelper_1.PopulationType.REPORT, populatedString);
485
494
  const modifiedPopulatedObject = yield populationHelper.get();
486
495
  records = yield repository.findMany({
487
496
  sort: sortQuery,
488
497
  filter,
489
498
  populate: modifiedPopulatedObject,
499
+ select,
500
+ lean: true,
490
501
  });
491
- var documents = [];
492
- for (var i = 0; i < records.length; i++) {
493
- const record = records[i];
494
- const recordFlatten = record.toObject();
495
- documents.push(recordFlatten);
496
- }
502
+ var documents = records;
497
503
  if (crudOperations && crudOperations.index && crudOperations.index.after) {
498
504
  try {
499
505
  documents = yield crudOperations.index.after(req, documents, currentUser);
@@ -502,18 +508,15 @@ let DashboardController = DashboardController_1 = class DashboardController {
502
508
  documents = yield crudOperations.index.after(req, records, currentUser);
503
509
  }
504
510
  }
505
- const fields = req.query.fields.map((v) => JSON.parse(v));
506
511
  const fileType = req.query.fileType;
507
512
  if (fileType === 'xlsx') {
508
- const buffer = ReportsGenerator_1.default.CreateXlsxFile(fields, documents, modelName, language, resource);
509
513
  res.writeHead(200, {
510
514
  'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
511
- 'Content-disposition': 'attachment;filename=' + `${modelName}.xlsx`,
512
- 'Content-Length': buffer.length,
515
+ 'Content-disposition': `attachment;filename=${modelName}.xlsx`,
513
516
  });
514
- res.end(buffer);
517
+ yield ReportsGenerator_1.default.CreateXlsxStream(fields, documents, modelName, language, resource, res);
515
518
  }
516
- if (fileType === 'pdf') {
519
+ else if (fileType === 'pdf') {
517
520
  const buffer = yield ReportsGenerator_1.default.CreatePdfFile(fields, documents, modelName, language, resource);
518
521
  res.writeHead(200, {
519
522
  'Content-Type': 'application/pdf',
@@ -522,6 +525,25 @@ let DashboardController = DashboardController_1 = class DashboardController {
522
525
  });
523
526
  res.end(buffer);
524
527
  }
528
+ else if (fileType === 'csv') {
529
+ res.writeHead(200, {
530
+ 'Content-Type': 'text/csv; charset=utf-8',
531
+ 'Content-disposition': `attachment;filename=${modelName}.csv`,
532
+ });
533
+ res.write('\uFEFF');
534
+ res.write(fields.map((f) => `"${f.label}"`).join(',') + '\r\n');
535
+ documents.forEach((record) => {
536
+ const row = fields.map((f) => {
537
+ const val = ReportsGenerator_1.default.getFieldValue(f, record, language, resource);
538
+ return `"${String(val !== null && val !== void 0 ? val : '').replace(/"/g, '""')}"`;
539
+ }).join(',');
540
+ res.write(row + '\r\n');
541
+ });
542
+ res.end();
543
+ }
544
+ if (!fileType) {
545
+ return ResponseUtils_1.default.send(res, 400, 'fileType query parameter is required');
546
+ }
525
547
  });
526
548
  }
527
549
  show(req, res) {
@@ -1,7 +1,8 @@
1
1
  import { IResourceFile } from "../types/IResourceFile";
2
2
  export declare enum PopulationType {
3
3
  LIST = "LIST",
4
- SHOW = "SHOW"
4
+ SHOW = "SHOW",
5
+ REPORT = "REPORT"
5
6
  }
6
7
  export declare class PopulationHelper {
7
8
  private resource;
@@ -14,6 +14,7 @@ var PopulationType;
14
14
  (function (PopulationType) {
15
15
  PopulationType["LIST"] = "LIST";
16
16
  PopulationType["SHOW"] = "SHOW";
17
+ PopulationType["REPORT"] = "REPORT";
17
18
  })(PopulationType = exports.PopulationType || (exports.PopulationType = {}));
18
19
  class PopulationHelper {
19
20
  constructor(resource, populationType, populatedString) {
@@ -27,7 +28,7 @@ class PopulationHelper {
27
28
  if (!populate) {
28
29
  return this.populatedString;
29
30
  }
30
- if (!populate.all && !populate.list && !populate.show) {
31
+ if (!populate.all && !populate.list && !populate.show && !populate.report) {
31
32
  return this.populatedString;
32
33
  }
33
34
  if (populate.all) {
@@ -38,6 +39,14 @@ class PopulationHelper {
38
39
  return yield populate.list(this.populatedString);
39
40
  }
40
41
  }
42
+ else if (this.populationType === PopulationType.REPORT) {
43
+ if (populate.report) {
44
+ return yield populate.report(this.populatedString);
45
+ }
46
+ if (populate.list) {
47
+ return yield populate.list(this.populatedString);
48
+ }
49
+ }
41
50
  else {
42
51
  if (populate.show) {
43
52
  return yield populate.show(this.populatedString);
@@ -17,10 +17,14 @@ export interface ILanguage {
17
17
  value?: string;
18
18
  }
19
19
  export default class ReportsGenerator {
20
+ static CreateXlsxStream(columns: Columns[], data: any[], name: string, language: Languages, resource: IResourceFile, stream: any): Promise<void>;
20
21
  static CreateXlsxFile(columns: Columns[], data: any[], name: string, language: Languages, resource: IResourceFile): Buffer;
21
22
  static CreatePdfFile(columns: Columns[], data: any[], name: string, language: Languages, resource: IResourceFile): Promise<Buffer>;
22
23
  static getRows(columns: Columns[], data: any[], language: Languages, resource: IResourceFile): any[][];
23
24
  static getFieldValue(field: Columns, row: any, language: Languages, resource: IResourceFile): any;
24
25
  static checkLocalizedStringExistence(columns: Columns[]): boolean;
26
+ static parseFields(queryFields: any): Columns[];
27
+ static buildSelect(fields: Columns[]): Record<string, number>;
28
+ static getColumnFieldKeys(fields: Columns[]): string[];
25
29
  static getReferenceValueByTitleType(rowValue: any, language: Languages, titleType?: FieldTypes): any;
26
30
  }
@@ -49,6 +49,24 @@ var Languages;
49
49
  Languages["ENGLISH"] = "en";
50
50
  })(Languages = exports.Languages || (exports.Languages = {}));
51
51
  class ReportsGenerator {
52
+ static CreateXlsxStream(columns, data, name, language, resource, stream) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ const ExcelJS = require('exceljs');
55
+ const workbook = new ExcelJS.stream.xlsx.WorkbookWriter({
56
+ stream,
57
+ useStyles: false,
58
+ useSharedStrings: false,
59
+ });
60
+ const worksheet = workbook.addWorksheet(name);
61
+ worksheet.addRow(columns.map(f => f.label)).commit();
62
+ data.forEach((record) => {
63
+ const row = columns.map((f) => this.getFieldValue(f, record, language, resource));
64
+ worksheet.addRow(row).commit();
65
+ });
66
+ worksheet.commit();
67
+ yield workbook.commit();
68
+ });
69
+ }
52
70
  static CreateXlsxFile(columns, data, name, language, resource) {
53
71
  const header = columns.map((field) => field.label);
54
72
  const rows = this.getRows(columns, data, language, resource);
@@ -64,7 +82,6 @@ class ReportsGenerator {
64
82
  }
65
83
  static CreatePdfFile(columns, data, name, language, resource) {
66
84
  return __awaiter(this, void 0, void 0, function* () {
67
- const rows = this.getRows(columns, data, language, resource);
68
85
  const ArabicFont = new pdfjs_1.default.Font(fs.readFileSync(__dirname + '/../assets/Amiri-Regular.ttf'));
69
86
  const localizedStringIsExisted = this.checkLocalizedStringExistence(columns);
70
87
  const doc = new pdfjs_1.default.Document({
@@ -85,14 +102,17 @@ class ReportsGenerator {
85
102
  textAlign: 'center',
86
103
  alignment: 'center',
87
104
  }));
88
- rows.forEach((row) => {
105
+ data.forEach((record) => {
89
106
  const tableRow = table.row();
90
- row.map((cell) => tableRow.cell(`${cell !== null && cell !== void 0 ? cell : '---'}`, {
91
- textAlign: 'center',
92
- alignment: 'center',
93
- paddingBottom: 5,
94
- paddingTop: 5,
95
- }));
107
+ columns.forEach((field) => {
108
+ const value = this.getFieldValue(field, record, language, resource);
109
+ tableRow.cell(`${value !== null && value !== void 0 ? value : '---'}`, {
110
+ textAlign: 'center',
111
+ alignment: 'center',
112
+ paddingBottom: 5,
113
+ paddingTop: 5,
114
+ });
115
+ });
96
116
  });
97
117
  return yield doc.asBuffer();
98
118
  });
@@ -132,6 +152,42 @@ class ReportsGenerator {
132
152
  static checkLocalizedStringExistence(columns) {
133
153
  return columns.some((column) => column.type === helpers_1.FieldTypes.LOCALIZEDSTRING);
134
154
  }
155
+ static parseFields(queryFields) {
156
+ if (!queryFields)
157
+ return [];
158
+ if (Array.isArray(queryFields)) {
159
+ return queryFields.map((v) => (typeof v === 'string' ? JSON.parse(v) : v));
160
+ }
161
+ return [];
162
+ }
163
+ static buildSelect(fields) {
164
+ const select = {};
165
+ fields.forEach((field) => {
166
+ const topField = field.value.split('.')[0];
167
+ select[topField] = 1;
168
+ if (field.titlePath) {
169
+ const topTitlePath = field.titlePath.split('.')[0];
170
+ select[topTitlePath] = 1;
171
+ }
172
+ });
173
+ return select;
174
+ }
175
+ static getColumnFieldKeys(fields) {
176
+ const keys = [];
177
+ fields.forEach((field) => {
178
+ const topField = field.value.split('.')[0];
179
+ if (!keys.includes(topField)) {
180
+ keys.push(topField);
181
+ }
182
+ if (field.titlePath) {
183
+ const topTitlePath = field.titlePath.split('.')[0];
184
+ if (!keys.includes(topTitlePath)) {
185
+ keys.push(topTitlePath);
186
+ }
187
+ }
188
+ });
189
+ return keys;
190
+ }
135
191
  static getReferenceValueByTitleType(rowValue, language, titleType) {
136
192
  if (!titleType)
137
193
  return rowValue;
@@ -12,6 +12,7 @@ interface IQueryOptions {
12
12
  skip?: number;
13
13
  paginateParams?: PaginateParams;
14
14
  populate?: any;
15
+ lean?: boolean;
15
16
  }
16
17
  export interface PageInfo {
17
18
  currentPage: number;
@@ -49,6 +49,7 @@ let Repository = Repository_1 = class Repository {
49
49
  const limit = this.getLimit(queryOptions);
50
50
  const skip = this.getSkip(queryOptions);
51
51
  const populate = queryOptions.populate;
52
+ const lean = queryOptions.lean;
52
53
  var query = this.model.find(filter);
53
54
  if (select) {
54
55
  query = query.select(select);
@@ -65,6 +66,9 @@ let Repository = Repository_1 = class Repository {
65
66
  if (populate) {
66
67
  query = query.populate(populate);
67
68
  }
69
+ if (lean) {
70
+ query = query.lean();
71
+ }
68
72
  return yield query;
69
73
  });
70
74
  }
@@ -36,6 +36,11 @@ interface IPopulate {
36
36
  * This function is called for the get one endpoint either in show or form an access over the populated string
37
37
  */
38
38
  show?: PopulateFunction;
39
+ /**
40
+ * This function is called for the report endpoint to have an access over the populated string.
41
+ * Falls back to populate.list if not defined.
42
+ */
43
+ report?: PopulateFunction;
39
44
  }
40
45
  interface Action {
41
46
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "identity-admin",
3
- "version": "1.28.30",
3
+ "version": "1.28.32",
4
4
  "description": "",
5
5
  "main": "lib/Dashboard.js",
6
6
  "types": "lib/Dashbord.d.ts",
@@ -50,6 +50,7 @@
50
50
  "connect-mongo": "^4.6.0",
51
51
  "cookie-parser": "^1.4.6",
52
52
  "deep-diff": "^1.0.2",
53
+ "exceljs": "^4.4.0",
53
54
  "express-session": "^1.17.3",
54
55
  "lodash": "^4.17.21",
55
56
  "memory-cache": "^0.2.0",