@simitgroup/simpleapp-generator 1.6.7-h-alpha → 1.6.7-i-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 (35) hide show
  1. package/ReleaseNote.md +6 -0
  2. package/dist/generate.js +2 -0
  3. package/dist/generate.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/generate.ts +2 -0
  6. package/templates/basic/miniApi/resource.controller.ts.eta +10 -3
  7. package/templates/basic/miniApi/resource.service.ts.eta +9 -2
  8. package/templates/basic/nest/apischema.ts.eta +21 -6
  9. package/templates/basic/nest/controller.ts.eta +37 -16
  10. package/templates/basic/nuxt/resource-bridge.service.ts.eta +3 -2
  11. package/templates/miniApi/src/constants/api-scopes.ts.eta +1 -1
  12. package/templates/nest/src/simpleapp/generate/commons/middlewares/tenant.middleware.ts.eta +34 -14
  13. package/templates/nest/src/simpleapp/generate/commons/robotuser.service.ts.eta +4 -8
  14. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +154 -17
  15. package/templates/nuxt/composables/getUserStore.generate.ts.eta +62 -66
  16. package/templates/nuxt/plugins/19.simpleapp-mini-app-store.ts.eta +240 -203
  17. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +1 -1
  18. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureCustomField.vue.eta +34 -0
  19. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureCustomPage.vue.eta +68 -0
  20. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureScope.vue.eta +53 -0
  21. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppIcon.vue.eta +49 -0
  22. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppMenuButton.vue.eta +6 -4
  23. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppPageIframe.vue.eta +9 -3
  24. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppPermissionWrapper.vue.eta +4 -4
  25. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppRestrictedWarning.vue.eta +3 -3
  26. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppSettingLayout.vue.eta +3 -3
  27. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppSettingPage.vue.eta +2 -2
  28. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppWrapper.vue.eta +2 -32
  29. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItem.vue.eta +6 -5
  30. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItemBadge.vue.eta +15 -9
  31. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItemGroup.vue.eta +4 -4
  32. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationPage.vue.eta +135 -22
  33. package/templates/nuxt/simpleapp/generate/features/miniApp/app/types/miniApp.ts.eta +7 -7
  34. package/templates/nuxt/simpleapp/generate/features/miniApp/bridge/services/bridge-resource-accessor.service.ts.eta +3 -1
  35. package/templates/nuxt/simpleapp/generate/features/miniApp/bridge/services/bridge.service.ts.eta +3 -0
@@ -10,13 +10,14 @@ import { InjectModel } from '@nestjs/mongoose';
10
10
  import { BadRequestException, ForbiddenException, Injectable, Logger, Scope } from '@nestjs/common';
11
11
  import * as jwt from 'jsonwebtoken';
12
12
  import { ClientSession, Model, PipelineStage } from 'mongoose';
13
- import { Branch, Organization, Permission, Tenant, TenantClientSetting, User, Appintegration, Webhook } from 'src/simpleapp/generate/types';
13
+ import { Branch, Organization, Permission, Tenant, TenantClientSetting, User, Appintegration, Webhook, Miniappinstallation, TUserType, TMiniApiTokenInfo } from 'src/simpleapp/generate/types';
14
14
  import { ProfileUserBranch, ProfileUserInvites } from '../../profile/profile.types';
15
15
  import { ModifiedRecords } from '../types';
16
16
  import { Role } from './roles/roles.enum';
17
17
  import systemWebHooks from '../../webhooks';
18
18
  import * as rolegroups from './roles/roles.group';
19
-
19
+ import { isEmpty } from 'lodash';
20
+ import { Request } from 'express';
20
21
 
21
22
  @Injectable({ scope: Scope.REQUEST })
22
23
  export class UserContext {
@@ -62,6 +63,10 @@ export class UserContext {
62
63
  email: string;
63
64
  } = { uid: '', uname: '', fullname: '', email: '' };
64
65
 
66
+ protected miniApiToken?: string;
67
+
68
+ protected miniApiTokenInfo?: TMiniApiTokenInfo;
69
+
65
70
  protected groups: string[] = [];
66
71
 
67
72
  protected branchCode: string = '';
@@ -92,7 +97,7 @@ export class UserContext {
92
97
 
93
98
  protected package: string = '';
94
99
 
95
- protected webhooks: Webhook[] = systemWebHooks
100
+ protected webhooks: Webhook[] = systemWebHooks;
96
101
  protected clientSetting: TenantClientSetting = {
97
102
  auditTrail: false,
98
103
  support: false,
@@ -101,7 +106,7 @@ export class UserContext {
101
106
  };
102
107
 
103
108
  private dbsession: ClientSession;
104
-
109
+
105
110
  protected modifiedRecords: ModifiedRecords = {
106
111
  createds: {},
107
112
  updateds: {},
@@ -113,10 +118,13 @@ export class UserContext {
113
118
  einvoice: boolean;
114
119
  } = { simbiz6: false, einvoice: false };
115
120
 
121
+ protected userType: TUserType = 'normal';
122
+
116
123
  constructor(
117
- private readonly userModel: Model<User>,
124
+ private readonly userModel: Model<User>,
118
125
  private readonly permModel: Model<Permission>,
119
126
  private readonly appModel: Model<Appintegration>,
127
+ private readonly miniAppInstallationModel: Model<Miniappinstallation>,
120
128
  ) {}
121
129
 
122
130
  setDBSession = (dbsession: ClientSession) => {
@@ -206,14 +214,31 @@ export class UserContext {
206
214
  return data;
207
215
  };
208
216
 
209
-
210
- setCurrentUserInfo = async (tokenstr: string, xOrg: string,webhookModel:Model<Webhook>) => {
217
+ getUserToken = () => this.token;
218
+
219
+ getMiniApiToken = () => this.miniApiToken;
220
+
221
+ getMiniApiTokenInfo = () => this.miniApiTokenInfo;
222
+
223
+ setMiniApiToken = (token: string) => {
224
+ this.miniApiToken = token;
225
+ };
226
+
227
+ setMiniApiTokenInfo = (miniApiTokenInfo: TMiniApiTokenInfo) => {
228
+ this.miniApiTokenInfo = miniApiTokenInfo;
229
+ };
230
+
231
+ setCurrentUserInfo = async (tokenstr: string, xOrg: string, webhookModel: Model<Webhook>) => {
211
232
  this.setXOrg(xOrg);
212
- await this.setUserToken(tokenstr);
213
- const wh = await webhookModel.find({branchId:this.getBranchId(),active:true})
233
+ await this.setUserToken(tokenstr);
234
+ this.setUserType('normal');
235
+ const wh = await webhookModel.find({ branchId: this.getBranchId(), active: true });
236
+
237
+ if (Array.isArray(wh) && wh.length > 0) this.webhooks = this.webhooks.concat(wh);
238
+ };
214
239
 
215
- if(Array.isArray(wh) && wh.length>0)
216
- this.webhooks = this.webhooks.concat(wh)
240
+ setPackage = (packageName: string) => {
241
+ this.package = packageName;
217
242
  };
218
243
 
219
244
  /**
@@ -267,7 +292,7 @@ export class UserContext {
267
292
  as: 'currentTenant',
268
293
  },
269
294
  },
270
-
295
+
271
296
  {
272
297
  $unwind: '$currentTenant',
273
298
  },
@@ -327,8 +352,6 @@ export class UserContext {
327
352
  return userProfile;
328
353
  };
329
354
 
330
- getUserToken = () => this.token;
331
-
332
355
  setUserToken = async (tokenStr: string) => {
333
356
  this.logger.debug(`===setUserToken===`);
334
357
  // Define token info
@@ -401,8 +424,8 @@ export class UserContext {
401
424
  orgId: this.orgId,
402
425
  };
403
426
  };
404
- getWebHooks = ()=> this.webhooks
405
-
427
+ getWebHooks = () => this.webhooks;
428
+
406
429
  getWorkflowTaskFilter() {
407
430
  return {
408
431
  'data.tenantId': this.tenantId,
@@ -467,6 +490,28 @@ export class UserContext {
467
490
  }
468
491
  };
469
492
 
493
+ decodeXOrg = (xOrg: string) => {
494
+ try {
495
+ const decodedText: string = Base64URL.decodeText(xOrg);
496
+ const xOrgRealm = decodedText.includes('/') ? decodedText.split('/') : decodedText.split('-');
497
+
498
+ const tenantId = Number(xOrgRealm[0]);
499
+ const orgId = Number(xOrgRealm[1]);
500
+ const branchId = Number(xOrgRealm[2]);
501
+ if (xOrgRealm.length == 3 && !isNaN(tenantId) && !isNaN(orgId) && !isNaN(branchId)) {
502
+ return {
503
+ tenantId,
504
+ orgId,
505
+ branchId,
506
+ };
507
+ } else {
508
+ throw new BadRequestException('invalidXorg');
509
+ }
510
+ } catch (err) {
511
+ throw new BadRequestException(err);
512
+ }
513
+ };
514
+
470
515
  async getUserInfo(): Promise<UserInfo> {
471
516
  this.logger.debug('===getUserInfo===');
472
517
 
@@ -495,6 +540,7 @@ export class UserContext {
495
540
  invites: this.getInvites(),
496
541
  moreProps: this.getMoreProps(),
497
542
  appintegration: this.getAppIntegration(),
543
+ userType: this.getUserType(),
498
544
  };
499
545
 
500
546
  if (this.getId() != '') {
@@ -749,6 +795,96 @@ export class UserContext {
749
795
  this.guestInfo.email = <string>tokeninfo?.email ?? '';
750
796
  this.guestInfo.uname = <string>tokeninfo?.preferred_username ?? '';
751
797
  this.guestInfo.fullname = <string>tokeninfo?.name ?? '';
798
+
799
+ this.setUserType('guest');
800
+ }
801
+
802
+ getUserType = () => this.userType;
803
+
804
+ setUserType = (userType: TUserType) => {
805
+ this.userType = userType;
806
+ };
807
+
808
+ detectMiniAppSdkRequest(req: Request) {
809
+ if (!isEmpty(req.headers['x-mini-app-dev-portal-app-id'])) {
810
+ this.setUserType('miniAppSdk');
811
+ }
812
+ }
813
+
814
+ async setMiniApiUser(tokenStr: string, xOrg: string) {
815
+ const tokenInfo: TMiniApiTokenInfo = jwt.decode(tokenStr) as TMiniApiTokenInfo;
816
+ const appId = tokenInfo?.miniAppId ?? '';
817
+
818
+ this.setXOrg(xOrg);
819
+ this.setUserType('miniApi');
820
+ this.setMiniApiToken(tokenStr);
821
+ this.setMiniApiTokenInfo(tokenInfo);
822
+
823
+ const miniAppInstallation = await this.findIsCentreInstalledMiniApp(appId);
824
+
825
+ if (isEmpty(miniAppInstallation.miniApiUser) || isEmpty(miniAppInstallation.miniApiUser.uid)) {
826
+ throw new ForbiddenException('NOT found connected user');
827
+ }
828
+
829
+ this.token = tokenStr;
830
+ this.uid = miniAppInstallation.miniApiUser.uid;
831
+
832
+ await this.setUserProfileFromDB();
833
+ }
834
+
835
+ async findIsCentreInstalledMiniApp(developerPortalAppId: string) {
836
+ const miniAppInstallation = await this.miniAppInstallationModel.findOne({
837
+ 'miniApp.developerPortalAppId': developerPortalAppId,
838
+ isActive: true,
839
+ tenantId: this.tenantId,
840
+ orgId: this.orgId,
841
+ branchId: this.branchId,
842
+ });
843
+
844
+ if (!miniAppInstallation) {
845
+ throw new ForbiddenException('NOT allowed to access this centre');
846
+ }
847
+
848
+ return miniAppInstallation;
849
+ }
850
+
851
+ async setUserProfileFromDB() {
852
+ const userProfile = await this.obtainProfileFromDB();
853
+ if (userProfile) {
854
+ this.logger.debug(`User ${this.uid} exists in tenant (${this.tenantId})`);
855
+
856
+ this._id = userProfile._id.toString();
857
+ this.email = userProfile.email ?? '';
858
+ this.uname = userProfile.uname ?? '';
859
+ this.fullname = userProfile.fullname ?? '';
860
+
861
+ this.branchCode = userProfile['branchCode'] ?? '';
862
+ this.branchName = userProfile['branchName'] ?? '';
863
+ this.orgCode = userProfile['orgCode'] ?? '';
864
+ this.orgName = userProfile['orgName'] ?? '';
865
+ this.timeZone = userProfile['timeZone'] ?? '';
866
+ this.currency = userProfile['currency'] ?? '';
867
+ this.country = userProfile['country'] ?? '';
868
+ this.offsetMinute = userProfile['offsetMinute'] ?? 0;
869
+ this.orgRecordId = userProfile['orgRecordId'] ?? '';
870
+ this.branchRecordId = userProfile['branchRecordId'] ?? '';
871
+ this.groups = userProfile['groups'] ?? [];
872
+ this.clientSetting = userProfile['clientSetting'] ?? {};
873
+ this.roles = userProfile['roles'] ?? [Role.Everyone, Role.User];
874
+ this.moreProps = this.setMoreProps(userProfile);
875
+ this.package = userProfile['package'];
876
+ this.appintegration = await this.setAppIntegration();
877
+ } else {
878
+ this.logger.debug(`User ${this.uid} not exists in tenant (${this.tenantId})`);
879
+ this.logger.debug(`Set unknown id of current user`);
880
+ this.roles = [Role.Everyone, Role.Unknown];
881
+ }
882
+
883
+ if (this.isRealmAdmin() && !this.roles.includes(Role.SuperAdmin)) {
884
+ this.roles.push(Role.SuperAdmin);
885
+ }
886
+
887
+ this.logger.verbose(`User ${this.uid} have _id (${this.getId()}), groups (${this.groups.join(',')}) and roles (${this.getRoles().join(',')}).`);
752
888
  }
753
889
 
754
890
  getAppIntegration = () => this.appintegration;
@@ -773,6 +909,7 @@ export class UserContext {
773
909
  }
774
910
  return this.appintegration;
775
911
  }
912
+
776
913
  /**
777
914
  * Define additional properties from user into moreProps
778
915
  */
@@ -927,4 +1064,4 @@ type UserInfo = {
927
1064
  type UserTenant = User & {
928
1065
  tenantName: string;
929
1066
  permissions: Permission[];
930
- };
1067
+ };
@@ -6,82 +6,78 @@
6
6
  * Author: Ks Tan
7
7
  * Last Modified By: Yong Xiang
8
8
  */
9
- let orgLogo = ""
9
+ let orgLogo = "";
10
10
 
11
- export const getUserStore = ()=>{
12
- const {$userstore} = useNuxtApp()
13
- return $userstore
14
- }
15
- export const reloadUserStore = async () =>{
16
- const {$userstore} = useNuxtApp()
17
- await $userstore.loadRemoteUserInfo()
18
- }
19
- export const getCurrency = () =>getUserStore()?.currency ?? '$$'
20
- export const getUserProfile = () => getUserStore()?.getUserInfo()
11
+ export const getUserStore = () => {
12
+ const { $userstore } = useNuxtApp();
13
+ return $userstore;
14
+ };
15
+ export const reloadUserStore = async () => {
16
+ const { $userstore } = useNuxtApp();
17
+ await $userstore.loadRemoteUserInfo();
18
+ };
19
+ export const getCurrency = () => getUserStore()?.currency ?? "$$";
20
+ export const getUserProfile = () => getUserStore()?.getUserInfo();
21
21
 
22
-
23
- export const isGuideComplete=(guidename: string):boolean=>{
24
- if(useNuxtApp().$userstore.moreProps.completedTours!==undefined){
25
- return useNuxtApp().$userstore.moreProps.completedTours.includes(guidename)
26
- }
27
- else return false
28
- }
29
- export const setGuideComplete= async(guidename:string)=>{
30
- const userstore =useNuxtApp().$userstore
31
- await getProfileApi().runTourComplete(guidename);
32
- if(getUserProfile()!==undefined){
33
- if(!Array.isArray(getUserProfile()?.moreProps.completedTours))
34
- userstore.moreProps.completedTours=[guidename]
35
- else
36
- userstore.moreProps.completedTours.push(guidename)
37
- }
38
- }
39
- export const getCurrentXorg = () =>{
40
- return (useRoute().params.xorg) ? String(useRoute().params.xorg) : undefined
41
- }
42
- export const getPageBaseUrl = (resourcename:string) =>{
43
- return `/${getCurrentXorg()}/${resourcename}`;
44
- }
22
+ export const isGuideComplete = (guidename: string): boolean => {
23
+ if (useNuxtApp().$userstore.moreProps.completedTours !== undefined) {
24
+ return useNuxtApp().$userstore.moreProps.completedTours.includes(guidename);
25
+ } else return false;
26
+ };
27
+ export const setGuideComplete = async (guidename: string) => {
28
+ const userstore = useNuxtApp().$userstore;
29
+ await getProfileApi().runTourComplete(guidename);
30
+ if (getUserProfile() !== undefined) {
31
+ if (!Array.isArray(getUserProfile()?.moreProps.completedTours))
32
+ userstore.moreProps.completedTours = [guidename];
33
+ else userstore.moreProps.completedTours.push(guidename);
34
+ }
35
+ };
36
+ export const getCurrentXorg = () => {
37
+ return useRoute().params.xorg ? String(useRoute().params.xorg) : undefined;
38
+ };
39
+ export const getPageBaseUrl = (resourcename: string) => {
40
+ return `/${getCurrentXorg()}/${resourcename}`;
41
+ };
45
42
  /**
46
43
  * verify current user can perform specific action base on backend RBAC
47
44
  * @param resource:string upper case first letter document name
48
45
  * @param action:string action name, can be create/update/delete...
49
46
  * @return boolean
50
47
  */
51
- export const canPerform = (resource:string,action:string):boolean =>{
52
-
53
- return getUserStore().canPerform(upperFirst(resource),action)
54
- }
55
- export const haveAccess = (resource:string):boolean =>{
56
- return getUserStore().haveAccess(upperFirst(resource))
57
- }
58
-
59
- export const checkHasHighPrivilege = ():boolean =>{
60
- return getUserStore().checkHasHighPrivilege()
61
- }
62
-
48
+ export const canPerform = (resource: string, action: string): boolean => {
49
+ return getUserStore().canPerform(upperFirst(resource), action);
50
+ };
51
+ export const haveAccess = (resource: string): boolean => {
52
+ return getUserStore().haveAccess(upperFirst(resource));
53
+ };
63
54
 
55
+ export const hasHighPrivilege = (): boolean => {
56
+ return getUserStore().hasHighPrivilege();
57
+ };
64
58
 
65
- export const getProfileEmail = () => getUserProfile()?.email
66
- export const getProfileUid = () => getUserProfile()?.uid
67
- export const getProfileFullName = () => getUserProfile()?.fullName
59
+ export const getProfileEmail = () => getUserProfile()?.email;
60
+ export const getProfileUid = () => getUserProfile()?.uid;
61
+ export const getProfileFullName = () => getUserProfile()?.fullName;
68
62
 
69
63
  export const refreshOrgLogo = async () => {
70
- const logodata = await useNuxtApp().$OrganizationDoc().getApi().runGetlogo()
71
- orgLogo = logodata.data
72
- }
73
- export const getOrgLogo = ()=> orgLogo
74
- export const setOrgLogo = (str:string) => orgLogo = str
75
- export const getCurrentBranch = ()=>{
76
- const branchId= getUserStore().branchId
77
- const branchinfo = getUserStore().branches.find(item=>item.branch.branchId==branchId)
78
- return branchinfo
79
- }
64
+ const logodata = await useNuxtApp().$OrganizationDoc().getApi().runGetlogo();
65
+ orgLogo = logodata.data;
66
+ };
67
+ export const getOrgLogo = () => orgLogo;
68
+ export const setOrgLogo = (str: string) => (orgLogo = str);
69
+ export const getCurrentBranch = () => {
70
+ const branchId = getUserStore().branchId;
71
+ const branchinfo = getUserStore().branches.find(
72
+ (item) => item.branch.branchId == branchId,
73
+ );
74
+ return branchinfo;
75
+ };
80
76
 
81
- export const getMySimpleAppUserPicker=()=>{
82
- return {
83
- _id: getUserProfile()?._id,
84
- uid: getUserProfile()?.uid,
85
- fullName: getUserProfile()?.fullName
86
- }
87
- }
77
+ export const getMySimpleAppUserPicker = () => {
78
+ return {
79
+ _id: getUserProfile()?._id,
80
+ uid: getUserProfile()?.uid,
81
+ fullName: getUserProfile()?.fullName,
82
+ };
83
+ };