@simitgroup/simpleapp-generator 2.0.2-b-alpha → 2.0.2-c-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.
- package/ReleaseNote.md +6 -0
- package/package.json +1 -1
- package/templates/basic/nest/controller.ts.eta +2 -2
- package/templates/nest/src/app.controller.ts.eta +10 -10
- package/templates/nest/src/app.module.ts._eta +1 -0
- package/templates/nest/src/simple-app/_core/features/auth/role-guard/roles.guard.ts.eta +5 -18
- package/templates/nest/src/simple-app/_core/features/document-no-format/document-no-format.service.ts.eta +14 -7
- package/templates/nest/src/simple-app/_core/features/log/log.service.ts.eta +10 -5
- package/templates/nest/src/simple-app/_core/features/mini-app/mini-app-scope/mini-app-scope.guard.ts.eta +4 -0
- package/templates/nest/src/simple-app/_core/features/profile/profile.service.ts.eta +15 -11
- package/templates/nest/src/simple-app/_core/features/queue/queue-base/queue-base.consumer.ts.eta +14 -13
- package/templates/nest/src/simple-app/_core/features/user-context/user.context.ts.eta +54 -3
- package/templates/nest/src/simple-app/_core/framework/base/simple-app.controller.ts.eta +21 -3
- package/templates/nest/src/simple-app/_core/framework/base/simple-app.service.ts.eta +401 -198
- package/templates/nest/src/simple-app/_core/framework/framework.module.ts.eta +3 -2
- package/templates/nest/src/simple-app/_core/framework/schemas/simple-app.schema.ts.eta +6 -0
- package/templates/nest/src/simple-app/_core/framework/simple-app-db-revert.service.ts.eta +101 -0
- package/templates/nest/src/simple-app/_core/framework/simple-app.interceptor.ts.eta +33 -12
package/ReleaseNote.md
CHANGED
package/package.json
CHANGED
|
@@ -99,8 +99,8 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
99
99
|
@ApiBody({ description: 'Data', type: schemas.SearchBody })
|
|
100
100
|
@ApiOperation({ operationId: 'runSearch' })
|
|
101
101
|
<%~ drawMiniAppScope('list') %>
|
|
102
|
-
async search(@AppUser() appuser: UserContext,@Body() data: schemas.SearchBody) {
|
|
103
|
-
return await this._search(appuser,data)
|
|
102
|
+
async search(@AppUser() appuser: UserContext,@Body() data: schemas.SearchBody, @Res({ passthrough: true }) res: Response) {
|
|
103
|
+
return await this._search(appuser,data, res)
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
<% if(simpleappconfig.search !==undefined){%>
|
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
* last change 2023-10-28
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
|
-
import { Controller, Get,Logger } from '@nestjs/common';
|
|
7
|
+
import { Controller, Get, Logger } from '@nestjs/common';
|
|
8
8
|
import { AppService } from './app.service';
|
|
9
|
-
|
|
9
|
+
import { Roles } from 'src/simple-app/_core/features/auth/role-guard/roles.decorator';
|
|
10
|
+
import { Role } from 'src/simple-app/_core/features/auth/role-guard/roles.enum';
|
|
10
11
|
@Controller()
|
|
11
12
|
export class AppController {
|
|
12
|
-
private logger = new Logger()
|
|
13
|
+
private logger = new Logger();
|
|
13
14
|
constructor(private readonly appService: AppService) {
|
|
14
|
-
if(process.env.DRYRUN=='true'){
|
|
15
|
-
this.logger.warn(
|
|
15
|
+
if (process.env.DRYRUN == 'true') {
|
|
16
|
+
this.logger.warn('DRY run Mode, transaction will roll back');
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
@Get()
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
@Get('/health')
|
|
21
|
+
@Roles(Role.Everyone)
|
|
22
|
+
async getHealth() {
|
|
23
|
+
return Promise.resolve('ok');
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
* last change 2024-03-17
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
Injectable,
|
|
9
|
-
Inject,
|
|
10
|
-
CanActivate,
|
|
11
|
-
ExecutionContext,
|
|
12
|
-
Scope,
|
|
13
|
-
} from '@nestjs/common';
|
|
7
|
+
import { Injectable, Inject, CanActivate, ExecutionContext, Scope } from '@nestjs/common';
|
|
14
8
|
import { Reflector } from '@nestjs/core';
|
|
15
9
|
import { Role } from './roles.enum';
|
|
16
10
|
import { ROLES_KEY } from './roles.decorator';
|
|
@@ -21,18 +15,13 @@ export class RolesGuard implements CanActivate {
|
|
|
21
15
|
constructor(private reflector: Reflector) {}
|
|
22
16
|
|
|
23
17
|
canActivate(context: ExecutionContext): boolean {
|
|
24
|
-
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
|
|
25
|
-
context.getHandler(),
|
|
26
|
-
context.getClass(),
|
|
27
|
-
]) || [];
|
|
18
|
+
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [context.getHandler(), context.getClass()]) || [];
|
|
28
19
|
const criticalRoles = [Role.SuperAdmin, Role.SuperUser, Role.TenantOwner];
|
|
29
|
-
|
|
30
20
|
criticalRoles.forEach((role) => {
|
|
31
21
|
if (!requiredRoles.includes(role)) {
|
|
32
22
|
requiredRoles.push(role);
|
|
33
23
|
}
|
|
34
24
|
});
|
|
35
|
-
|
|
36
25
|
let sessionuser: UserContext;
|
|
37
26
|
if (context.getType() == 'http') {
|
|
38
27
|
const request = context.switchToHttp().getRequest();
|
|
@@ -41,17 +30,15 @@ export class RolesGuard implements CanActivate {
|
|
|
41
30
|
const req = context.getArgs()[2].req;
|
|
42
31
|
sessionuser = req['sessionuser'];
|
|
43
32
|
}
|
|
44
|
-
|
|
33
|
+
|
|
45
34
|
if (!requiredRoles) {
|
|
46
35
|
return true;
|
|
47
36
|
}
|
|
48
|
-
|
|
49
|
-
const roles = sessionuser.getRoles();
|
|
37
|
+
const roles = sessionuser ? sessionuser.getRoles() : [Role.Everyone];
|
|
50
38
|
if (!roles) {
|
|
51
39
|
return false;
|
|
52
40
|
}
|
|
53
|
-
const result = requiredRoles.some((role) => roles.includes(role));
|
|
54
|
-
|
|
41
|
+
const result = requiredRoles.some((role) => roles.includes(role));
|
|
55
42
|
return result;
|
|
56
43
|
// return true
|
|
57
44
|
}
|
|
@@ -65,8 +65,8 @@ export class SimpleAppDocumentNoFormatService {
|
|
|
65
65
|
}
|
|
66
66
|
//
|
|
67
67
|
Object.assign(filter, appUser.getBranchFilter());
|
|
68
|
-
const session = appUser.getDBSession()
|
|
69
|
-
const result = await this.docformat.find(filter)
|
|
68
|
+
const session = appUser.getDBSession();
|
|
69
|
+
const result = await this.docformat.find(filter).session(session);
|
|
70
70
|
if (result && result.length > 0) {
|
|
71
71
|
const d: DocumentNoFormat = result[0];
|
|
72
72
|
const recordId = d._id;
|
|
@@ -74,8 +74,9 @@ export class SimpleAppDocumentNoFormatService {
|
|
|
74
74
|
const newnextnumber = d.nextNumber + 1;
|
|
75
75
|
const updatedata = { nextNumber: newnextnumber } as DocumentNoFormat;
|
|
76
76
|
|
|
77
|
-
const options = process.env.BlockGenerateDocNumberWithSession ? {} : {session:session}
|
|
78
|
-
const updateresult = await this.docformat.findByIdAndUpdate(recordId, updatedata,options)
|
|
77
|
+
const options = process.env.BlockGenerateDocNumberWithSession ? {} : { session: session };
|
|
78
|
+
const updateresult = await this.docformat.findByIdAndUpdate(recordId, updatedata, options);
|
|
79
|
+
appUser.addTransactionStep('update','documentnoformat',[recordId],[result[0]])
|
|
79
80
|
if (updateresult) {
|
|
80
81
|
const result: DocNumberFormatResult = {
|
|
81
82
|
formatId: d._id,
|
|
@@ -111,7 +112,9 @@ export class SimpleAppDocumentNoFormatService {
|
|
|
111
112
|
const docformats = alldocuments.filter((item) => item.docNumber);
|
|
112
113
|
const allFormats: DocumentNoFormat[] = [];
|
|
113
114
|
for (let i = 0; i < docformats.length; i++) {
|
|
115
|
+
|
|
114
116
|
const doc = docformats[i];
|
|
117
|
+
if(['tenantinvoice'].includes(doc.docType)) continue;
|
|
115
118
|
const pattern = doc.docNoPattern.replace('@BranchCode', branchCode);
|
|
116
119
|
const formatdata: DocumentNoFormat = {
|
|
117
120
|
_id: crypto.randomUUID(),
|
|
@@ -137,6 +140,10 @@ export class SimpleAppDocumentNoFormatService {
|
|
|
137
140
|
try {
|
|
138
141
|
//rollback when not able to create branch
|
|
139
142
|
const result = await this.docformat.insertMany(allFormats, { session: appUser.getDBSession() });
|
|
143
|
+
const allRecordIds = result.map(item=>item._id)
|
|
144
|
+
const allLogData = result.map(item=>null)
|
|
145
|
+
|
|
146
|
+
appUser.addTransactionStep('create','documentnoformat',allRecordIds,allLogData)
|
|
140
147
|
if (!result) {
|
|
141
148
|
throw new InternalServerErrorException(`Generate ${allFormats.length} document formats for "${branchCode}" failed.`, 'generateDefaultDocNumbers');
|
|
142
149
|
}
|
|
@@ -215,9 +222,9 @@ export class SimpleAppDocumentNoFormatService {
|
|
|
215
222
|
}
|
|
216
223
|
const updatedata = { nextNumber: d.nextNumber + 1 } as DocumentNoFormat;
|
|
217
224
|
|
|
218
|
-
const options = process.env.BlockGenerateDocNumberWithSession ? {} : {session:appUser.getDBSession()}
|
|
219
|
-
const updateresult = await this.docformat.findByIdAndUpdate(recordId, updatedata,options)
|
|
220
|
-
|
|
225
|
+
const options = process.env.BlockGenerateDocNumberWithSession ? {} : { session: appUser.getDBSession(), };
|
|
226
|
+
const updateresult = await this.docformat.findByIdAndUpdate(recordId, updatedata, options);
|
|
227
|
+
appUser.addTransactionStep('update','documentnoformat',[recordId],[result[0]])
|
|
221
228
|
return documentNumbers;
|
|
222
229
|
} else {
|
|
223
230
|
throw new BadRequestException(`No active document number found for ${doctype}. Please update in Settings > Document Numbering Format`);
|
|
@@ -48,6 +48,8 @@ export class SimpleAppLogService {
|
|
|
48
48
|
return data;
|
|
49
49
|
}
|
|
50
50
|
async addEvent(appUser: UserContext, documentName: string, id: string, eventType: string, data: any) {
|
|
51
|
+
if(process.env.DISABLE_DOCUMENT_EVENT==='true') return false
|
|
52
|
+
|
|
51
53
|
const eventdata: DocumentEvent = {
|
|
52
54
|
_id: crypto.randomUUID(),
|
|
53
55
|
documentName: documentName,
|
|
@@ -68,6 +70,7 @@ export class SimpleAppLogService {
|
|
|
68
70
|
const newdoc = new this.doc(eventdata);
|
|
69
71
|
const dbsession = appUser.getDBSession();
|
|
70
72
|
const result = await newdoc.save({ session: dbsession });
|
|
73
|
+
appUser.addTransactionStep('create','documentevent',[eventdata._id],[null])
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
async addManyEvents(appUser: UserContext, documentName: string, eventType: string, datas: any[]) {
|
|
@@ -93,11 +96,13 @@ export class SimpleAppLogService {
|
|
|
93
96
|
alldata.push(eventdata);
|
|
94
97
|
}
|
|
95
98
|
const dbsession = appUser.getDBSession();
|
|
96
|
-
try{
|
|
97
|
-
await this.doc.insertMany(alldata, { session: dbsession });
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
try {
|
|
100
|
+
await this.doc.insertMany(alldata, { session: dbsession });
|
|
101
|
+
const allIds = alldata.map(item=>item._id)
|
|
102
|
+
const allLogData = alldata.map(item=>null)
|
|
103
|
+
appUser.addTransactionStep('create','documentevent',allIds,allLogData)
|
|
104
|
+
} catch (e) {
|
|
105
|
+
throw e;
|
|
100
106
|
}
|
|
101
|
-
|
|
102
107
|
}
|
|
103
108
|
}
|
|
@@ -20,6 +20,10 @@ export class MiniAppScopeGuard implements CanActivate {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const req = context.switchToHttp().getRequest();
|
|
23
|
+
|
|
24
|
+
if(req.url==='/health'){
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
23
27
|
const appUser: UserContext = req?.sessionuser;
|
|
24
28
|
if (!appUser) {
|
|
25
29
|
throw new BadRequestException('User Context Not Found');
|
|
@@ -87,14 +87,16 @@ export class ProfileService {
|
|
|
87
87
|
return userinfo;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
async createTenant(appuser: UserContext, tenantName: string, timeZone: string, utcOffset: number, businessType: string,mobileNo:string) {
|
|
90
|
+
async createTenant(appuser: UserContext, tenantName: string, timeZone: string, utcOffset: number, businessType: string, mobileNo: string) {
|
|
91
91
|
// try{
|
|
92
|
+
|
|
93
|
+
|
|
92
94
|
const timezonedata = countrytimezone.getCountriesForTimezone(timeZone)[0];
|
|
93
95
|
const countryCode = timezonedata['id'];
|
|
94
96
|
const countryName = timezonedata['name'];
|
|
95
97
|
const currencyCode = countryToCurrency[countryCode];
|
|
96
98
|
|
|
97
|
-
appuser.
|
|
99
|
+
appuser.startTransaction()
|
|
98
100
|
const tenantdata: Tenant = {
|
|
99
101
|
tenantId: 1,
|
|
100
102
|
tenantName: tenantName,
|
|
@@ -111,12 +113,12 @@ export class ProfileService {
|
|
|
111
113
|
uid: appuser.getUid(),
|
|
112
114
|
},
|
|
113
115
|
};
|
|
114
|
-
this.logger.
|
|
116
|
+
this.logger.debug(tenantdata, 'createTenant data');
|
|
115
117
|
const tenantResult = await this.tenantService.create(appuser, tenantdata);
|
|
116
118
|
if (!tenantResult) {
|
|
117
119
|
throw new BadRequestException('Create tenant failed');
|
|
118
120
|
}
|
|
119
|
-
this.logger.
|
|
121
|
+
this.logger.debug(tenantResult, 'createTenant result');
|
|
120
122
|
const tenantId = tenantResult.tenantId;
|
|
121
123
|
|
|
122
124
|
// return tenantResult
|
|
@@ -133,7 +135,7 @@ export class ProfileService {
|
|
|
133
135
|
orgId: 1,
|
|
134
136
|
};
|
|
135
137
|
|
|
136
|
-
this.logger.
|
|
138
|
+
this.logger.debug(orgdata, 'createOrg data');
|
|
137
139
|
const orgResult = await this.orgService.create(appuser, orgdata);
|
|
138
140
|
if (!orgResult) {
|
|
139
141
|
throw new BadRequestException('Create Org failed');
|
|
@@ -168,14 +170,14 @@ export class ProfileService {
|
|
|
168
170
|
tenantId: tenantResult.tenantId,
|
|
169
171
|
organization: { _id: orgRecordId, label: tenantName },
|
|
170
172
|
};
|
|
171
|
-
this.logger.
|
|
173
|
+
this.logger.debug(branchdata, 'createbranch data');
|
|
172
174
|
|
|
173
175
|
const branchResult = await this.branchService.create(appuser, branchdata);
|
|
174
176
|
if (!branchResult) {
|
|
175
177
|
throw new BadRequestException('Create Branch failed');
|
|
176
178
|
}
|
|
177
179
|
const branchRecordId = branchResult._id.toString();
|
|
178
|
-
this.logger.
|
|
180
|
+
this.logger.debug(branchResult, 'createbranch result');
|
|
179
181
|
|
|
180
182
|
const userdata: User = {
|
|
181
183
|
tenantId: tenantResult.tenantId,
|
|
@@ -186,14 +188,14 @@ export class ProfileService {
|
|
|
186
188
|
email: appuser.getEmail(),
|
|
187
189
|
active: true,
|
|
188
190
|
};
|
|
189
|
-
this.logger.
|
|
191
|
+
this.logger.debug(userdata, 'createtenant user data');
|
|
190
192
|
const userResult = await this.userService.create(appuser, userdata);
|
|
191
193
|
// if(true ){
|
|
192
194
|
if (!userResult) {
|
|
193
195
|
throw new BadRequestException('Create User failed');
|
|
194
196
|
}
|
|
195
197
|
|
|
196
|
-
this.logger.
|
|
198
|
+
this.logger.debug(userResult, 'createtenant user result');
|
|
197
199
|
const userRecordId = userResult._id.toString();
|
|
198
200
|
|
|
199
201
|
const permdata: Permission = {
|
|
@@ -204,13 +206,13 @@ export class ProfileService {
|
|
|
204
206
|
userId: userRecordId,
|
|
205
207
|
groups: ['admin'],
|
|
206
208
|
};
|
|
207
|
-
this.logger.
|
|
209
|
+
this.logger.debug(permdata, 'create Permission data');
|
|
208
210
|
const permResult = await this.permService.create(appuser, permdata);
|
|
209
211
|
if (!permResult) {
|
|
210
212
|
throw new BadRequestException('Create permResult failed');
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
this.logger.
|
|
215
|
+
this.logger.debug(permResult, 'create Permission result');
|
|
214
216
|
|
|
215
217
|
//tenant owner shall map to userId for that tenant
|
|
216
218
|
|
|
@@ -228,6 +230,8 @@ export class ProfileService {
|
|
|
228
230
|
orgId: orgResult.orgId,
|
|
229
231
|
branchId: branchResult.branchId,
|
|
230
232
|
};
|
|
233
|
+
|
|
234
|
+
// console.log("finalresult, is transaction",finalresult,appuser.getDBSession().inTransaction())
|
|
231
235
|
return finalresult;
|
|
232
236
|
// }catch(e){
|
|
233
237
|
// this.logger.error("Couldn't generate tenant or subsequence records")
|
package/templates/nest/src/simple-app/_core/features/queue/queue-base/queue-base.consumer.ts.eta
CHANGED
|
@@ -7,19 +7,21 @@ import { UserContext } from '../../user-context/user.context';
|
|
|
7
7
|
import { QueueUserContext } from '../queue-user-context/queue-user-context.service';
|
|
8
8
|
import { Queuejob } from '../queue.type';
|
|
9
9
|
// import { QueueName } from '../queue.enum';
|
|
10
|
-
import { forwardRef, Inject, InternalServerErrorException } from '@nestjs/common';
|
|
10
|
+
import { forwardRef, Inject, Logger, InternalServerErrorException } from '@nestjs/common';
|
|
11
11
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
12
12
|
import _ from 'lodash';
|
|
13
|
+
import { SimpleAppDbRevertService } from 'src/simple-app/_core/framework/simple-app-db-revert.service';
|
|
13
14
|
|
|
14
15
|
export abstract class BaseQueueConsumer extends WorkerHost {
|
|
15
16
|
// protected abstract readonly processor: QueueName;
|
|
16
17
|
protected abstract readonly processor: string;
|
|
17
|
-
|
|
18
|
+
protected logger = new Logger()
|
|
18
19
|
constructor(
|
|
19
20
|
protected readonly queueUserContext: QueueUserContext,
|
|
20
21
|
@InjectModel('Queuejob') protected queueJobModel: Model<Queuejob>,
|
|
21
22
|
@InjectConnection() private readonly connection: Connection,
|
|
22
23
|
protected eventEmitter: EventEmitter2,
|
|
24
|
+
protected simpleAppDbRevertService: SimpleAppDbRevertService
|
|
23
25
|
) {
|
|
24
26
|
super();
|
|
25
27
|
}
|
|
@@ -36,6 +38,7 @@ export abstract class BaseQueueConsumer extends WorkerHost {
|
|
|
36
38
|
async process(job: Job) {
|
|
37
39
|
// console.log("process job", job.data)
|
|
38
40
|
const { userContext, payload } = job.data;
|
|
41
|
+
this.logger.debug(payload,`run queue job ${job.name}`)
|
|
39
42
|
|
|
40
43
|
const appUser = await this.createUserContext(userContext.user);
|
|
41
44
|
await this.startSession(appUser);
|
|
@@ -45,19 +48,19 @@ export abstract class BaseQueueConsumer extends WorkerHost {
|
|
|
45
48
|
// this.queueUserContext.assign(userContext);
|
|
46
49
|
|
|
47
50
|
await this.dispatch(appUser, job, payload);
|
|
48
|
-
if (appUser.getDBSession().inTransaction()) {
|
|
49
|
-
await appUser.getDBSession().commitTransaction();
|
|
50
|
-
}
|
|
51
|
+
// if (appUser.getDBSession().inTransaction()) {
|
|
52
|
+
await appUser.commitTransaction() //.getDBSession().commitTransaction();
|
|
53
|
+
// }
|
|
51
54
|
return {
|
|
52
55
|
success: true,
|
|
53
56
|
};
|
|
54
57
|
} catch (e) {
|
|
55
|
-
if (appUser.getDBSession().inTransaction()) {
|
|
56
|
-
await appUser.getDBSession().abortTransaction();
|
|
57
|
-
}
|
|
58
|
+
// if (appUser.getDBSession().inTransaction()) {
|
|
59
|
+
await appUser.rollBackTransaction(this.simpleAppDbRevertService) //.getDBSession().abortTransaction();
|
|
60
|
+
// }
|
|
58
61
|
throw e;
|
|
59
62
|
} finally {
|
|
60
|
-
appUser.getDBSession().endSession();
|
|
63
|
+
await appUser.endSession()//getDBSession().endSession();
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
@@ -74,8 +77,7 @@ export abstract class BaseQueueConsumer extends WorkerHost {
|
|
|
74
77
|
await handler.call(this, appUser, job, payload);
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
protected async updateQueueJobRecord(job: Job, status: 'completed' | 'failed', result: any) {
|
|
78
|
-
|
|
80
|
+
protected async updateQueueJobRecord(job: Job, status: 'completed' | 'failed', result: any) {
|
|
79
81
|
await this.queueJobModel.updateOne(
|
|
80
82
|
{
|
|
81
83
|
'job.id': job.id,
|
|
@@ -83,8 +85,7 @@ export abstract class BaseQueueConsumer extends WorkerHost {
|
|
|
83
85
|
'job.processor': this.processor,
|
|
84
86
|
},
|
|
85
87
|
{
|
|
86
|
-
|
|
87
|
-
'job.status': status,
|
|
88
|
+
'job.status': status,
|
|
88
89
|
initTime: new Date(job.timestamp).toISOString(),
|
|
89
90
|
startTime: new Date(job.processedOn).toISOString(),
|
|
90
91
|
endTime: new Date(job.finishedOn).toISOString(),
|
|
@@ -30,12 +30,15 @@ import { Role } from '../auth/role-guard/roles.enum';
|
|
|
30
30
|
import { Environment } from '@core-features/maintenance/schemas';
|
|
31
31
|
import * as rolegroups from '../auth/role-guard/roles.group';
|
|
32
32
|
import { TenantLicenseEnum } from '@resources/tenant/tenant.enum';
|
|
33
|
+
import { SimpleAppDbRevertService } from '../../framework/simple-app-db-revert.service';
|
|
34
|
+
import { StepData } from 'src/simple-app/_core/resources/permission/permission.schema';
|
|
33
35
|
|
|
34
36
|
// import systemWebHooks from '../../webhooks';
|
|
35
37
|
@Injectable({ scope: Scope.REQUEST })
|
|
36
38
|
export class UserContext extends UserContextInfo {
|
|
37
39
|
sessionId: string = crypto.randomUUID();
|
|
38
|
-
|
|
40
|
+
protected isTransaction = false
|
|
41
|
+
protected transSteps:StepData[] = []
|
|
39
42
|
protected logger = new Logger(this.constructor.name);
|
|
40
43
|
|
|
41
44
|
// protected uid: string = '';
|
|
@@ -148,7 +151,7 @@ export class UserContext extends UserContextInfo {
|
|
|
148
151
|
};
|
|
149
152
|
|
|
150
153
|
getDBSession = (): ClientSession => this.dbsession;
|
|
151
|
-
|
|
154
|
+
getTransStep = () => this.transSteps
|
|
152
155
|
getId = () => this._id;
|
|
153
156
|
|
|
154
157
|
getUid = () => this.uid;
|
|
@@ -448,7 +451,7 @@ export class UserContext extends UserContextInfo {
|
|
|
448
451
|
branchName: '$b.branchName',
|
|
449
452
|
branchId: '$b.branchId',
|
|
450
453
|
imageUrl: '$b.imageUrl',
|
|
451
|
-
active: '$b.active'
|
|
454
|
+
active: '$b.active',
|
|
452
455
|
},
|
|
453
456
|
|
|
454
457
|
groups: 1,
|
|
@@ -1216,8 +1219,56 @@ export class UserContext extends UserContextInfo {
|
|
|
1216
1219
|
const isodate = new Date(timestamp + -offsets).toISOString().split('.')[0] + 'Z';
|
|
1217
1220
|
return isodate;
|
|
1218
1221
|
}
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
addTransactionStep (action:string,collection:string,id:string[], data:any[]) {
|
|
1225
|
+
this.transSteps.push({action:action,collection:collection,id:id,data:data})
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
inTransaction(){
|
|
1230
|
+
if(process.env.MONGO_TRANS==='false')
|
|
1231
|
+
return this.isTransaction
|
|
1232
|
+
else
|
|
1233
|
+
return this.dbsession && this.dbsession.inTransaction() ? true : false
|
|
1234
|
+
}
|
|
1235
|
+
startTransaction(){
|
|
1236
|
+
if(process.env.MONGO_TRANS==='false'){
|
|
1237
|
+
this.isTransaction=true
|
|
1238
|
+
this.transSteps=[]
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
}else{
|
|
1242
|
+
this.dbsession.startTransaction({ readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' }, readPreference: 'primary' });
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
async commitTransaction(){
|
|
1246
|
+
if(process.env.MONGO_TRANS==='false'){
|
|
1247
|
+
this.isTransaction=false
|
|
1248
|
+
this.transSteps=[]
|
|
1249
|
+
}else{
|
|
1250
|
+
if(this.dbsession.inTransaction())
|
|
1251
|
+
await this.dbsession.commitTransaction()
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
async rollBackTransaction(dbService:SimpleAppDbRevertService){
|
|
1255
|
+
if(process.env.MONGO_TRANS==='false'){
|
|
1256
|
+
await dbService.revertSteps(this.transSteps)
|
|
1257
|
+
this.isTransaction=false
|
|
1258
|
+
this.transSteps=[]
|
|
1259
|
+
|
|
1260
|
+
}else{
|
|
1261
|
+
if(this.dbsession.inTransaction())
|
|
1262
|
+
await this.dbsession.abortTransaction()
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
async endSession(){
|
|
1266
|
+
await this.dbsession.endSession()
|
|
1267
|
+
}
|
|
1219
1268
|
}
|
|
1220
1269
|
|
|
1270
|
+
|
|
1271
|
+
// type StepData = {action:string,collection:string,id:string[],data:any[]}
|
|
1221
1272
|
/**
|
|
1222
1273
|
* Define a type for userinfo
|
|
1223
1274
|
*/
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* last change 2025-09-01
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
|
-
import { Controller, Get, Put, Post, Delete, Body, Param, Type } from '@nestjs/common';
|
|
7
|
+
import { Controller, Get, Put, Post, Delete, Body, Param, Type, Res } from '@nestjs/common';
|
|
8
|
+
import { Response } from 'express';
|
|
8
9
|
// import { ApiTags, ApiBody, ApiResponse, ApiOperation } from '@nestjs/swagger';
|
|
9
10
|
import { UserContext } from '../../features/user-context/user.context';
|
|
10
11
|
import { SearchBody, TextSearchBody, PatchManyRequest } from '../schemas';
|
|
@@ -15,6 +16,9 @@ const doctype = 'person'.toUpperCase();
|
|
|
15
16
|
type ServiceType = {
|
|
16
17
|
list: Function;
|
|
17
18
|
search: Function;
|
|
19
|
+
searchWithPageInfo: Function;
|
|
20
|
+
setPaginationHeaders: Function;
|
|
21
|
+
getTotalCount: Function;
|
|
18
22
|
create: Function;
|
|
19
23
|
//update: Function;
|
|
20
24
|
//delete: Function;
|
|
@@ -47,8 +51,22 @@ export class SimpleAppController<TService extends ServiceType, TApiSchema> {
|
|
|
47
51
|
return this.service.fullTextSearch(appuser, body);
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
async _search(appuser: UserContext, searchObject: SearchBody) {
|
|
51
|
-
return this.service.search(appuser, searchObject['filter'], searchObject['fields'], searchObject['sorts'], searchObject['lookup']);
|
|
54
|
+
async _search(appuser: UserContext, searchObject: SearchBody, res?: Response) {
|
|
55
|
+
//return this.service.search(appuser, searchObject['filter'], searchObject['fields'], searchObject['sorts'], searchObject['lookup']);
|
|
56
|
+
const items = await this.service.searchWithPageInfo(
|
|
57
|
+
appuser,
|
|
58
|
+
searchObject['filter'],
|
|
59
|
+
searchObject['fields'],
|
|
60
|
+
searchObject['sorts'],
|
|
61
|
+
searchObject['lookup'],
|
|
62
|
+
searchObject['pagination'],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (res && searchObject['pagination']) {
|
|
66
|
+
const total = await this.service.getTotalCount(appuser, searchObject['filter'] || {});
|
|
67
|
+
this.service.setPaginationHeaders(res, total, searchObject['pagination']);
|
|
68
|
+
}
|
|
69
|
+
return items;
|
|
52
70
|
}
|
|
53
71
|
|
|
54
72
|
async _autocomplete(appuser: UserContext, keyword: string, data?: TApiSchema) {
|