@simitgroup/simpleapp-generator 2.0.0-t-alpha → 2.0.0-u-alpha

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 (49) hide show
  1. package/ReleaseNote.md +12 -1
  2. package/dist/buildinschemas/autoincreament.js +1 -1
  3. package/dist/buildinschemas/docnoformat.js +1 -1
  4. package/dist/buildinschemas/docnoformat.js.map +1 -1
  5. package/dist/buildinschemas/documentevent.js +1 -1
  6. package/dist/generate.d.ts.map +1 -1
  7. package/dist/generate.js +49 -26
  8. package/dist/generate.js.map +1 -1
  9. package/package.json +1 -1
  10. package/src/generate.ts +116 -93
  11. package/templates/nest/src/simple-app/_core/features/mini-app/developer-portal/developer-portal.service.ts.eta +9 -25
  12. package/templates/nest/src/simple-app/_core/framework/base/simple-app.service.ts.eta +76 -3
  13. package/templates/nest/src/simple-app/_core/framework/schemas/others.schema.ts.eta +12 -1
  14. package/dist/buildinschemas/message.d.ts +0 -3
  15. package/dist/buildinschemas/message.d.ts.map +0 -1
  16. package/dist/buildinschemas/message.js +0 -34
  17. package/dist/buildinschemas/message.js.map +0 -1
  18. package/dist/buildinschemas/webhookhistory.d.ts +0 -3
  19. package/dist/buildinschemas/webhookhistory.d.ts.map +0 -1
  20. package/dist/buildinschemas/webhookhistory.js +0 -44
  21. package/dist/buildinschemas/webhookhistory.js.map +0 -1
  22. package/dist/createproject.js +0 -138
  23. package/dist/createproject.js.map +0 -1
  24. package/dist/generate-allow-changebackend.js +0 -305
  25. package/dist/generate-allow-changebackend.js.map +0 -1
  26. package/dist/index2.js +0 -118
  27. package/dist/index2.js.map +0 -1
  28. package/dist/installdependency.js +0 -20
  29. package/dist/installdependency.js.map +0 -1
  30. package/dist/installnest.js +0 -2
  31. package/dist/installnest.js.map +0 -1
  32. package/dist/installnuxt.js +0 -2
  33. package/dist/installnuxt.js.map +0 -1
  34. package/dist/processors/groupsbuilder.js +0 -2
  35. package/dist/processors/groupsbuilder.js.map +0 -1
  36. package/dist/schematype/baseschema.js +0 -25
  37. package/dist/schematype/baseschema.js.map +0 -1
  38. package/dist/schematype/default.js +0 -2
  39. package/dist/schematype/default.js.map +0 -1
  40. package/dist/schematype/index.js +0 -12
  41. package/dist/schematype/index.js.map +0 -1
  42. package/dist/schematype/primarymasterdata.js +0 -38
  43. package/dist/schematype/primarymasterdata.js.map +0 -1
  44. package/dist/schematype/simple.js +0 -24
  45. package/dist/schematype/simple.js.map +0 -1
  46. package/dist/schematype/simplemasterdata.js +0 -31
  47. package/dist/schematype/simplemasterdata.js.map +0 -1
  48. package/dist/schematype/transaction.js +0 -74
  49. package/dist/schematype/transaction.js.map +0 -1
package/src/generate.ts CHANGED
@@ -30,8 +30,27 @@ import _ from 'lodash';
30
30
  import * as buildinschemas from './buildinschemas';
31
31
  import { JSONSchema7 } from 'json-schema';
32
32
  import { generatePrintformat } from './processors/jrxmlbuilder';
33
- const skipIsolationDocument = ['tenant','organization','branch','permission','user']
34
- const systemResources = ['user','tenant','organization','branch','permission','keyvaluepair','customfield','miniapp','miniappinstallation','systemmessage','queuejob','documentnoformat']
33
+ const skipIsolationDocument = [
34
+ 'tenant',
35
+ 'organization',
36
+ 'branch',
37
+ 'permission',
38
+ 'user'
39
+ ];
40
+ const systemResources = [
41
+ 'user',
42
+ 'tenant',
43
+ 'organization',
44
+ 'branch',
45
+ 'permission',
46
+ 'keyvaluepair',
47
+ 'customfield',
48
+ 'miniapp',
49
+ 'miniappinstallation',
50
+ 'systemmessage',
51
+ 'queuejob',
52
+ 'documentnoformat'
53
+ ];
35
54
  const { Eta } = require('eta');
36
55
  const { capitalizeFirstLetter } = require('./libs');
37
56
  // const X_DOCUMENT_TYPE='x-document-type'
@@ -106,18 +125,18 @@ export const run = async (
106
125
  for (let j = 0; j < files.length; j++) {
107
126
  const file = files[j];
108
127
  const filenamearr = file.split('.');
109
- if (_.last(filenamearr) != 'json'){
110
- log.warn(file," skip")
128
+ if (_.last(filenamearr) != 'json') {
129
+ log.warn(file, ' skip');
111
130
  continue;
112
131
  }
113
-
132
+
114
133
  const fullfilename = `${configs.jsonschemaFolder}/${file}`;
115
134
  try {
116
135
  const jsoncontent = readFileSync(fullfilename, 'utf-8');
117
136
  // log.info("Process ",fullfilename)
118
137
  // console.log("=====>>>>>",fullfilename)
119
138
  const jsonschema = JSON.parse(jsoncontent);
120
- const schemaconfig:SchemaConfig = jsonschema['x-simpleapp-config'];
139
+ const schemaconfig: SchemaConfig = jsonschema['x-simpleapp-config'];
121
140
  if (schemaconfig['printFormats']) {
122
141
  const formats: SchemaPrintFormat[] = schemaconfig['printFormats'];
123
142
  for (let formatno = 0; formatno < formats.length; formatno++) {
@@ -173,7 +192,7 @@ const processSchema = async (schemaname: string, jsondata: JSONSchema7) => {
173
192
  const config: SchemaConfig = jsondata['x-simpleapp-config'];
174
193
  let doctype = config.documentType;
175
194
  let docname = config.documentName;
176
- let resourceName = config.resourceName
195
+ let resourceName = config.resourceName;
177
196
  const rendertype = 'basic';
178
197
  jsonschemas[docname] = jsondata;
179
198
  const copyofjsonschema = { ...jsondata };
@@ -184,23 +203,22 @@ const processSchema = async (schemaname: string, jsondata: JSONSchema7) => {
184
203
  (item) => item.doctype == doctype
185
204
  );
186
205
  if (moduleindex < 0) {
187
-
188
- const api = config.additionalApis ?? []
189
- if(copyofjsonschema['x-simpleapp-config']['printFormats']){
190
- api.push({
191
- "action": "runPrint",
192
- "method": RESTMethods.get,
193
- "entryPoint": ":id/print/:formatId",
194
- "responseType": "String",
195
- "requiredRole": ["User"],
196
- "description": "print pdf"
197
- })
206
+ const api = config.additionalApis ?? [];
207
+ if (copyofjsonschema['x-simpleapp-config']['printFormats']) {
208
+ api.push({
209
+ action: 'runPrint',
210
+ method: RESTMethods.get,
211
+ entryPoint: ':id/print/:formatId',
212
+ responseType: 'String',
213
+ requiredRole: ['User'],
214
+ description: 'print pdf'
215
+ });
198
216
  }
199
217
  activatemodules.push({
200
218
  doctype: doctype,
201
219
  docname: capitalizeFirstLetter(docname),
202
220
  resourcename: resourceName,
203
- typename:capitalizeFirstLetter(resourceName),
221
+ typename: capitalizeFirstLetter(resourceName),
204
222
  pagetype: config.pageType ?? '',
205
223
  api: api,
206
224
  schema: copyofjsonschema
@@ -232,45 +250,46 @@ const generateSchema = (
232
250
  const finalizefolder = `${constants.templatedir}/nest`;
233
251
  const modelname = _.upperFirst(docname);
234
252
  const currentmodel = allmodels[modelname];
235
- const xconfig:SchemaConfig = jsonschemas[docname]?.['x-simpleapp-config']
236
- const apiSettings = currentmodel.apiSettings?? []
253
+ const xconfig: SchemaConfig = jsonschemas[docname]?.['x-simpleapp-config'];
254
+ const apiSettings = currentmodel.apiSettings ?? [];
237
255
  const resourceName = xconfig?.resourceName ?? docname;
238
- if(xconfig.getPhoto){
239
- apiSettings.push( {
240
- action: 'getPhoto',
241
- entryPoint: ':id/photo',
242
- requiredRole: ['Everyone'],
243
- method: RESTMethods.get,
244
- responseType: 'String',
245
- description: 'Get photo'
246
- },)
247
- jsonschemas['imageUrl']={type:'string'}
256
+ if (xconfig.getPhoto) {
257
+ apiSettings.push({
258
+ action: 'getPhoto',
259
+ entryPoint: ':id/photo',
260
+ requiredRole: ['Everyone'],
261
+ method: RESTMethods.get,
262
+ responseType: 'String',
263
+ description: `Get ${capitalizeFirstLetter(resourceName)} photo`
264
+ });
265
+ jsonschemas['imageUrl'] = { type: 'string' };
248
266
  }
249
- if(xconfig.uploadPhoto){
250
- apiSettings.push( {
251
- action: 'uploadPhoto',
252
- entryPoint: ':id/photo',
253
- requiredRole: [capitalizeFirstLetter(resourceName)+'_create'],
254
- schema: 'KeyValue',
255
- method: RESTMethods.post,
256
- responseType: 'String',
257
- description: 'upload photo'
258
- },)
267
+
268
+ if (xconfig.uploadPhoto) {
269
+ apiSettings.push({
270
+ action: 'uploadPhoto',
271
+ entryPoint: ':id/photo',
272
+ requiredRole: [capitalizeFirstLetter(resourceName) + '_create'],
273
+ schema: 'UploadPhoto',
274
+ method: RESTMethods.post,
275
+ responseType: 'String',
276
+ description: `Upload ${capitalizeFirstLetter(resourceName)} photo`
277
+ });
259
278
  }
260
-
261
- if(Array.isArray(xconfig.printFormats) && xconfig.printFormats.length>0){
262
- apiSettings.push( {
263
- action: 'print',
264
- entryPoint: ':id/print/:formatId',
265
- requiredRole: [capitalizeFirstLetter(resourceName)+'_print'],
266
- method: RESTMethods.get,
267
- responseType: 'String',
268
- description: 'obtain base64 pdf'
269
- },)
279
+
280
+ if (Array.isArray(xconfig.printFormats) && xconfig.printFormats.length > 0) {
281
+ apiSettings.push({
282
+ action: 'print',
283
+ entryPoint: ':id/print/:formatId',
284
+ requiredRole: [capitalizeFirstLetter(resourceName) + '_print'],
285
+ method: RESTMethods.get,
286
+ responseType: 'String',
287
+ description: 'obtain base64 pdf'
288
+ });
270
289
  }
271
290
  // if(xconfig)
272
-
273
- const resourceFileName = camelToKebab(resourceName)
291
+
292
+ const resourceFileName = camelToKebab(resourceName);
274
293
  //console.log("---^^^^^------",modelname,docname, doctype, rendertype,currentmodel,allmodels)
275
294
 
276
295
  const miniAppWhitelistApis =
@@ -281,7 +300,7 @@ const generateSchema = (
281
300
  doctype: doctype,
282
301
  models: allmodels,
283
302
  getPhoto: xconfig.getPhoto,
284
- uploadPhoto:xconfig.uploadPhoto,
303
+ uploadPhoto: xconfig.uploadPhoto,
285
304
  autocompletecode: currentmodel.codeField ?? '',
286
305
  autocompletename: currentmodel.nameField ?? '',
287
306
  moreAutoComplete: currentmodel.moreAutoComplete ?? [],
@@ -310,7 +329,6 @@ const generateSchema = (
310
329
  hasMiniAppWhitelistedApi: Object.keys(miniAppWhitelistApis).length > 0
311
330
  }
312
331
  };
313
-
314
332
 
315
333
  const templatefolder = `${constants.templatedir}/${rendertype}`;
316
334
  // log.info(`- Generate ${docname}, ${doctype}, ${templatefolder}`)
@@ -330,7 +348,7 @@ const generateSchema = (
330
348
  //generate code for every schema
331
349
  const generateTemplatefolder = `${constants.templatedir}/basic/${foldertype}`;
332
350
  const allfiles = readdirSync(generateTemplatefolder, { recursive: true });
333
-
351
+
334
352
  for (let j = 0; j < allfiles.length; j++) {
335
353
  const filename: string = String(allfiles[j]);
336
354
  const templatepath = `${generateTemplatefolder}/${filename}`;
@@ -363,8 +381,8 @@ const generateSchema = (
363
381
  if (autogeneratetypes.includes(filecategory)) {
364
382
  //multiple files in folder, append s at folder name
365
383
  let storein = `${backendTargetFolder}/_resources/${resourceFileName}`;
366
- if(systemResources.includes(docname)){
367
- storein=`${backendTargetFolder}/_core/resources/${resourceFileName}`
384
+ if (systemResources.includes(docname)) {
385
+ storein = `${backendTargetFolder}/_core/resources/${resourceFileName}`;
368
386
  }
369
387
  const targetfile = `${storein}/${resourceFileName}.${filecategory}.${filetype}`;
370
388
  if (!existsSync(storein)) {
@@ -374,21 +392,21 @@ const generateSchema = (
374
392
  const filecontent = eta.render(templatepath, variables);
375
393
  writeFileSync(targetfile, filecontent);
376
394
  // console.log("Write complete")
377
- } else if(['api'].includes(filecategory)){
378
- //if no define additional api, then no prepare additional api
395
+ } else if (['api'].includes(filecategory)) {
396
+ //if no define additional api, then no prepare additional api
379
397
  // continue
380
- if(variables.apiSettings.length==0){
381
- continue;
382
- }else{
383
- log.info("process additional api",docname);
398
+ if (variables.apiSettings.length == 0) {
399
+ continue;
400
+ } else {
401
+ log.info('process additional api', docname);
384
402
  }
385
403
 
386
- const arrcategory = filename.split('.')
404
+ const arrcategory = filename.split('.');
387
405
  // console.log("process",docname, arrcategory);
388
- const subcategory = arrcategory[0]
389
- const subcategoryscope = arrcategory[1]
390
- const subcategorytype = arrcategory[2]
391
-
406
+ const subcategory = arrcategory[0];
407
+ const subcategoryscope = arrcategory[1];
408
+ const subcategorytype = arrcategory[2];
409
+
392
410
  const targetfolder = `${simpleappTargetFolder}/${subcategory}s/${resourceFileName}-api`;
393
411
  const targetfile = `${targetfolder}/${resourceFileName}-api.${subcategoryscope}.${subcategorytype}`;
394
412
  if (!existsSync(targetfolder)) {
@@ -396,10 +414,12 @@ const generateSchema = (
396
414
  }
397
415
 
398
416
  //if controller will always override
399
- if ( targetfile.includes('controller') || targetfile.includes('resolver') ||
400
- (!existsSync(targetfile) ||
417
+ if (
418
+ targetfile.includes('controller') ||
419
+ targetfile.includes('resolver') ||
420
+ !existsSync(targetfile) ||
401
421
  readFileSync(targetfile, 'utf-8').includes(
402
- '--remove-this-line-to-prevent-override--')
422
+ '--remove-this-line-to-prevent-override--'
403
423
  )
404
424
  ) {
405
425
  // log.info("Write ",targetfile)
@@ -408,14 +428,14 @@ const generateSchema = (
408
428
  } else {
409
429
  // log.info("skip ",targetfile)
410
430
  }
411
- }else if (['event'].includes(filecategory)) {
431
+ } else if (['event'].includes(filecategory)) {
412
432
  //service file won't override if exists
413
- const arrcategory = filename.split('.')
414
- console.log("process",docname, arrcategory);
415
- const subcategory = arrcategory[0]
416
- const subcategoryscope = arrcategory[1]
417
- const subcategorytype = arrcategory[2]
418
-
433
+ const arrcategory = filename.split('.');
434
+ console.log('process', docname, arrcategory);
435
+ const subcategory = arrcategory[0];
436
+ const subcategoryscope = arrcategory[1];
437
+ const subcategorytype = arrcategory[2];
438
+
419
439
  const targetfolder = `${simpleappTargetFolder}/${subcategory}s/${resourceFileName}`;
420
440
  const targetfile = `${targetfolder}/${resourceFileName}.${subcategoryscope}.${subcategorytype}`;
421
441
  if (!existsSync(targetfolder)) {
@@ -423,10 +443,11 @@ const generateSchema = (
423
443
  }
424
444
 
425
445
  //if controller will always override
426
- if ( targetfile.includes('controller.ts') ||
427
- (!existsSync(targetfile) ||
446
+ if (
447
+ targetfile.includes('controller.ts') ||
448
+ !existsSync(targetfile) ||
428
449
  readFileSync(targetfile, 'utf-8').includes(
429
- '--remove-this-line-to-prevent-override--')
450
+ '--remove-this-line-to-prevent-override--'
430
451
  )
431
452
  ) {
432
453
  // log.info("Write ",targetfile)
@@ -742,7 +763,7 @@ const processPlatformFileMiniApi = (
742
763
  ) => {
743
764
  const mapfiles = {
744
765
  'resource.service.ts.eta': {
745
- to: `src/mini-app/resource/resources/${_.kebabCase(resourceName)}`,
766
+ to: `src/modules/resource/resources/${_.kebabCase(resourceName)}`,
746
767
  as: `${_.kebabCase(resourceName)}.service.ts`,
747
768
  validate: (targetfile: string, isexists: boolean) => {
748
769
  const {
@@ -757,7 +778,7 @@ const processPlatformFileMiniApi = (
757
778
  }
758
779
  },
759
780
  'resource.controller.ts.eta': {
760
- to: `src/mini-app/resource/resources/${_.kebabCase(resourceName)}`,
781
+ to: `src/modules/resource/resources/${_.kebabCase(resourceName)}`,
761
782
  as: `${_.kebabCase(resourceName)}.controller.ts`,
762
783
  validate: (targetfile: string, isexists: boolean) => {
763
784
  const {
@@ -772,7 +793,7 @@ const processPlatformFileMiniApi = (
772
793
  }
773
794
  },
774
795
  'resource.module.ts.eta': {
775
- to: `src/mini-app/resource/resources/${_.kebabCase(resourceName)}`,
796
+ to: `src/modules/resource/resources/${_.kebabCase(resourceName)}`,
776
797
  as: `${_.kebabCase(resourceName)}.module.ts`,
777
798
  validate: (targetfile: string, isexists: boolean) => {
778
799
  const {
@@ -905,11 +926,10 @@ const prepareRoles = (groupsettings) => {
905
926
  };
906
927
 
907
928
  function camelToKebab(key) {
908
- var result = key.replace( /([A-Z])/g, " $1" );
909
- return result.split(' ').join('-').toLowerCase();
929
+ var result = key.replace(/([A-Z])/g, ' $1');
930
+ return result.split(' ').join('-').toLowerCase();
910
931
  }
911
932
 
912
-
913
933
  const getCodeGenHelper = () =>
914
934
  'const capitalizeFirstLetter = (str) => !str ? `Object` : str.slice(0, 1).toUpperCase() + str.slice(1);' +
915
935
  'const initType=(str)=>{return ["string","number","boolean","array","object"].includes(str) ? capitalizeFirstLetter(str) : str;};' +
@@ -918,8 +938,11 @@ const getCodeGenHelper = () =>
918
938
  'const camelToKebab = (value) => { return value.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); };' +
919
939
  'const removeSuffix = (input, suffix) => { return input.endsWith(suffix) ? input.slice(0, -suffix.length) : input };' +
920
940
  'const isWhitelistedMiniApp = (actionName, it) => { return it.miniApp.whitelistApis?.[actionName] === true };' +
921
- 'const titleCase = (value) => { return value.replace(/([a-z])([A-Z])/g, "$1 $2"); }; '+
922
- 'const systemType = () => [ "String","Number","Boolean","Array","Object"];'+
923
- 'const toTypeName = (resName,fieldName)=>{return ["string","number","boolean","array","object"].includes(fieldName.toLowerCase())? capitalizeFirstLetter(fieldName) :upperFirstCase(resName) + fieldName.slice(resName.length)};'+
924
- 'const skipIsolationDocument = () => ' + JSON.stringify(skipIsolationDocument)+';'+
925
- 'const getSystemResources = () => '+JSON.stringify(systemResources);
941
+ 'const titleCase = (value) => { return value.replace(/([a-z])([A-Z])/g, "$1 $2"); }; ' +
942
+ 'const systemType = () => [ "String","Number","Boolean","Array","Object"];' +
943
+ 'const toTypeName = (resName,fieldName)=>{return ["string","number","boolean","array","object"].includes(fieldName.toLowerCase())? capitalizeFirstLetter(fieldName) :upperFirstCase(resName) + fieldName.slice(resName.length)};' +
944
+ 'const skipIsolationDocument = () => ' +
945
+ JSON.stringify(skipIsolationDocument) +
946
+ ';' +
947
+ 'const getSystemResources = () => ' +
948
+ JSON.stringify(systemResources);
@@ -7,37 +7,26 @@ import { InjectModel } from '@nestjs/mongoose';
7
7
  import { Model } from 'mongoose';
8
8
  import { UserContext } from 'src/simple-app/_core/features/user-context/user.context';
9
9
  import { MiniAppEnvEnum } from 'src/simple-app/_core/resources/mini-app/mini-app.enum';
10
- import { MiniAppInstallationService } from '@resources/mini-app-installation/mini-app-installation.service';
11
- import { MiniAppService } from '@resources/mini-app/mini-app.service';
12
- import { BranchService } from '@resources/branch/branch.service';
13
10
 
14
11
  @Injectable()
15
12
  export class DeveloperPortalService {
16
13
  constructor(
17
- // @InjectModel('Miniapp')
18
- // protected miniAppDoc: Model<MiniApp>,
19
- protected miniAppService: MiniAppService,
14
+ @InjectModel('MiniApp')
15
+ protected miniAppDoc: Model<MiniApp>,
20
16
 
21
- // @InjectModel('Miniappinstallation')
22
- // protected miniAppInstallationDoc: Model<MiniAppInstallation>,
23
- protected miniAppInstallationService: MiniAppInstallationService,
17
+ @InjectModel('MiniAppInstallation')
18
+ protected miniAppInstallationDoc: Model<MiniAppInstallation>,
24
19
 
25
- // @InjectModel('Branch')
26
- // protected branchDoc: Model<Branch>,
27
- protected branchService: BranchService,
20
+ @InjectModel('Branch')
21
+ protected branchDoc: Model<Branch>,
28
22
  ) {}
29
23
 
30
24
  async getDemoCompany(appUser: UserContext, developerPortalAppId: string) {
31
25
  // Only dev got development.demoXOrg field
32
- // const miniApp = await this.miniAppDoc.findOne({
33
- // 'developerPortal.appId': developerPortalAppId,
34
- // env: MiniAppEnvEnum.DEV,
35
- // });
36
- const miniApps = await this.miniAppService.search(appUser, {
26
+ const miniApp = await this.miniAppDoc.findOne({
37
27
  'developerPortal.appId': developerPortalAppId,
38
28
  env: MiniAppEnvEnum.DEV,
39
29
  });
40
- const miniApp = miniApps[0];
41
30
  if (miniApp && !_.isEmpty(miniApp?.development?.demoXOrg)) {
42
31
  return miniApp.development.demoXOrg;
43
32
  }
@@ -49,11 +38,7 @@ export class DeveloperPortalService {
49
38
  const demoXOrg = await this.getDemoCompany(appUser, developerPortalAppId);
50
39
 
51
40
  // Only get env === prod one
52
- // const miniAppInstallations = await this.miniAppInstallationDoc.find({
53
- // 'miniApp.developerPortalAppId': developerPortalAppId,
54
- // 'miniApp.env': MiniAppEnvEnum.PROD,
55
- // });
56
- const miniAppInstallations = await this.miniAppInstallationService.search(appUser, {
41
+ const miniAppInstallations = await this.miniAppInstallationDoc.find({
57
42
  'miniApp.developerPortalAppId': developerPortalAppId,
58
43
  'miniApp.env': MiniAppEnvEnum.PROD,
59
44
  });
@@ -82,8 +67,7 @@ export class DeveloperPortalService {
82
67
  };
83
68
 
84
69
  // Step 3: Run one query to get all branches
85
- // const allBranches = await this.branchDoc.find(branchFilter);
86
- const allBranches = await this.branchService.search(appUser, branchFilter);
70
+ const allBranches = await this.branchDoc.find(branchFilter);
87
71
 
88
72
  // Step 4: Build a lookup map: `${tenantId}-${orgId}-${branchId}` → branch
89
73
  const branchMap = new Map<string, Branch>();
@@ -23,6 +23,7 @@ import { SimpleAppLogService } from '../../features/log/log.service';
23
23
  import { UserContext } from '../../features/user-context/user.context';
24
24
  import { RunWebhookService } from '../../features/webhook/run-webhook.service';
25
25
  import { DeleteResultType, IsolationType, MoreProjectionType, PatchManyRequest, SchemaFields, TextSearchBody, UniqueKeyExistResponse } from '../schemas';
26
+ import { SearchWithRelation } from './dto/simple-app-search-with-relation.dto';
26
27
 
27
28
  @Injectable()
28
29
  export class SimpleAppService<T extends SchemaFields> {
@@ -106,7 +107,7 @@ export class SimpleAppService<T extends SchemaFields> {
106
107
  public isReadOnly(): boolean {
107
108
  return false;
108
109
  }
109
- reCalculateValue(data: T) { }
110
+ reCalculateValue(data: T) {}
110
111
  getIsolationFilter = (appuser: UserContext) => {
111
112
  let isolationFilter = {};
112
113
  switch (this.isolationtype) {
@@ -221,7 +222,7 @@ export class SimpleAppService<T extends SchemaFields> {
221
222
  throw new InternalServerErrorException('first aggregate pipelinestage shall use $match');
222
223
  }
223
224
  }
224
- async aggregate(appuser: UserContext, pipeline: PipelineStage[]) {
225
+ async aggregate<T = any>(appuser: UserContext, pipeline: PipelineStage[]) {
225
226
  if (pipeline[0] && pipeline[0]['$match']) {
226
227
  try {
227
228
  const isolationFilter = { ...this.getIsolationFilter(appuser) };
@@ -233,7 +234,7 @@ export class SimpleAppService<T extends SchemaFields> {
233
234
  // if(appuser.getId() == ''){
234
235
  // console.log(JSON.stringify(pipeline))
235
236
  // }
236
- const res = await this.doc.aggregate(pipeline, {
237
+ const res = await this.doc.aggregate<T>(pipeline, {
237
238
  session: appuser.getDBSession(),
238
239
  });
239
240
 
@@ -1304,4 +1305,76 @@ export class SimpleAppService<T extends SchemaFields> {
1304
1305
  async addManyAuditEvents(appUser: UserContext, documentName: string, eventType: string, datas: any) {
1305
1306
  await this.logService.addManyEvents(appUser, documentName, eventType, datas);
1306
1307
  }
1308
+
1309
+ async searchWithRelation<T>(appUser: UserContext, option: SearchWithRelation<T>, allowedRelations: string[]) {
1310
+ // Root Filter
1311
+ const pipeline: PipelineStage[] = [
1312
+ {
1313
+ $match: {
1314
+ ...(option.root?.filter ?? {}),
1315
+ },
1316
+ },
1317
+ ];
1318
+
1319
+ // Relation lookups
1320
+ Object.entries(option.relations).forEach(([relationName, relationOption]) => {
1321
+ // Prevent mini api user lookup sensitive data
1322
+ if (!allowedRelations.includes(relationName)) {
1323
+ throw new BadRequestException(`Not allowed to lookup ${relationName}`);
1324
+ }
1325
+
1326
+ const subPipeline: PipelineStage.Lookup['$lookup']['pipeline'] = [];
1327
+ const foreignField = `${this.documentName}._id`;
1328
+
1329
+ subPipeline.push({
1330
+ $match: {
1331
+ $expr: { $eq: [`$${foreignField}`, '$$resourceId'] },
1332
+ },
1333
+ ...relationOption.filter,
1334
+ });
1335
+
1336
+ // Relation sort
1337
+ if (relationOption.sort) {
1338
+ subPipeline.push({
1339
+ $sort: relationOption.sort,
1340
+ });
1341
+ }
1342
+
1343
+ // Relation projection
1344
+ if (relationOption.projection) {
1345
+ subPipeline.push({
1346
+ $project: {
1347
+ ...(relationOption.projection ?? {}),
1348
+ },
1349
+ });
1350
+ }
1351
+
1352
+ pipeline.push({
1353
+ $lookup: {
1354
+ from: relationName,
1355
+ as: `_${relationName}`,
1356
+ let: { resourceId: '$_id' },
1357
+ pipeline: subPipeline,
1358
+ },
1359
+ });
1360
+ });
1361
+
1362
+ // Root sort
1363
+ if (option.root?.sort) {
1364
+ pipeline.push({
1365
+ $sort: option.root.sort,
1366
+ });
1367
+ }
1368
+
1369
+ // Root Projection
1370
+ if (option.root.projection) {
1371
+ pipeline.push({
1372
+ $project: {
1373
+ ...(option.root?.projection ?? {}),
1374
+ },
1375
+ });
1376
+ }
1377
+
1378
+ return await this.aggregate(appUser, pipeline);
1379
+ }
1307
1380
  }
@@ -1,4 +1,4 @@
1
- import { ApiProperty } from '@nestjs/swagger';
1
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
2
  import { Field, ObjectType, ID } from '@nestjs/graphql';
3
3
  import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json';
4
4
 
@@ -81,6 +81,17 @@ export class KeyValue {
81
81
  id?: string;
82
82
  }
83
83
 
84
+ @ObjectType()
85
+ export class UploadPhoto {
86
+ @Field()
87
+ @ApiPropertyOptional({ type: () => String, nullable: true })
88
+ filename?: string | null;
89
+
90
+ @Field()
91
+ @ApiProperty({ type: () => String })
92
+ base64Image: string;
93
+ }
94
+
84
95
  @ObjectType()
85
96
  export class ImportErrorMessgeError {
86
97
  @Field()
@@ -1,3 +0,0 @@
1
- import { SchemaType } from '../type';
2
- export declare const docnoformat: SchemaType;
3
- //# sourceMappingURL=message.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/buildinschemas/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,SAAS,CAAA;AAE5D,eAAO,MAAM,WAAW,EAAC,UA6BtB,CAAA"}
@@ -1,34 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.docnoformat = void 0;
4
- const type_1 = require("../type");
5
- exports.docnoformat = {
6
- "type": "object",
7
- "x-simpleapp-config": {
8
- "documentType": "msg",
9
- "documentName": "message",
10
- "isolationType": type_1.IsolationType.tenant,
11
- "documentTitle": "messageTitle"
12
- },
13
- "properties": {
14
- "_id": { "type": "string" },
15
- "created": { "type": "string" },
16
- "updated": { "type": "string" },
17
- "createdBy": { "type": "string" },
18
- "updatedBy": { "type": "string" },
19
- "tenantId": { "type": "integer", "default": 1 },
20
- "orgId": { "type": "integer", "default": 1 },
21
- "branchId": { "type": "integer", "default": 1 },
22
- "messageTitle": {
23
- "type": "string",
24
- "minLength": 3
25
- },
26
- "read": { "type": "boolean", "default": false },
27
- "url": { "type": "string" },
28
- "description": {
29
- "type": "string",
30
- "format": "text"
31
- }
32
- }
33
- };
34
- //# sourceMappingURL=message.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/buildinschemas/message.ts"],"names":[],"mappings":";;;AAAA,kCAA4D;AAE/C,QAAA,WAAW,GACxB;IACI,MAAM,EAAE,QAAQ;IAChB,oBAAoB,EAAE;QACpB,cAAc,EAAE,KAAK;QACrB,cAAc,EAAE,SAAS;QACzB,eAAe,EAAE,oBAAa,CAAC,MAAM;QACrC,eAAe,EAAE,cAAc;KAChC;IACD,YAAY,EAAE;QACZ,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC3B,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC/B,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC/B,WAAW,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QACjC,WAAW,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;QACjC,UAAU,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAC/C,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE;QAC/C,cAAc,EAAE;YACd,MAAM,EAAE,QAAQ;YAChB,WAAW,EAAE,CAAC;SACf;QACD,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAC;QAC9C,KAAK,EAAC,EAAE,MAAM,EAAE,QAAQ,EAAC;QACzB,aAAa,EAAE;YACb,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,MAAM;SACjB;KACF;CACF,CAAA"}
@@ -1,3 +0,0 @@
1
- import { SchemaType } from '../type';
2
- export declare const webhookhistory: SchemaType;
3
- //# sourceMappingURL=webhookhistory.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhookhistory.d.ts","sourceRoot":"","sources":["../../src/buildinschemas/webhookhistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,SAAS,CAAA;AAE5D,eAAO,MAAM,cAAc,EAAC,UAsC3B,CAAA"}
@@ -1,44 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.webhookhistory = void 0;
4
- const type_1 = require("../type");
5
- exports.webhookhistory = {
6
- type: "object",
7
- "x-simpleapp-config": {
8
- documentType: 'webhookhistory',
9
- documentName: 'webhookhistory',
10
- isolationType: type_1.IsolationType.tenant,
11
- // uniqueKey:'documentName',
12
- // documentTitle:'documentName'
13
- // pageType:"crud",
14
- },
15
- required: ["documentName", "url"],
16
- properties: {
17
- _id: { type: 'string' },
18
- created: { type: 'string' },
19
- updated: { type: 'string' },
20
- createdBy: { type: 'string' },
21
- updatedBy: { type: 'string' },
22
- tenantId: { type: 'integer', default: 1, minimum: 0 },
23
- orgId: { type: 'integer', default: 1, minimum: 0 },
24
- branchId: { type: 'integer', default: 1, minimum: 0 },
25
- webHookId: { type: "string", format: "uuid" },
26
- url: { type: "string", format: 'uri' },
27
- authentication: { type: "string" },
28
- headers: {
29
- type: "array",
30
- items: {
31
- type: "object",
32
- description: "http headers",
33
- properties: {
34
- name: { type: 'string' },
35
- value: { type: 'string' }
36
- }
37
- }
38
- },
39
- description: { type: "string", format: "text" },
40
- setting: { type: "string", format: "text" },
41
- result: { type: "string" }
42
- }
43
- };
44
- //# sourceMappingURL=webhookhistory.js.map