@simitgroup/simpleapp-generator 1.6.7-l-alpha → 1.6.7-o-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 CHANGED
@@ -1,3 +1,9 @@
1
+ [1.6.7o-alpha]
2
+ 1. exclude findIdThenPatch to execute beforeUpdate and afterUpdate
3
+
4
+ [1.6.7m-alpha]
5
+ 1. insert many bug fix
6
+
1
7
  [1.6.7l-alpha]
2
8
  1. insert many support transaction
3
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simitgroup/simpleapp-generator",
3
- "version": "1.6.7l-alpha",
3
+ "version": "1.6.7o-alpha",
4
4
  "description": "frontend nuxtjs and backend nests code generator using jsonschema",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -10,6 +10,7 @@ import { MongooseModule,MongooseModuleOptions } from '@nestjs/mongoose';
10
10
  import { GraphQLModule } from '@nestjs/graphql';
11
11
  import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
12
12
  import {GenerateModule} from './simpleapp/simpleapp.module'
13
+ import {EnvironmentMongoSchema} from './simpleapp/maintenance/models/environment.model'
13
14
  <% const nestmodules = it.configs.additionalNestModules%>
14
15
  <% for(let i=0; i<nestmodules.length;i++){ %>
15
16
  <% const modulename = capitalizeFirstLetter(nestmodules[i]) %>
@@ -91,6 +92,7 @@ import { WebhookMongoSchema } from './simpleapp/generate/models/webhook.model';
91
92
  { name: 'Permission', schema: PermissionMongoSchema },
92
93
  { name: 'ApiEvent', schema: ApiEventMongoSchema },
93
94
  { name: 'Webhook', schema: WebhookMongoSchema },
95
+ { name: 'Environment', schema: EnvironmentMongoSchema },
94
96
  ]),
95
97
  ],
96
98
  controllers: [AppController],
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * This file was automatically generated by simpleapp generator. Every
3
3
  * MODIFICATION OVERRIDE BY GENERATEOR
4
- * last change 2024-03-17
4
+ * last change 2025-08-27
5
5
  * Author: Ks Tan
6
6
  */
7
7
 
8
8
  import Base64URL from '@darkwolf/base64url';
9
- import { BadRequestException, Injectable, Logger, NestMiddleware } from '@nestjs/common';
9
+ import { BadRequestException, Injectable, Logger, NestMiddleware, ServiceUnavailableException } from '@nestjs/common';
10
10
  import { InjectModel } from '@nestjs/mongoose';
11
11
  import { NextFunction, Request, Response } from 'express';
12
12
  import { Model } from 'mongoose';
@@ -17,7 +17,7 @@ import { Miniappinstallation, Webhook } from '../../types';
17
17
  import { UserContext } from '../user.context';
18
18
  import { ApiKeyService } from './api-key/api-key.service';
19
19
  import { HEADER_X_API_KEY, HEADER_X_API_SECRET } from '../constants/header';
20
-
20
+ import {Environment} from '../../../maintenance/apischemas/environment'
21
21
  @Injectable()
22
22
  export class TenantMiddleware implements NestMiddleware {
23
23
  protected defaultXOrg = Base64URL.encodeText('0-0-0');
@@ -32,6 +32,7 @@ export class TenantMiddleware implements NestMiddleware {
32
32
  @InjectModel('Appintegration') private readonly appModel: Model<Appintegration>,
33
33
  @InjectModel('Webhook') private readonly webhookModel: Model<Webhook>,
34
34
  @InjectModel('Miniappinstallation') private readonly miniAppInstallationModel: Model<Miniappinstallation>,
35
+ @InjectModel('Environment') private envModel:Model<Environment>,
35
36
  private readonly apiKeyService: ApiKeyService,
36
37
  ) {}
37
38
 
@@ -51,6 +52,13 @@ export class TenantMiddleware implements NestMiddleware {
51
52
  return;
52
53
  }
53
54
 
55
+ const envs = await this.envModel.find()
56
+ let maintenanceMode = false
57
+ if(envs){
58
+ maintenanceMode = !envs[0].systemEnable
59
+ }
60
+
61
+
54
62
  let tokenStr: string = req.get('authorization') ?? '';
55
63
  tokenStr = tokenStr.replace('Bearer ', '');
56
64
  const xOrg = req.get('x-org') ?? this.defaultXOrg;
@@ -61,6 +69,11 @@ export class TenantMiddleware implements NestMiddleware {
61
69
  if (tokenStr) {
62
70
  await user.setCurrentUserInfo(tokenStr, xOrg, this.webhookModel);
63
71
  }
72
+
73
+ if(maintenanceMode && !user.isRealmAdmin()){
74
+ throw new ServiceUnavailableException("System in maintenance mode")
75
+ }
76
+
64
77
  req['sessionuser'] = user;
65
78
  next();
66
79
  return;
@@ -74,6 +87,9 @@ export class TenantMiddleware implements NestMiddleware {
74
87
  await this.apiKeyService.validate(req, user);
75
88
 
76
89
  req['sessionuser'] = user;
90
+ if(maintenanceMode){
91
+ throw new ServiceUnavailableException("System in maintenance mode")
92
+ }
77
93
  next();
78
94
  return;
79
95
  } catch (e) {
@@ -110,6 +126,12 @@ export class TenantMiddleware implements NestMiddleware {
110
126
 
111
127
  try {
112
128
  await user.setCurrentUserInfo(tokenStr, xOrg, this.webhookModel);
129
+
130
+ if(maintenanceMode && !user.isRealmAdmin()){
131
+ throw new ServiceUnavailableException("System in maintenance mode")
132
+ }
133
+
134
+
113
135
  user.detectMiniAppSdkRequest(req);
114
136
  if (user.getId() == '' && this.requireXOrg(req.baseUrl)) {
115
137
  this.logger.log('Access deny for user:', req.baseUrl);
@@ -337,12 +337,9 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
337
337
  }
338
338
 
339
339
  async createManyWithId(appuser: UserContext, datas: T[]) {
340
- if (Array.isArray(datas)) {
341
- const dbsession = appuser.getDBSession();
342
- if (dbsession && !dbsession.inTransaction()) {
343
- dbsession.startTransaction({ readPreference: 'primary' });
344
- }
345
340
 
341
+ if (Array.isArray(datas)) {
342
+
346
343
  for (let i = 0; i < datas.length; i++) {
347
344
  const data = datas[i];
348
345
  let isolationFilter: any = { ...appuser.getCreateFilterWithId() };
@@ -353,12 +350,11 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
353
350
  await this.validateData(appuser, data);
354
351
  this.applyNestedDateTime(appuser, data, 'create');
355
352
  }
356
-
353
+
357
354
  const dbsession = appuser.getDBSession();
358
355
  if (dbsession && !dbsession.inTransaction()) {
359
356
  dbsession.startTransaction({ readPreference: 'primary' });
360
357
  }
361
- const result = await this.doc.insertMany(datas,{session:dbsession});
362
358
 
363
359
  const result = await this.doc.insertMany(datas, { session: dbsession });
364
360
  await this.audittrail.addManyEvents(appuser, this.documentName, 'createMany', datas);
@@ -840,7 +836,7 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
840
836
  }
841
837
  };
842
838
 
843
- findIdThenPatch = async (appuser: UserContext, id: string, data: T, session: mongo.ClientSession = undefined,skipLog:boolean=false) => {
839
+ findIdThenPatch = async (appuser: UserContext, id: string, data: Partial<T>, session: mongo.ClientSession = undefined, skipLog: boolean = false) => {
844
840
  const existingdata = await this.findById(appuser, id);
845
841
  if (!existingdata) {
846
842
  throw new NotFoundException(`${id} not found`, 'not found');
@@ -853,7 +849,8 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
853
849
 
854
850
  await this.identifyForeignKeys(appuser, data);
855
851
 
856
- if (this.hooks.beforeUpdate) await this.hooks.beforeUpdate(appuser, id, existingdata, data);
852
+ //patch not suitable trigger afterupdate
853
+ // if (this.hooks.beforeUpdate) await this.hooks.beforeUpdate(appuser, id, existingdata, data);
857
854
 
858
855
  const dbsession = appuser.getDBSession();
859
856
  if (dbsession && !dbsession.inTransaction()) {
@@ -864,7 +861,8 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
864
861
  // Object.assign(existingdata, data);
865
862
  delete data['_id'];
866
863
 
867
- this.reCalculateValue(data);
864
+ //patch not suitable trigger afterupdate
865
+ // this.reCalculateValue(data);
868
866
 
869
867
  // existingdata['_id']=''
870
868
  // console.log("newdata",data)
@@ -883,13 +881,14 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
883
881
  new: true,
884
882
  });
885
883
  //skip audit trail, useful when want to patch x-foreignkey code,label
886
- if(!skipLog) {
884
+ if (!skipLog) {
887
885
  await this.audittrail.addEvent(appuser, this.documentName, id, 'patch', data);
888
886
  }
889
887
  appuser.addUpdatedRecordId(this.documentName, data._id);
890
888
 
891
- if (this.hooks.afterUpdate) await this.hooks.afterUpdate(appuser, id, existingdata, result);
892
- await this.callWebhook(appuser, 'update', result);
889
+ //patch not suitable trigger afterupdate
890
+ // if (this.hooks.afterUpdate) await this.hooks.afterUpdate(appuser, id, existingdata, result);
891
+ // await this.callWebhook(appuser, 'update', result);
893
892
  return result; //await this.findById(appuser, id);
894
893
  } catch (err) {
895
894
  throw new InternalServerErrorException(err.message);
@@ -1040,7 +1039,7 @@ export class SimpleAppService<T extends { _id?: string; __v?: number }> {
1040
1039
  async runDefault(appuser: UserContext): Promise<unknown> {
1041
1040
  return 'Hello this is ' + this.getDocumentType() + ': ' + this.getDocumentName();
1042
1041
  }
1043
- async identifyForeignKeys(appuser: UserContext, data: T) {
1042
+ async identifyForeignKeys(appuser: UserContext, data: Partial<T>) {
1044
1043
  /**
1045
1044
  * 1. looping schemas identify what foreign key exists
1046
1045
  * 2. loop through record obtain all foreign key value
@@ -47,8 +47,8 @@ export type DefaultHooks<T> = {
47
47
  beforeUpdate?: (
48
48
  appuser: UserContext,
49
49
  id: string,
50
- data: T,
51
50
  existingdata: T,
51
+ data: T,
52
52
  ) => Promise<void>;
53
53
  afterUpdate?: (appuser: UserContext, id: string, prevdata: T,newdata:T) => Promise<void>;
54
54
  beforeDelete?: (
@@ -0,0 +1,17 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+
8
+ import { ApiProperty } from '@nestjs/swagger';
9
+
10
+ export class UpgradeScript {
11
+ @ApiProperty({ type: String})
12
+ id: String
13
+ @ApiProperty({ type: String})
14
+ subject:String
15
+ @ApiProperty({ type: String})
16
+ description:String
17
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+ export class Environment {
8
+ systemEnable: boolean
9
+ stopUntil: string
10
+ maintenanceMessage: string
11
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+ export * from './dbupdate'
8
+ export * from './environment'
@@ -0,0 +1,39 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * --remove-this-line-to-prevent-override--
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+
8
+ import { InternalServerErrorException } from "@nestjs/common"
9
+ import { exec } from "child_process"
10
+ import mongoose, { ClientSession } from "mongoose"
11
+
12
+
13
+ const readEnvironment = async () =>{
14
+ try {
15
+ await mongoose.connection.db.collection('environment').aggregate([
16
+
17
+ ],).toArray() // `toArray` forces execution
18
+ return "read environment";
19
+ } catch (err) {
20
+ throw err
21
+ }
22
+ }
23
+
24
+
25
+ export const v1_00_00 = ()=>{
26
+ const subject = 'Just a sample'
27
+ const description = `do nothing, only read enironment
28
+ `;
29
+ const execute = async () =>{
30
+ try{
31
+ const res1 = await readEnvironment()
32
+
33
+ return `${res1}`
34
+ }catch(e){
35
+ throw e
36
+ }
37
+ }
38
+ return {execute,subject,description}
39
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * --remove-this-line-to-prevent-override--
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+ export { v1_00_00 } from './1.00.00'
8
+
@@ -0,0 +1,72 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+ import { Controller, Get, Post, Param,Logger,HttpCode } from '@nestjs/common';
8
+ import { MaintenanceService } from './maintenance.service';
9
+ import { ApiTags, ApiBody, ApiResponse, ApiOperation, ApiQuery } from '@nestjs/swagger';
10
+ import { Roles } from 'src/simpleapp/generate/commons/roles/roles.decorator';
11
+ import { Role } from 'src/simpleapp/generate/commons/roles/roles.enum';
12
+ import * as schemas from './apischemas'
13
+
14
+ @ApiTags('maintenance')
15
+ @Controller('maintenance')
16
+ @Roles(Role.SuperAdmin)
17
+ export class MaintenanceController {
18
+ private logger = new Logger();
19
+ constructor(private readonly maintenanceSvc: MaintenanceService) {}
20
+
21
+ @Get('/get-updates')
22
+ @Roles(Role.SuperAdmin)
23
+ @ApiResponse({
24
+ status: 200,
25
+ description: 'Sample 200 response',
26
+ type: [schemas.UpgradeScript],
27
+ })
28
+ async getUpdate() {
29
+ const result = await this.maintenanceSvc.getUpdates();
30
+ return result
31
+ }
32
+
33
+ @Post('/run-updates/:id')
34
+ @HttpCode(200)
35
+ @Roles(Role.SuperAdmin)
36
+ @ApiResponse({
37
+ status: 200,
38
+ description: 'Sample 200 response',
39
+ type: [String],
40
+ })
41
+ async runUpdate(@Param('id') id:string) {
42
+ const result:string = await this.maintenanceSvc.runUpdates(id);
43
+ return result
44
+ }
45
+
46
+ @Post('/stop-service')
47
+ @HttpCode(200)
48
+ @Roles(Role.SuperAdmin)
49
+ @ApiResponse({
50
+ status: 200,
51
+ description: 'Sample 200 response',
52
+ type: [String],
53
+ })
54
+ async runStopService() {
55
+ const result:string = await this.maintenanceSvc.runStopService();
56
+ return result
57
+ }
58
+
59
+ @Post('/start-service')
60
+ @HttpCode(200)
61
+ @Roles(Role.SuperAdmin)
62
+ @ApiResponse({
63
+ status: 200,
64
+ description: 'Sample 200 response',
65
+ type: [String],
66
+ })
67
+ async runStartService() {
68
+ const result:string = await this.maintenanceSvc.runStartService();
69
+ return result
70
+ }
71
+
72
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+
8
+ import { BadRequestException, Injectable, InternalServerErrorException } from '@nestjs/common';
9
+ import { Model } from 'mongoose';
10
+ import { InjectModel } from '@nestjs/mongoose';
11
+ import * as dbupdate from './dbupdate'
12
+ import * as schemas from './apischemas'
13
+ @Injectable()
14
+ export class MaintenanceService {
15
+
16
+
17
+ constructor(@InjectModel('Environment') private sysEnvdoc: Model<schemas.Environment>) {
18
+
19
+ this.initEnv()
20
+ }
21
+
22
+ async initEnv(){
23
+ const res = await this.sysEnvdoc.find()
24
+ if(res.length==0){
25
+ const newdoc = new this.sysEnvdoc({
26
+ systemEnable:true
27
+ });
28
+ await newdoc.save()
29
+ }
30
+
31
+ }
32
+
33
+
34
+ async getUpdates() {
35
+ const keys = Object.keys(dbupdate)
36
+ const updatescripts:schemas.UpgradeScript[] = []
37
+ const key =keys[0]
38
+ // console.log(dbupdate[key]())
39
+
40
+
41
+ keys.forEach((k)=>{
42
+ const item = dbupdate[k]()
43
+ if(item.execute && item.subject){
44
+ updatescripts.push({
45
+ id: k,
46
+ subject:item.subject,
47
+ description: item.description
48
+ })
49
+ }
50
+ })
51
+
52
+ return Promise.resolve(updatescripts);
53
+ }
54
+
55
+ async runUpdates(versionId:string) {
56
+ try{
57
+ if(dbupdate[versionId]){
58
+ const result = await dbupdate[versionId]().execute()
59
+ return Promise.resolve(result);
60
+ }else{
61
+
62
+ throw new BadRequestException(`invalid update script ${versionId}`)
63
+ }
64
+
65
+ }catch(e){
66
+ throw new InternalServerErrorException(`Error db update (${versionId}): ${e.message}`)
67
+ }
68
+
69
+
70
+ }
71
+
72
+ async runStopService(){
73
+ const res = await this.sysEnvdoc.find()
74
+ if(res.length>0){
75
+ res[0].systemEnable=false
76
+ res[0].save()
77
+ }
78
+ return Promise.resolve(`status: ${res[0].systemEnable}`)
79
+ }
80
+ async runStartService(){
81
+ const res = await this.sysEnvdoc.find()
82
+ if(res.length>0){
83
+ res[0].systemEnable=true
84
+ res[0].save()
85
+ }
86
+ return Promise.resolve(`status: ${res[0].systemEnable}`)
87
+ }
88
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * This file was automatically generated by simpleapp generator. Every
3
+ * MODIFICATION OVERRIDE BY GENERATEOR
4
+ * last change 2025-08-27
5
+ * Author: Ks Tan
6
+ */
7
+ import { Schema } from 'mongoose';
8
+ // import { TenantClientSetting, TenantOwner, TenantOutstandingReminder, Tenant } from '../types/tenant.type';
9
+ const schemasetting = {
10
+ systemEnable: { type: Boolean},
11
+ stopUntil: { type: String },
12
+ maintenanceMessage: { type: String},
13
+ };
14
+
15
+ export const EnvironmentMongoSchema = new Schema(schemasetting, { collection: 'environment' })
16
+
@@ -10,6 +10,10 @@ import {DocNumberFormatGenerator} from './generate/commons/docnogenerator.servic
10
10
  import { AuditTrail } from './generate/commons/audittrail.service';
11
11
  import { RunWebhookService } from '../simpleapp/generate/commons/runwebhook.service'
12
12
  import { UserResolverService } from './services/userresolver.service';
13
+ import {MaintenanceService} from './maintenance/maintenance.service'
14
+ import {MaintenanceController} from './maintenance/maintenance.controller'
15
+ import {EnvironmentMongoSchema} from './maintenance/models/environment.model'
16
+
13
17
  // auto import modules
14
18
  <% for(let i=0;i<it.modules.length; i++){ %>
15
19
  <% let obj = it.modules[i]%>
@@ -42,6 +46,7 @@ import additionalModule from './additional.module';
42
46
  ...additionalModule.imports,
43
47
 
44
48
  MongooseModule.forFeature([
49
+ { name: 'Environment', schema: EnvironmentMongoSchema },
45
50
  <% for(let i=0;i<it.modules.length; i++){ %>
46
51
  <% let obj = it.modules[i]%>
47
52
  { name: '<%= obj.docname %>', schema: <%= obj.docname %>MongoSchema },