@simitgroup/simpleapp-generator 1.0.56 → 1.0.57
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.
- package/package.json +1 -1
- package/templates/basic/nest/processor.ts.eta +13 -73
- package/templates/nest/src/simpleapp/generate/commons/encryption.static.ts.eta +78 -0
- package/templates/nest/src/simpleapp/generate/commons/exceptions/SimpleAppExceptionFilter.ts.eta +15 -7
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +25 -16
- package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +2 -1
package/package.json
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { UserContext } from '../commons/user.context'
|
|
9
9
|
import { Injectable } from '@nestjs/common';
|
|
10
10
|
import { InjectModel } from '@nestjs/mongoose';
|
|
11
|
+
import * as jsonpath from 'jsonpath'
|
|
11
12
|
import { Model } from 'mongoose';
|
|
12
13
|
import {<%= it.typename%>JsonSchema } from '../jsonschemas/<%= it.doctype %>.jsonschema'
|
|
13
14
|
import { SimpleAppService,IsolationType,HookType } from './simpleapp.processor';
|
|
@@ -48,80 +49,19 @@ export class <%= it.typename %>Processor extends SimpleAppService<<%= it.typenam
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
reCalculateValue(){
|
|
52
|
-
console.log('trigger new recalculate')
|
|
53
|
-
|
|
52
|
+
reCalculateValue(data:<%= it.typename %>):<%= it.typename %>{
|
|
53
|
+
console.log('trigger new recalculate')
|
|
54
|
+
<% if(it.jsonschema['x-simpleapp-config']['formulas']){ %>
|
|
55
|
+
<%Object.keys(it.jsonschema['x-simpleapp-config']['formulas']).forEach(function(index) { %>
|
|
56
|
+
<% let fml = it.jsonschema['x-simpleapp-config']['formulas'][index] %>
|
|
57
|
+
// <%~ JSON.stringify(fml) %>
|
|
58
|
+
//const tmp = jsonpath.query(vdata,fieldpath).filter((item:string)=>item!='')
|
|
59
|
+
|
|
60
|
+
jsonpath.apply(data, '<%~ fml.jsonpath %>', function(value) { return <%~fml.formula %> });
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
<%
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
data.<%=key%> = <%= obj['x-compute'].function %>(
|
|
60
|
-
<% if(obj['x-compute'].paramters){ %>
|
|
61
|
-
<% let p = obj['x-compute'].paramters %>
|
|
62
|
-
<%for(let j=0; j<p.length; j++){%>
|
|
63
|
-
<%= p[j].replace('@data','data') %>,
|
|
64
|
-
<%}%>
|
|
65
|
-
<%}%>
|
|
66
|
-
)
|
|
67
|
-
<%}%>
|
|
68
|
-
<%if(obj.type=='array' && obj.items.type=='object'){%>
|
|
69
|
-
// process compute for 2nd level sub tables
|
|
70
|
-
for(let index=0;index<data.<%=key%>.length;index++){
|
|
71
|
-
<%Object.keys(obj.items.properties).forEach(function(subkey) { %>
|
|
72
|
-
<%let subobj = obj.items.properties[subkey]%>
|
|
73
|
-
<%if(subobj['x-compute']){%>
|
|
74
|
-
|
|
75
|
-
data.<%=key%>[index].<%=subkey%> = <%= subobj['x-compute'].function %>(
|
|
76
|
-
<% if(subobj['x-compute'].paramters){ %>
|
|
77
|
-
<% let subp = subobj['x-compute'].paramters %>
|
|
78
|
-
<%for(let k=0; k<subp.length; k++){%>
|
|
79
|
-
<%= subp[k].replace('@data','data').replace('@index','index') %>,
|
|
80
|
-
<%}%>
|
|
81
|
-
<%}%>
|
|
82
|
-
)
|
|
83
|
-
<%}%>
|
|
84
|
-
|
|
85
|
-
<% if(subobj.type=='array' && subobj.items && subobj.items.type=='object'){ %>
|
|
86
|
-
// process compute for 3rd level sub tables
|
|
87
|
-
for(let index2=0;index<data.<%=key%>[index].length;index2++){
|
|
88
|
-
<%Object.keys(subobj.items.properties).forEach(function(sub2key) { %>
|
|
89
|
-
<%let sub2obj = subobj.items.properties[sub2key]%>
|
|
90
|
-
<%if(sub2obj['x-compute']){%> //x-compute 3rd level field
|
|
91
|
-
data.<%=key%>[index].<%=subkey%>[index2].<%=sub2key%> = <%= sub2obj['x-compute'].function %>(
|
|
92
|
-
<% if(sub2obj['x-compute'].paramters){ %>
|
|
93
|
-
<% let sub2p = sub2obj['x-compute'].paramters %>
|
|
94
|
-
<%for(let l=0; l<sub2p.length; l++){%>
|
|
95
|
-
<%= sub2p[l].replace('@data','data').replace('@index','index').replace('@index2','index2') %>,
|
|
96
|
-
<%}%>
|
|
97
|
-
<%}%>
|
|
98
|
-
)
|
|
99
|
-
<%}%>
|
|
100
|
-
<%if(sub2obj.type=='array' && sub2obj.items && sub2obj.items.type=='object'){%>
|
|
101
|
-
// process compute for 4rd level sub tables
|
|
102
|
-
for(let index3=0;index<data.<%=key%>[index].<%=subkey%>[index2].length;index3++){
|
|
103
|
-
<%Object.keys(sub2obj.items.properties).forEach(function(sub3key) { %>
|
|
104
|
-
<%let sub3obj = sub2obj.items.properties[sub3key]%>
|
|
105
|
-
<%if(sub3obj['x-compute']){%> //x-compute 4th level field
|
|
106
|
-
data.<%=key%>[index].<%=subkey%>[index2].<%=sub2key%>.[index3].<%=sub3key%> = <%= sub3obj['x-compute'].function %>(
|
|
107
|
-
<% if(sub3obj['x-compute'].paramters){ %>
|
|
108
|
-
<% let sub3p = sub3obj['x-compute'].paramters %>
|
|
109
|
-
<%for(let m=0; m<sub3p.length; m++){%>
|
|
110
|
-
<%= subp[m].replace('@data','data').replace('@index','index').replace('@index2','index2').replace('@index3','index3') %>,
|
|
111
|
-
<%}%>
|
|
112
|
-
<%}%>
|
|
113
|
-
)
|
|
114
|
-
<%}%>
|
|
115
|
-
|
|
116
|
-
<%})%>
|
|
117
|
-
<%} /* process compute for 4rd level sub tables */%>
|
|
118
|
-
<%})%>
|
|
119
|
-
}
|
|
120
|
-
<%} // process compute for 3rd level sub tables%>
|
|
121
|
-
<%}) %>
|
|
122
|
-
}
|
|
123
|
-
<%} /*process compute for 2nd level sub tables*/%>
|
|
124
|
-
<%}) %>
|
|
62
|
+
<%}) %>
|
|
63
|
+
<%} %>
|
|
64
|
+
return data
|
|
125
65
|
}
|
|
126
66
|
|
|
127
67
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated by simpleapp generator. Every
|
|
3
|
+
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
4
|
+
* last change 2023-10-31
|
|
5
|
+
* Author: Ks Tan
|
|
6
|
+
*
|
|
7
|
+
* this class developed for implement field level encryption, however it still half way and keep here for future enhancement
|
|
8
|
+
* it doesn't effect anything at the moment
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Injectable } from '@nestjs/common';
|
|
12
|
+
import { createCipheriv,createDecipheriv, randomBytes, scrypt,Cipher,Decipher } from 'crypto';
|
|
13
|
+
import { promisify } from 'util';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export class Encryption{
|
|
18
|
+
private static instance: Encryption;
|
|
19
|
+
private algorithm = 'aes-256-ctr'
|
|
20
|
+
private iv = randomBytes(16);
|
|
21
|
+
private password = String(process.env.ENRYPTION_KEY)
|
|
22
|
+
|
|
23
|
+
private key :Buffer
|
|
24
|
+
|
|
25
|
+
constructor(){
|
|
26
|
+
this.init();
|
|
27
|
+
}
|
|
28
|
+
public static getInstance(): Encryption {
|
|
29
|
+
if (!Encryption.instance) {
|
|
30
|
+
Encryption.instance = new Encryption();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return Encryption.instance;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async init (){
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
console.log("Initialized encryption class")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
getKey = async (salt)=>{
|
|
46
|
+
const key = (await promisify(scrypt)(this.password,salt , 32)) as Buffer;
|
|
47
|
+
return key
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
encrypt = async (value:string)=>{
|
|
51
|
+
const salt ='salt'
|
|
52
|
+
const key = await this.getKey(salt)
|
|
53
|
+
const cipher = createCipheriv(this.algorithm, key, this.iv);
|
|
54
|
+
console.log("Encrypting text ",value,cipher)
|
|
55
|
+
const encryptedText = Buffer.concat([
|
|
56
|
+
cipher.update(value),
|
|
57
|
+
cipher.final(),
|
|
58
|
+
]).toString('hex');
|
|
59
|
+
console.log("encryptedText",encryptedText)
|
|
60
|
+
return encryptedText
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
decrypt = async (value:string,salt:string)=>{
|
|
64
|
+
const key = await this.getKey(salt)
|
|
65
|
+
const decipher = createDecipheriv('aes-256-ctr', key, this.iv);
|
|
66
|
+
const buf = Buffer.from(value)
|
|
67
|
+
const decryptedText = Buffer.concat([
|
|
68
|
+
decipher.update(buf),
|
|
69
|
+
decipher.final(),
|
|
70
|
+
]).toString('hex');
|
|
71
|
+
return decryptedText
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
package/templates/nest/src/simpleapp/generate/commons/exceptions/SimpleAppExceptionFilter.ts.eta
CHANGED
|
@@ -29,18 +29,26 @@ export class SimpleAppExceptionFilter implements ExceptionFilter {
|
|
|
29
29
|
const session:ClientSession = request['sessionuser'].getDBSession()
|
|
30
30
|
if(session.inTransaction())session.abortTransaction()
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
console.log('exceptionexception',typeof exception,Object.keys(exception),exception)
|
|
33
|
+
let errordata
|
|
34
|
+
let finalstatus
|
|
35
|
+
let msg
|
|
36
|
+
if(Object.keys(exception).length>0){
|
|
37
|
+
msg = exception.message
|
|
38
|
+
errordata = (exception.response && exception.response.options) ? exception.response.options : exception.options
|
|
39
|
+
finalstatus = ( exception.response && exception.response.status) ? exception.response.status : exception.status
|
|
40
|
+
}else{
|
|
41
|
+
msg = String(exception)
|
|
42
|
+
finalstatus = 500
|
|
43
|
+
}
|
|
33
44
|
|
|
34
45
|
const responseBody = {
|
|
35
|
-
message:
|
|
46
|
+
message: msg,
|
|
36
47
|
timestamp: new Date().toISOString(),
|
|
37
48
|
path: httpAdapter.getRequestUrl(ctx.getRequest()),
|
|
38
|
-
error:
|
|
49
|
+
error:errordata
|
|
39
50
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// console.log("exception.responseexception.response",exception)
|
|
43
|
-
const finalstatus = exception.response.status??exception.status
|
|
51
|
+
|
|
44
52
|
const eventObj = request['eventObj']
|
|
45
53
|
if(eventObj){
|
|
46
54
|
eventObj.statusCode=finalstatus
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Injectable, Logger,Inject } from '@nestjs/common';
|
|
8
8
|
import { InjectModel } from '@nestjs/mongoose';
|
|
9
|
-
import
|
|
9
|
+
import jsonpath from 'jsonpath'
|
|
10
10
|
import { uniq } from 'lodash';
|
|
11
11
|
import { AuditTrail } from '../commons/audittrail.service';
|
|
12
12
|
import {foreignkeys} from '../commons/dicts/foreignkeys'
|
|
@@ -290,14 +290,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
290
290
|
this.logger.debug("Create data before isolation",'SimpleAppService')
|
|
291
291
|
this.logger.debug(data,'SimpleAppService')
|
|
292
292
|
Object.assign(data, isolationFilter);
|
|
293
|
-
|
|
293
|
+
data = this.reCalculateValue(data)
|
|
294
294
|
await this.validateData(appuser,data);
|
|
295
295
|
this.logger.debug("Create record",'SimpleAppService')
|
|
296
296
|
this.logger.debug(data,'SimpleAppService')
|
|
297
297
|
|
|
298
298
|
this.applyNestedDateTime(appuser,data,'create')
|
|
299
299
|
const newdoc = new this.doc(data);
|
|
300
|
-
|
|
300
|
+
await this.identifyUniqueKeys(appuser,data)
|
|
301
301
|
try{
|
|
302
302
|
result = await newdoc.save({session:dbsession})
|
|
303
303
|
}catch(err){
|
|
@@ -464,7 +464,9 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
464
464
|
// try {
|
|
465
465
|
Object.assign(data, appuser.getUpdateFilter());
|
|
466
466
|
Object.assign(existingdata, data);
|
|
467
|
-
delete
|
|
467
|
+
delete data['_id']
|
|
468
|
+
|
|
469
|
+
data = this.reCalculateValue(data)
|
|
468
470
|
// existingdata['_id']=''
|
|
469
471
|
// console.log("newdata",data)
|
|
470
472
|
await this.validateData(appuser,data);
|
|
@@ -508,7 +510,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
508
510
|
const collection = this.doc.db.collection(collectionname);
|
|
509
511
|
//single schema may have multiple foreign key link here, loop all
|
|
510
512
|
for (let j = 0; j < fobjs.length; j++) {
|
|
511
|
-
const fkey = fobjs[j]
|
|
513
|
+
const fkey = fobjs[j]
|
|
512
514
|
let filter = {}
|
|
513
515
|
filter[fkey] = id;
|
|
514
516
|
|
|
@@ -579,23 +581,26 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
579
581
|
|
|
580
582
|
//get all foreign keys catalogue
|
|
581
583
|
const collections = Object.getOwnPropertyNames(this.foreignkeys)
|
|
582
|
-
|
|
584
|
+
console.log("111111",collections)
|
|
583
585
|
//obtain exists data in according foreign key
|
|
584
586
|
const pipelines :PipelineStage[] =[ {$match:{_id:false}}] //exclude data from current collection
|
|
585
|
-
const vdata = data['_doc']
|
|
587
|
+
const vdata = data//['_doc']
|
|
586
588
|
const keystore = {}
|
|
587
589
|
collections.forEach((collectionname)=>{
|
|
588
590
|
const fks:string[] = this.foreignkeys[collectionname]
|
|
589
591
|
let results:string[] = []
|
|
590
592
|
fks.forEach(fieldpath=>{
|
|
593
|
+
// console.log("fieldpath:",fieldpath,"vdata",data,vdata)
|
|
591
594
|
const tmp = jsonpath.query(vdata,fieldpath).filter((item:string)=>item!='')
|
|
595
|
+
// console.log("tmp",tmp)
|
|
596
|
+
|
|
592
597
|
results = results.concat(tmp)
|
|
593
598
|
})
|
|
594
599
|
|
|
595
600
|
|
|
596
601
|
|
|
597
602
|
if(results.length>0){
|
|
598
|
-
console.log(results)
|
|
603
|
+
console.log('tmp',results)
|
|
599
604
|
if(results.length>1){
|
|
600
605
|
results = uniq<string>(results)
|
|
601
606
|
}
|
|
@@ -609,22 +614,24 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
609
614
|
pipelines.push(stagefilter)
|
|
610
615
|
}
|
|
611
616
|
})
|
|
612
|
-
|
|
617
|
+
this.logger.debug(pipelines,'identifyUniqueKeys')
|
|
613
618
|
// this.doc.db.collection(collectionname);
|
|
614
619
|
const unionresult = await this.doc.aggregate(pipelines)
|
|
615
620
|
|
|
616
621
|
if(!unionresult){
|
|
622
|
+
this.logger.error("foreign key control failed ",'identifyUniqueKeys')
|
|
617
623
|
throw new InternalServerErrorException("Foreignkey check execution error",pipelines as HttpExceptionOptions)
|
|
618
624
|
}else{
|
|
619
625
|
let searchresult:any = {}
|
|
620
626
|
unionresult.forEach(item=>{
|
|
627
|
+
console.log("111")
|
|
621
628
|
if(searchresult[item.collection]){
|
|
622
629
|
searchresult[item.collection].push(item._id)
|
|
623
630
|
}else{
|
|
624
631
|
searchresult[item.collection] = [item._id]
|
|
625
632
|
}
|
|
626
633
|
})
|
|
627
|
-
|
|
634
|
+
|
|
628
635
|
//search is it all foreign key exists in db
|
|
629
636
|
for(let i=0; i<collections.length; i++){
|
|
630
637
|
const collectionname = collections[i]
|
|
@@ -634,19 +641,21 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
634
641
|
}
|
|
635
642
|
for(let k=0;k<keys.length; k++){
|
|
636
643
|
const key = keys[k]
|
|
637
|
-
if(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
644
|
+
if(searchresult[collectionname] && searchresult[collectionname].includes(key)){
|
|
645
|
+
this.logger.debug(`foreignkey ${collectionname}->${key} exists`)
|
|
646
|
+
}
|
|
641
647
|
else{
|
|
642
|
-
|
|
648
|
+
this.logger.warn(`Foreignkey ${key} at collection ${collectionname} does not exist`,'identifyUniqueKeys')
|
|
649
|
+
const errordata = {key:key,collection:collectionname}
|
|
650
|
+
throw new BadRequestException(`Foreignkey ${key} at collection ${collectionname} does not exist`,JSON.stringify(errordata))
|
|
651
|
+
|
|
643
652
|
}
|
|
644
653
|
}
|
|
645
654
|
|
|
646
655
|
}
|
|
647
656
|
|
|
648
657
|
}
|
|
649
|
-
|
|
658
|
+
console.log("666")
|
|
650
659
|
}
|
|
651
660
|
|
|
652
661
|
|
|
@@ -8,6 +8,7 @@ import { Module } from '@nestjs/common';
|
|
|
8
8
|
import { MongooseModule } from '@nestjs/mongoose';
|
|
9
9
|
import {DocNumberFormatGenerator} from './generate/commons/docnogenerator.service'
|
|
10
10
|
import { AuditTrail } from './generate/commons/audittrail.service';
|
|
11
|
+
|
|
11
12
|
// auto import modules
|
|
12
13
|
<% for(let i=0;i<it.modules.length; i++){ %>
|
|
13
14
|
<% let obj = it.modules[i]%>
|
|
@@ -23,7 +24,7 @@ import { ProfileService } from './profile/profile.service';
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
//<%if(it.doctype != 'autoinc'){%>import {AutoincreamentModule} from '../autoinc/autoinc.module'<%}%>
|
|
26
|
-
|
|
27
|
+
//encryption use for model (not class and cant inject, use singleton instead and init as early as possible)
|
|
27
28
|
|
|
28
29
|
@Module({
|
|
29
30
|
imports: [
|