@simitgroup/simpleapp-generator 2.0.2-v-alpha → 2.0.2-x-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 +14 -0
  2. package/dist/buildinschemas/autoincreament.d.ts +3 -0
  3. package/dist/buildinschemas/autoincreament.d.ts.map +1 -0
  4. package/dist/buildinschemas/autoincreament.js +39 -0
  5. package/dist/buildinschemas/autoincreament.js.map +1 -0
  6. package/dist/buildinschemas/docnoformat.d.ts +3 -0
  7. package/dist/buildinschemas/docnoformat.d.ts.map +1 -0
  8. package/dist/buildinschemas/docnoformat.js +58 -0
  9. package/dist/buildinschemas/docnoformat.js.map +1 -0
  10. package/dist/buildinschemas/documentevent.d.ts +3 -0
  11. package/dist/buildinschemas/documentevent.d.ts.map +1 -0
  12. package/dist/buildinschemas/documentevent.js +48 -0
  13. package/dist/buildinschemas/documentevent.js.map +1 -0
  14. package/dist/buildinschemas/webhooklog.d.ts +3 -0
  15. package/dist/buildinschemas/webhooklog.d.ts.map +1 -0
  16. package/dist/buildinschemas/webhooklog.js +79 -0
  17. package/dist/buildinschemas/webhooklog.js.map +1 -0
  18. package/dist/framework.d.ts.map +1 -1
  19. package/dist/framework.js +8 -18
  20. package/dist/framework.js.map +1 -1
  21. package/dist/generate.d.ts.map +1 -1
  22. package/dist/generate.js +8 -18
  23. package/dist/generate.js.map +1 -1
  24. package/dist/index.js +7 -17
  25. package/dist/index.js.map +1 -1
  26. package/dist/libs.d.ts.map +1 -1
  27. package/dist/processors/bpmnbuilder.d.ts.map +1 -1
  28. package/dist/processors/bpmnbuilder.js +7 -17
  29. package/dist/processors/bpmnbuilder.js.map +1 -1
  30. package/dist/processors/jrxmlbuilder.d.ts.map +1 -1
  31. package/dist/processors/jrxmlbuilder.js +7 -17
  32. package/dist/processors/jrxmlbuilder.js.map +1 -1
  33. package/dist/processors/jsonschemabuilder.d.ts.map +1 -1
  34. package/dist/processors/jsonschemabuilder.js.map +1 -1
  35. package/package.json +1 -1
  36. package/templates/nest/src/simple-app/_core/features/document-no-format/document-no-format.service.ts.eta +68 -62
  37. package/templates/nest/src/simple-app/_core/features/mini-app/mini-app-manager/mini-app-manager.controller.ts.eta +2 -3
  38. package/templates/nest/src/simple-app/_core/features/profile/profile.controller.ts.eta +7 -7
  39. package/templates/nest/src/simple-app/_core/features/profile/profile.schema.ts.eta +38 -6
  40. package/templates/nest/src/simple-app/_core/features/user-context/user-context.type.ts.eta +43 -13
  41. package/templates/nest/src/simple-app/_core/features/user-context/user.context.ts.eta +57 -37
  42. package/templates/nest/src/simple-app/_core/framework/schemas/simple-app.schema.ts.eta +34 -25
  43. package/templates/nest/src/simple-app/_core/framework/simple-app.interceptor.ts.eta +23 -20
  44. package/templates/nest/src/simple-app/_core/utils/dayjs.ts.eta +14 -9
  45. package/templates/nuxt/app.vue.eta +46 -47
  46. package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +102 -92
  47. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +69 -51
  48. package/templates/nuxt/server/api/auth/[...].ts.eta +1 -0
  49. package/templates/nuxt/server/api/auth/logout.ts.eta +20 -7
@@ -6,32 +6,31 @@
6
6
  * 2.
7
7
  */
8
8
  import Base64URL from '@darkwolf/base64url';
9
- import { isEmpty } from 'lodash';
10
- import { Request } from 'express';
11
- import { InjectModel } from '@nestjs/mongoose';
12
9
  import { BadRequestException, ForbiddenException, Injectable, Logger, Scope } from '@nestjs/common';
10
+ import { Request } from 'express';
13
11
  import * as jwt from 'jsonwebtoken';
12
+ import { isEmpty } from 'lodash';
14
13
  import { ClientSession, Model, PipelineStage } from 'mongoose';
15
14
 
16
15
  // import { Branch, Organization, Permission, Tenant, TenantClientSetting, User, Appintegration, Webhook, Miniappinstallation, TUserType, TMiniApiTokenInfo } from 'src/simpleapp/generate/types';
17
- import { TUserType, TMiniApiTokenInfo } from 'src/simple-app/_core/framework/schemas';
16
+ import { TMiniApiTokenInfo, TUserType } from 'src/simple-app/_core/framework/schemas';
18
17
  import { MiniAppInstallation } from 'src/simple-app/_core/resources/mini-app-installation/mini-app-installation.schema';
19
18
 
20
- import { Tenant, TenantClientSetting } from 'src/simple-app/_core/resources/tenant/tenant.schema';
21
19
  import { Organization } from 'src/simple-app/_core/resources/organization/organization.schema';
22
- import { Branch } from 'src/simple-app/_core/resources/branch/branch.schema';
20
+ import { Tenant, TenantClientSetting } from 'src/simple-app/_core/resources/tenant/tenant.schema';
23
21
 
24
- import { Permission } from 'src/simple-app/_core/resources/permission/permission.schema';
25
- import { User } from 'src/simple-app/_core/resources/user/user.schema';
22
+ import { Environment } from '@core-features/maintenance/schemas';
23
+ import { TenantLicenseEnum } from '@resources/tenant/tenant.enum';
24
+ import { ProfileUserBranch, TenantHealth, TenantPermission, UserContextInfo } from 'src/simple-app/_core/features/profile/profile.schema';
26
25
  import { Webhook } from 'src/simple-app/_core/features/webhook/schemas';
27
- import { UserContextInfo, ProfileUserBranch, ProfileUserInvites, TenantPermission } from 'src/simple-app/_core/features/profile/profile.schema';
26
+ import { Permission, StepData } from 'src/simple-app/_core/resources/permission/permission.schema';
27
+ import { User } from 'src/simple-app/_core/resources/user/user.schema';
28
28
  import { ModifiedRecords } from '../../framework/schemas';
29
+ import { SimpleAppDbRevertService } from '../../framework/simple-app-db-revert.service';
29
30
  import { Role } from '../auth/role-guard/roles.enum';
30
- import { Environment } from '@core-features/maintenance/schemas';
31
31
  import * as rolegroups from '../auth/role-guard/roles.group';
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';
32
+ import { TenantHealthStatusEnum } from './user-context.enum';
33
+ import { ENV_EMAIL_ROLE_MAP, EnvEmailFieldKey, RoleGroupResolver, TenantPermissionAggregateRow } from './user-context.type';
35
34
 
36
35
  // import systemWebHooks from '../../webhooks';
37
36
  @Injectable({ scope: Scope.REQUEST })
@@ -136,6 +135,16 @@ export class UserContext extends UserContextInfo {
136
135
 
137
136
  protected userType: TUserType = 'normal';
138
137
 
138
+ tenantHealth?: TenantHealth = {
139
+ status: TenantHealthStatusEnum.ACTIVE,
140
+ message: 'User context initial',
141
+ isLicenseRenewable: false,
142
+ isLicenseDowngradable: false,
143
+ isLicenseCancellable: false,
144
+ isLicenseUpgradable: true,
145
+ isLicenseAddOnAllowed: false,
146
+ };
147
+
139
148
  constructor(
140
149
  private readonly userModel: Model<User>,
141
150
  private readonly permModel: Model<Permission>,
@@ -215,7 +224,7 @@ export class UserContext extends UserContextInfo {
215
224
 
216
225
  setLicense = (license: TenantLicenseEnum) => {
217
226
  if (!this.tenantInfo) {
218
- this.tenantInfo = {} as any;
227
+ this.tenantInfo = {} as Tenant;
219
228
  }
220
229
 
221
230
  this.tenantInfo.license = license;
@@ -260,6 +269,10 @@ export class UserContext extends UserContextInfo {
260
269
  this.offsetMinute = offsetMinute;
261
270
  };
262
271
 
272
+ setTenantHealth = (data: TenantHealth) => {
273
+ this.tenantHealth = data;
274
+ };
275
+
263
276
  // async obtainNoTenantProfile() {
264
277
  // const pipelines: PipelineStage[] = [{ $match: { uid: this.uid, tenantId: this.tenantId } }];
265
278
  // try {
@@ -288,8 +301,8 @@ export class UserContext extends UserContextInfo {
288
301
  // return this.obtainNoTenantProfile();
289
302
  // }
290
303
  const pipelines: PipelineStage[] = [
291
- //get profile
292
- { $match: { uid: this.uid, tenantId: this.tenantId } },
304
+ //get profile (inactive users must not load org/branch/groups)
305
+ { $match: { uid: this.uid, tenantId: this.tenantId, active: { $ne: false } } },
293
306
  {
294
307
  $lookup: {
295
308
  from: 'tenant',
@@ -497,7 +510,7 @@ export class UserContext extends UserContextInfo {
497
510
  },
498
511
  ];
499
512
 
500
- const userProfiles: UserContextInfo[] = await this.userModel.aggregate(pipelines).exec();
513
+ const userProfiles = await this.userModel.aggregate<UserContextInfo>(pipelines).exec();
501
514
  return userProfiles[0];
502
515
  }
503
516
 
@@ -539,7 +552,7 @@ export class UserContext extends UserContextInfo {
539
552
  });
540
553
  this.branches = userProfile['branches'];
541
554
  this.groups = userProfile['groups'] ?? [];
542
- this.clientSetting = userProfile['clientSetting'] ?? {
555
+ this.clientSetting = userProfile.tenantInfo?.clientSetting ?? {
543
556
  auditTrail: false,
544
557
  disableClassReminder: true,
545
558
  webhook: false,
@@ -552,24 +565,24 @@ export class UserContext extends UserContextInfo {
552
565
  }
553
566
  if (this.tenantInfo?.company && this.tenantInfo.company.billUserEmail === this.email) {
554
567
  this.roles.push(Role.Billing);
568
+ this.roles.push(Role.Tenant_search);
569
+ this.roles.push(Role.TenantInvoice_search);
555
570
  }
556
571
  if (systemEnv) {
557
- // console.log("systemEnv",systemEnv)
558
- const emailFields = {
559
- adminEmails: 'SuperAdmin',
560
- billingEmails: 'DevBilling',
561
- supportEmails: 'DevSupport',
562
- };
563
- for (const f of Object.keys(emailFields)) {
564
- if (Array.isArray(systemEnv[f]) && systemEnv[f].includes(this.email) && !this.roles.includes(Role[emailFields[f]])) {
565
- this.roles.push(Role[emailFields[f]]);
572
+ for (const f of Object.keys(ENV_EMAIL_ROLE_MAP) as EnvEmailFieldKey[]) {
573
+ const emails = systemEnv[f];
574
+ const targetRole = ENV_EMAIL_ROLE_MAP[f];
575
+ if (Array.isArray(emails) && emails.includes(this.email) && !this.roles.includes(targetRole)) {
576
+ this.roles.push(targetRole);
566
577
  }
567
578
  }
568
579
  }
569
580
 
570
581
  // console.log('this.roles', this.roles);
571
582
  for (const group of this.groups) {
572
- const roles: Role[] = rolegroups[group]();
583
+ const roleResolver = (rolegroups as Record<string, RoleGroupResolver | undefined>)[group];
584
+ if (!roleResolver) continue;
585
+ const roles: Role[] = roleResolver();
573
586
  //(<() => Role[]>rolegroups[group])();
574
587
  for (let r = 0; r < roles.length; r++) {
575
588
  if (!this.roles.includes(roles[r])) {
@@ -797,6 +810,7 @@ export class UserContext extends UserContextInfo {
797
810
  branches: this.getBranches(),
798
811
  invites: this.getInvites(),
799
812
  moreProps: this.moreProps,
813
+ tenantHealth: this.tenantHealth,
800
814
  };
801
815
  return result;
802
816
  }
@@ -887,6 +901,8 @@ export class UserContext extends UserContextInfo {
887
901
  tenantId: {
888
902
  $gt: 0,
889
903
  },
904
+ // Inactive user rows must not appear on pick-tenant / org switcher
905
+ active: { $ne: false },
890
906
  },
891
907
  },
892
908
  {
@@ -964,10 +980,10 @@ export class UserContext extends UserContextInfo {
964
980
  },
965
981
  ];
966
982
 
967
- const datas = await this.userModel.aggregate(pipelines);
983
+ const datas = await this.userModel.aggregate<TenantPermissionAggregateRow>(pipelines);
968
984
  for (const r of datas) {
969
985
  const perms: ProfileUserBranch[] = [];
970
- for (const p of r.perms) {
986
+ for (const p of r.perms ?? []) {
971
987
  perms.push({
972
988
  permissionId: p._id,
973
989
  tenantId: p.tenantId,
@@ -1039,7 +1055,7 @@ export class UserContext extends UserContextInfo {
1039
1055
  const pipeLine: PipelineStage[] = [{ $match: { tenantId: -1 } }, { $unionWith: { coll: 'organization', pipeline: [{ $match: { orgId: this.orgId } }] } }, { $limit: 1 }];
1040
1056
 
1041
1057
  // console.log("set as static user", pipeLine)
1042
- const result: Organization[] = await this.userModel.aggregate(pipeLine).exec();
1058
+ const result = await this.userModel.aggregate<Organization>(pipeLine).exec();
1043
1059
  // console.log("result",result)
1044
1060
  if (result && result.length > 0) {
1045
1061
  const res = result[0];
@@ -1150,7 +1166,7 @@ export class UserContext extends UserContextInfo {
1150
1166
  });
1151
1167
  this.branches = userProfile['branches'];
1152
1168
  this.groups = userProfile['groups'] ?? [];
1153
- this.clientSetting = userProfile['clientSetting'] ?? {
1169
+ this.clientSetting = userProfile.tenantInfo?.clientSetting ?? {
1154
1170
  auditTrail: false,
1155
1171
  disableClassReminder: true,
1156
1172
  webhook: false,
@@ -1159,7 +1175,9 @@ export class UserContext extends UserContextInfo {
1159
1175
  this.roles = userProfile['roles'] ?? [Role.Everyone, Role.User];
1160
1176
 
1161
1177
  for (const group of this.groups) {
1162
- const roles: Role[] = rolegroups[group]();
1178
+ const roleResolver = (rolegroups as Record<string, RoleGroupResolver | undefined>)[group];
1179
+ if (!roleResolver) continue;
1180
+ const roles: Role[] = roleResolver();
1163
1181
  for (let r = 0; r < roles.length; r++) {
1164
1182
  if (!this.roles.includes(roles[r])) {
1165
1183
  this.roles.push(roles[r]);
@@ -1233,8 +1251,9 @@ export class UserContext extends UserContextInfo {
1233
1251
  /**
1234
1252
  * Define additional properties from user into moreProps
1235
1253
  */
1236
- setMoreProps(userProfile: UserContextInfo): Record<string, any> {
1254
+ setMoreProps(userProfile: UserContextInfo): Record<string, unknown> {
1237
1255
  const allprops = Object.keys(userProfile);
1256
+ const profileRecord = userProfile as unknown as Record<string, unknown>;
1238
1257
  const excludekeys = [
1239
1258
  'created',
1240
1259
  'createdBy',
@@ -1265,11 +1284,11 @@ export class UserContext extends UserContextInfo {
1265
1284
  'uid',
1266
1285
  'orgRecordId',
1267
1286
  ];
1268
- const data: Record<string, any> = {};
1287
+ const data: Record<string, unknown> = {};
1269
1288
  for (let i = 0; i < allprops.length; i++) {
1270
1289
  const key = allprops[i];
1271
1290
  if (!excludekeys.includes(key)) {
1272
- data[key] = userProfile[key];
1291
+ data[key] = profileRecord[key];
1273
1292
  }
1274
1293
  }
1275
1294
 
@@ -1293,7 +1312,7 @@ export class UserContext extends UserContextInfo {
1293
1312
  return isodate;
1294
1313
  }
1295
1314
 
1296
- addTransactionStep(action: string, collection: string, id: string[], data: any[]) {
1315
+ addTransactionStep(action: string, collection: string, id: string[], data: StepData['data']) {
1297
1316
  this.transSteps.push({ action: action, collection: collection, id: id, data: data });
1298
1317
  }
1299
1318
 
@@ -1326,6 +1345,7 @@ export class UserContext extends UserContextInfo {
1326
1345
  if (this.dbsession.inTransaction()) await this.dbsession.abortTransaction();
1327
1346
  }
1328
1347
  }
1348
+
1329
1349
  async endSession() {
1330
1350
  await this.dbsession.endSession();
1331
1351
  }
@@ -1,6 +1,7 @@
1
+ import { Field, ObjectType } from '@nestjs/graphql';
1
2
  import { ApiProperty } from '@nestjs/swagger';
2
- import { Field, ObjectType, ID } from '@nestjs/graphql';
3
- import { JSONSchema7, JSONSchema7Type, JSONSchema7Version, JSONSchema7TypeName, JSONSchema7Definition } from 'json-schema';
3
+ import { JSONSchema7 } from 'json-schema';
4
+ import { PipelineStage } from 'mongoose';
4
5
  import { Permission } from 'src/simple-app/_core/resources/permission/permission.schema';
5
6
 
6
7
  export class ModifiedCollection {
@@ -18,12 +19,14 @@ export class DocNumberFormatResult {
18
19
  }
19
20
 
20
21
  export class SearchBody {
21
- filter?: object;
22
+ filter?: PipelineStage.Match['$match'];
22
23
 
23
- fields?: any[];
24
+ fields?: PipelineStage.Project['$project'];
25
+
26
+ sorts?: PipelineStage.Sort['$sort'];
27
+
28
+ lookup?: PipelineStage.Lookup['$lookup'];
24
29
 
25
- sorts?: any[];
26
- lookup?: object;
27
30
  pagination?: {
28
31
  pageSize?: number;
29
32
  pageNo?: number;
@@ -39,22 +42,6 @@ export enum IsolationType {
39
42
  export class MoreProjectionType {
40
43
  [key: string]: string;
41
44
  }
42
- export class ApiEvent {
43
- _id: string;
44
- created: string;
45
- updated?: string;
46
- duration: number;
47
- createdBy: string;
48
- path: string;
49
- ip: string;
50
- method: string;
51
- headers: any;
52
- data?: any;
53
- statusCode: number;
54
- status: string;
55
- errMsg?: string;
56
- errData?: any;
57
- }
58
45
 
59
46
  export class DeleteResultType<T> {
60
47
  data: T;
@@ -70,6 +57,7 @@ export class DocumentStatus {
70
57
  readOnly: boolean;
71
58
  actions: string[]; //api name ['confirm','revert','close','void' and etc]
72
59
  }
60
+
73
61
  export enum RESTMethods {
74
62
  'post' = 'post',
75
63
  'get' = 'get',
@@ -126,14 +114,21 @@ export class ForeignKey {
126
114
  @Field()
127
115
  @ApiProperty({ type: () => String })
128
116
  _id?: string;
117
+
129
118
  @Field()
130
119
  @ApiProperty({ type: () => String })
131
120
  code?: string;
121
+
132
122
  @Field()
133
123
  @ApiProperty({ type: () => String })
134
124
  label?: string;
135
- [key: string]: any;
125
+
126
+ // ! DO NOT use an index signature on your own schemas. ForeignKey is intentionally strict — only
127
+ // ! `_id`, `code`, and `label` are allowed. For fields with extra dynamic properties, extend this
128
+ // ! class or use the appropriate XxxAutoComplete type instead.
129
+ // [key: string]: any;
136
130
  }
131
+
137
132
  export class MyForeignKey {
138
133
  [collectionname: string]: string[];
139
134
  }
@@ -141,6 +136,9 @@ export class MyForeignKey {
141
136
  export class NoParam {}
142
137
 
143
138
  export class DynamicParam {
139
+ // ! `any` is intentional here. DynamicParam represents a fully open key-value map where both
140
+ // ! the keys and value types are unknown at compile time. Do not use this class for typed fields.
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
144
142
  [key: string]: any;
145
143
  }
146
144
 
@@ -163,11 +161,11 @@ export class SchemaFields {
163
161
  updatedBy?: string;
164
162
  __v?: number;
165
163
  documentStatus?: string;
166
- [key: string]: any; //SimpleAppJSONSchema7 | SimpleAppJSONSchema7[] | undefined;
167
164
  }
168
165
 
169
166
  export class SimpleAppJSONSchema7 implements JSONSchema7 {
170
167
  'x-simpleapp-config': SchemaConfig;
168
+ type?: JSONSchema7['type'];
171
169
  }
172
170
  export const SimpleAppJSONSchema7Definition = SimpleAppJSONSchema7;
173
171
 
@@ -176,7 +174,18 @@ export class BranchPermission extends Permission {
176
174
  branch: ForeignKey;
177
175
  }
178
176
 
179
- export type StepData = {action:string,collection:string,id:string[],data:any[]}
177
+ export type StepData = {
178
+ action: string;
179
+
180
+ collection: string;
181
+
182
+ id: string[];
183
+
184
+ // ! `any[]` is intentional here. Each step in a SAGA transaction can carry data from any
185
+ // ! MongoDB collection, so the shape is not known until runtime.
186
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
+ data: any[];
188
+ };
180
189
 
181
190
  export type DocumentDictEntry = {
182
191
  docName: string;
@@ -4,13 +4,13 @@
4
4
  * last change 2023-03-17
5
5
  * Author: Ks Tan
6
6
  */
7
+ import { ApiEvent } from '@core-features/log/schemas';
7
8
  import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
8
9
  import { InjectConnection, InjectModel } from '@nestjs/mongoose';
10
+ import type { Response as ExpressResponse } from 'express';
9
11
  import { Connection, Model } from 'mongoose';
10
- import { Observable } from 'rxjs';
11
12
  import { catchError, map, tap } from 'rxjs/operators';
12
13
  import { UserContext } from '../features/user-context/user.context';
13
- import { ApiEvent } from './schemas';
14
14
  import { SimpleAppDbRevertService } from './simple-app-db-revert.service';
15
15
  @Injectable()
16
16
  export class SimpleAppInterceptor implements NestInterceptor {
@@ -20,40 +20,32 @@ export class SimpleAppInterceptor implements NestInterceptor {
20
20
  private simpleAppDbRevertService: SimpleAppDbRevertService,
21
21
  ) {}
22
22
 
23
- async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
23
+ async intercept(context: ExecutionContext, next: CallHandler) {
24
24
  //not http request then exclude such as graphql
25
25
  if (context.getType() != 'http') {
26
26
  // obtain usersession here
27
- return next.handle().pipe(
28
- tap(async () => {
29
- //console.log("none http, do nothing at interceptor")
30
- }),
31
- );
27
+ return next.handle().pipe(tap(() => {}));
32
28
  }
33
- const req = context.switchToHttp().getRequest();
34
- const resp = context.switchToHttp().getResponse();
29
+ const req = context.switchToHttp().getRequest<Request>();
30
+ const resp = context.switchToHttp().getResponse<ExpressResponse>();
35
31
  //console.log("want to get user session:", Object.keys(req))
36
32
 
37
33
  if (req.url == '/health') {
38
- return next.handle().pipe(
39
- tap(async () => {
40
- //console.log("none http, do nothing at interceptor")
41
- }),
42
- );
34
+ return next.handle().pipe(tap(() => {}));
43
35
  }
44
36
 
45
- const usersession: UserContext = req['sessionuser'];
37
+ const usersession = req['sessionuser'] as UserContext;
46
38
  //console.log("after read user session:",usersession)
47
39
  const method = req['method'];
48
40
  const headers = { ...req['headers'] };
49
- const ip = req['ip'];
41
+ const ip = req['ip'] as string;
50
42
  const url = req['url'];
51
43
  // let { url, method, headers, body }
52
44
  const session = await this.connection.startSession();
53
45
  if (!session['runCount']) {
54
46
  session['runCount'] = 0;
55
47
  } else {
56
- session['runCount'] = session['runCount'] + 1;
48
+ session['runCount'] = (session['runCount'] as number) + 1;
57
49
  }
58
50
  usersession.setDBSession(session);
59
51
  // const session: ClientSession = usersession.getDBSession();
@@ -83,8 +75,10 @@ export class SimpleAppInterceptor implements NestInterceptor {
83
75
  return next.handle().pipe(
84
76
  map((data) => {
85
77
  if (data && typeof data === 'object' && 'pagination' in data && 'items' in data) {
78
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
86
79
  return data;
87
80
  }
81
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
88
82
  return data;
89
83
  }),
90
84
  catchError(async (err, caught) => {
@@ -97,20 +91,29 @@ export class SimpleAppInterceptor implements NestInterceptor {
97
91
  }
98
92
 
99
93
  const responseBody = {
94
+ // eslint-disable-next-line
100
95
  message: err.message,
101
96
  timestamp: new Date().toISOString(),
102
97
  path: url,
103
- error: err.options,
98
+ // eslint-disable-next-line
99
+ error: err.options as object,
104
100
  };
105
101
 
102
+ // eslint-disable-next-line
106
103
  eventObj.statusCode = err.status;
104
+ // eslint-disable-next-line
107
105
  eventObj.errMsg = responseBody.message;
108
106
  eventObj.data = req.body;
109
107
  eventObj.status = 'NG';
110
108
  eventObj.errData = responseBody.error;
111
- resp.status(err?.status ?? 500);
109
+
110
+ resp.status(
111
+ // eslint-disable-next-line
112
+ err?.status ?? 500,
113
+ );
112
114
  return responseBody;
113
115
  }),
116
+ // eslint-disable-next-line
114
117
  tap(async () => {
115
118
  // console.log("============interceptor tap",method,url)
116
119
  const endtime = new Date();
@@ -1,28 +1,29 @@
1
1
  import dayjs from 'dayjs';
2
2
  import duration from 'dayjs/plugin/duration';
3
+ import isBetween from 'dayjs/plugin/isBetween';
3
4
  import timezone from 'dayjs/plugin/timezone';
4
5
  import utc from 'dayjs/plugin/utc';
5
6
 
6
7
  dayjs.extend(utc);
7
8
  dayjs.extend(duration);
8
9
  dayjs.extend(timezone);
10
+ dayjs.extend(isBetween);
9
11
 
10
12
  export const getDayJs = () => {
11
13
  return dayjs;
12
14
  };
13
15
 
14
-
15
16
  /**
16
- * this function is used to convert user time date to UTC
17
- * @param date
18
- * @param timeZone from appuser, example Asia/Malaysia
19
- * @returns
20
- */
17
+ * this function is used to convert user time date to UTC
18
+ * @param date
19
+ * @param timeZone from appuser, example Asia/Malaysia
20
+ * @returns
21
+ */
21
22
  export const convertToStartOfDayUTC = (date: string, timeZone: string): string => {
22
23
  const startOfDay = dayjs.tz(date, timeZone).startOf('day');
23
24
  const utcTime = startOfDay.utc().format();
24
25
  return utcTime;
25
- }
26
+ };
26
27
 
27
28
  /**
28
29
  * this function is used to convert user time date to UTC
@@ -34,7 +35,7 @@ export const convertToEndOfDayUTC = (date: string, timeZone: string): string =>
34
35
  const endOfDay = dayjs.tz(date, timeZone).endOf('day');
35
36
  const utcTime = endOfDay.utc().format();
36
37
  return utcTime;
37
- }
38
+ };
38
39
 
39
40
  /**
40
41
  * this function is used to convert UTC time to user timezone
@@ -44,4 +45,8 @@ export const convertToEndOfDayUTC = (date: string, timeZone: string): string =>
44
45
  export const convertUTCToTimezone = (date: string, timeZone: string): string => {
45
46
  const localTime = dayjs(date).tz(timeZone).format();
46
47
  return localTime;
47
- }
48
+ };
49
+
50
+ export const utcToLocalOffset = (utcTime: string, timeZoneOffset: number) => {
51
+ return dayjs.utc(utcTime).utcOffset(Number(timeZoneOffset));
52
+ };
@@ -1,17 +1,16 @@
1
1
  <template>
2
- <NuxtLayout>
3
-
2
+ <NuxtLayout>
4
3
  <!-- <NuxtLayout :name="getLayout()"> -->
5
- <ConfirmDialog></ConfirmDialog>
4
+ <ConfirmDialog></ConfirmDialog>
6
5
  <DynamicDialog />
7
- <SessionBlock/>
8
- <OverlayHoldscreen/>
9
- <EventDocumentViewer></EventDocumentViewer>
10
- <EventDecision/>
11
- <EventNotification/>
12
- <SubscriptionExpirationWarning/>
13
- <SubscriptionFreeBanner/>
14
- <NuxtPage/>
6
+ <SessionBlock />
7
+ <OverlayHoldscreen />
8
+ <EventDocumentViewer></EventDocumentViewer>
9
+ <EventDecision />
10
+ <EventNotification />
11
+ <SubscriptionFreeBanner />
12
+ <SubscriptionGracePeriodBanner />
13
+ <NuxtPage />
15
14
  </NuxtLayout>
16
15
  </template>
17
16
 
@@ -22,50 +21,50 @@
22
21
  * last change 2024-03-17
23
22
  * Author: Ks Tan
24
23
  */
25
- let currentXorg = getCurrentXorg()
26
- watch(()=>useRoute().fullPath,async (newval,oldvalue)=>{
27
- if(getCurrentXorg()!=currentXorg){
28
- currentXorg = getCurrentXorg()
29
- await reloadUserStore()
30
- }
31
- if(getPathPara('xorg','')!=''){
32
-
33
- if(getCurrentXorg()===''){
34
- navigateTo('/picktenant')
35
- }else if(!getUserProfile()?.currentGroup){
36
- goTo('pickgroup')
24
+ let currentXorg = getCurrentXorg();
25
+ watch(
26
+ () => useRoute().fullPath,
27
+ async (newval, oldvalue) => {
28
+ if (getCurrentXorg() != currentXorg) {
29
+ currentXorg = getCurrentXorg();
30
+ await reloadUserStore();
37
31
  }
38
- setGraphqlServer()
39
- }
40
- })
32
+ if (getPathPara("xorg", "") != "") {
33
+ if (getCurrentXorg() === "") {
34
+ navigateTo("/picktenant");
35
+ } else if (!getUserProfile()?.currentGroup) {
36
+ goTo("pickgroup");
37
+ }
38
+ setGraphqlServer();
39
+ }
40
+ },
41
+ );
41
42
 
42
- const getLayout = ()=>{
43
- // const { status } = useAuth();
44
-
43
+ const getLayout = () => {
44
+ // const { status } = useAuth();
45
45
  // if(status.value=='unauthenticated') return 'loginlayout'
46
46
  // else {
47
47
  // if (isMobile()) return 'mobile'
48
48
  // else 'default'
49
- // }
50
- }
49
+ // }
50
+ };
51
51
 
52
- onMounted(async()=>{
53
- const x = useAuthState()
54
- if(x.data.value?.expires && x.data.value?.expires > new Date().toISOString()){
55
- await reloadUserStore()
56
- const currentgroup = useCookie('currentGroup').value
52
+ onMounted(async () => {
53
+ const x = useAuthState();
54
+ if (x.data.value?.expires && x.data.value?.expires > new Date().toISOString()) {
55
+ await reloadUserStore();
56
+ const currentgroup = useCookie("currentGroup").value;
57
57
  //if no xorg, no enforce pick group
58
- if(getCurrentXorg()===''){
59
- navigateTo('/picktenant')
60
- }else if(!currentgroup){
61
- goTo('pickgroup')
58
+ if (getCurrentXorg() === "") {
59
+ navigateTo("/picktenant");
60
+ } else if (!currentgroup) {
61
+ goTo("pickgroup");
62
62
  }
63
- setGraphqlServer()
64
- }else{
65
- if(useRoute().path!='/login'){
63
+ setGraphqlServer();
64
+ } else {
65
+ if (useRoute().path != "/login") {
66
66
  navigateTo("/login");
67
- }
68
- }
69
-
70
- })
67
+ }
68
+ }
69
+ });
71
70
  </script>