@simitgroup/simpleapp-generator 1.0.24 → 1.0.25
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/dist/framework.js +20 -12
- package/dist/framework.js.map +1 -1
- package/package.json +1 -1
- package/src/framework.ts +21 -14
- package/templates/basic/model.eta +2 -1
- package/templates/nest/TenantMiddleware.eta +28 -19
- package/templates/nest/User.eta +106 -71
- package/templates/nest/app.module.eta +10 -1
- package/templates/nest/nest.env.eta +12 -1
- package/templates/nest/nest.main.eta +13 -4
- package/templates/nest/oauth2-redirect.eta +79 -0
- package/templates/nuxt/components.crudsimple.vue.eta +1 -2
- package/templates/nuxt/composables.getautocomplete.ts.eta +12 -7
- package/templates/nuxt/composables.getmenus.ts.eta +21 -10
- package/templates/nuxt/env.eta +11 -1
- package/templates/nuxt/nuxt.config.ts.eta +8 -7
- package/templates/nuxt/pages.[xorg].index.vue.eta +19 -0
- package/templates/nuxt/pages.index.vue.eta +9 -1
- package/templates/nuxt/pages.login.vue.eta +20 -0
- package/templates/nuxt/plugins.simpleapp.ts.eta +2 -3
- package/templates/nuxt/server.api.auth.logout.ts.eta +12 -0
- package/templates/nuxt/server.api.auth[...].ts.eta +144 -0
- package/templates/nuxt/server.api.ts.eta +19 -14
package/dist/framework.js
CHANGED
|
@@ -41,6 +41,12 @@ let config = {
|
|
|
41
41
|
"frontendFolder": "./myfrontend",
|
|
42
42
|
"frontendPort": "8080",
|
|
43
43
|
"openapi3Yaml": "../openapi.yaml",
|
|
44
|
+
"keycloaksetting": {
|
|
45
|
+
"OAUTH2_CONFIGURL": "https://keycloak-server-url/realms/realm-name",
|
|
46
|
+
"OAUTH2_CLIENTID": "client-id",
|
|
47
|
+
"OAUTH2_CLIENTSECRET": "client-secret-value",
|
|
48
|
+
"AUTH_SECRET_KEY": "my-secret",
|
|
49
|
+
}
|
|
44
50
|
};
|
|
45
51
|
const setConfiguration = (paraconfig) => {
|
|
46
52
|
config = paraconfig;
|
|
@@ -81,18 +87,18 @@ const prepareNest = (callback) => {
|
|
|
81
87
|
const targetfolder = config.backendFolder;
|
|
82
88
|
log.info(`creating backend project ${targetfolder}`);
|
|
83
89
|
if (!fs_1.default.existsSync(`${targetfolder}/.env`)) {
|
|
84
|
-
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install --save axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config`, async (error, stdout, stderr) => {
|
|
90
|
+
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install --save @nestjs/serve-static axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config`, async (error, stdout, stderr) => {
|
|
85
91
|
// log.info(`dependency installed`)
|
|
86
92
|
if (!error) {
|
|
93
|
+
fs_1.default.mkdirSync(`${targetfolder}/public_html`, { recursive: true });
|
|
87
94
|
const eta = new eta_1.Eta({ views: constants.templatedir });
|
|
88
|
-
const variables =
|
|
89
|
-
backendPort: config.backendPort,
|
|
90
|
-
mongoConnectStr: config.mongoConnectStr
|
|
91
|
-
};
|
|
95
|
+
const variables = config;
|
|
92
96
|
const txtEnv = eta.render('./nest/nest.env.eta', variables);
|
|
93
97
|
const txtMain = eta.render('./nest/nest.main.eta', variables);
|
|
98
|
+
const txtRedirectHtml = eta.render('./nest/oauth2-redirect.eta', variables);
|
|
94
99
|
fs_1.default.writeFileSync(`${targetfolder}/.env`, txtEnv);
|
|
95
100
|
fs_1.default.writeFileSync(`${targetfolder}/src/main.ts`, txtMain);
|
|
101
|
+
fs_1.default.writeFileSync(`${targetfolder}/public_html/oauth2-redirect.html`, txtRedirectHtml);
|
|
96
102
|
const tsconfigpath = process.cwd() + '/' + `${targetfolder}/tsconfig.json`;
|
|
97
103
|
const tsconfig = require(tsconfigpath);
|
|
98
104
|
tsconfig.compilerOptions.esModuleInterop = true;
|
|
@@ -118,22 +124,20 @@ const prepareNuxt = (callback) => {
|
|
|
118
124
|
const targetfolder = config.frontendFolder;
|
|
119
125
|
if (!fs_1.default.existsSync(`${targetfolder}/.env`)) {
|
|
120
126
|
//asume no environment. prepare now
|
|
121
|
-
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install;pnpm install -D @nuxt/ui @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core nuxt-security prettier `, (error, stdout, stderr) => {
|
|
127
|
+
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install;pnpm install -D @sidebase/nuxt-auth @nuxt/ui @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core nuxt-security prettier `, (error, stdout, stderr) => {
|
|
122
128
|
//;pnpm install
|
|
123
129
|
console.log(error, stdout, stderr);
|
|
124
|
-
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install --save
|
|
130
|
+
(0, child_process_1.exec)(`cd ${targetfolder};pnpm install --save next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv dotenv @fullcalendar/core @fullcalendar/vue3 quill uuid ajv-formats primeflex primeicons prettier primevue axios json-schema mitt @simitgroup/simpleapp-vue-component@latest`, (error, stdout, stderr) => {
|
|
125
131
|
console.log(error, stdout, stderr);
|
|
126
132
|
fs_1.default.mkdirSync(`${targetfolder}/assets/css/`, { recursive: true });
|
|
127
133
|
fs_1.default.mkdirSync(`${targetfolder}/layouts`, { recursive: true });
|
|
128
134
|
fs_1.default.mkdirSync(`${targetfolder}/components`, { recursive: true });
|
|
129
135
|
fs_1.default.mkdirSync(`${targetfolder}/server/api/[xorg]`, { recursive: true });
|
|
130
|
-
fs_1.default.mkdirSync(`${targetfolder}/
|
|
136
|
+
fs_1.default.mkdirSync(`${targetfolder}/server/api/auth`, { recursive: true });
|
|
137
|
+
fs_1.default.mkdirSync(`${targetfolder}/pages/[xorg]`, { recursive: true });
|
|
131
138
|
fs_1.default.mkdirSync(`${targetfolder}/plugins`, { recursive: true });
|
|
132
139
|
const eta = new eta_1.Eta({ views: `${constants.templatedir}/nuxt` });
|
|
133
|
-
const variables =
|
|
134
|
-
backendPort: config.backendPort,
|
|
135
|
-
frontendPort: config.frontendPort
|
|
136
|
-
};
|
|
140
|
+
const variables = config;
|
|
137
141
|
const writes = {
|
|
138
142
|
'./app.vue.eta': 'app.vue',
|
|
139
143
|
'./components.eventmonitor.vue.eta': 'components/EventMonitor.vue',
|
|
@@ -142,8 +146,12 @@ const prepareNuxt = (callback) => {
|
|
|
142
146
|
'./components.debugdocdata.vue.eta': 'components/DebugDocumentData.vue',
|
|
143
147
|
'./layouts.default.vue.eta': 'layouts/default.vue',
|
|
144
148
|
'./server.api.ts.eta': 'server/api/[xorg]/[...].ts',
|
|
149
|
+
'./server.api.auth.logout.ts.eta': 'server/api/auth/logout.ts',
|
|
150
|
+
'./server.api.auth[...].ts.eta': 'server/api/auth/[...].ts',
|
|
145
151
|
'./nuxt.config.ts.eta': 'nuxt.config.ts',
|
|
146
152
|
'./pages.index.vue.eta': 'pages/index.vue',
|
|
153
|
+
'./pages.[xorg].index.vue.eta': 'pages/[xorg]/index.vue',
|
|
154
|
+
'./pages.login.vue.eta': 'pages/login.vue',
|
|
147
155
|
'./plugins.simpleapp.ts.eta': 'plugins/simpleapp.ts',
|
|
148
156
|
'./tailwind.config.ts.eta': 'tailwind.config.ts',
|
|
149
157
|
'./tailwind.css.eta': 'assets/css/tailwind.css',
|
package/dist/framework.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../src/framework.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4CAAmB;AACnB,iDAAwC;AACxC,iCAAwC;AACxC,sDAAuC;AACvC,6BAA0B;AAC1B,MAAM,GAAG,GAAoB,IAAI,cAAM,EAAE,CAAC;AAE1C,IAAI,MAAM,GAAG;IACT,mBAAmB,EAAC,eAAe;IACnC,eAAe,EAAC,aAAa;IAC7B,aAAa,EAAC,MAAM;IACpB,iBAAiB,EAAC,kEAAkE;IACpF,gBAAgB,EAAC,cAAc;IAC/B,cAAc,EAAC,MAAM;IACrB,cAAc,EAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../src/framework.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/framework.ts
CHANGED
|
@@ -13,6 +13,12 @@ let config = {
|
|
|
13
13
|
"frontendFolder":"./myfrontend",
|
|
14
14
|
"frontendPort":"8080",
|
|
15
15
|
"openapi3Yaml":"../openapi.yaml",
|
|
16
|
+
"keycloaksetting":{
|
|
17
|
+
"OAUTH2_CONFIGURL":"https://keycloak-server-url/realms/realm-name",
|
|
18
|
+
"OAUTH2_CLIENTID":"client-id",
|
|
19
|
+
"OAUTH2_CLIENTSECRET":"client-secret-value",
|
|
20
|
+
"AUTH_SECRET_KEY":"my-secret",
|
|
21
|
+
}
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
export const setConfiguration=(paraconfig)=>{
|
|
@@ -53,20 +59,19 @@ export const prepareNest = (callback:Function)=>{
|
|
|
53
59
|
if(!fs.existsSync(`${targetfolder}/.env`)){
|
|
54
60
|
|
|
55
61
|
|
|
56
|
-
exec(`cd ${targetfolder};pnpm install --save axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config`,async (error, stdout, stderr)=>{
|
|
62
|
+
exec(`cd ${targetfolder};pnpm install --save @nestjs/serve-static axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config`,async (error, stdout, stderr)=>{
|
|
57
63
|
// log.info(`dependency installed`)
|
|
58
64
|
if(!error){
|
|
59
|
-
|
|
65
|
+
fs.mkdirSync(`${targetfolder}/public_html`,{recursive:true})
|
|
60
66
|
const eta = new Eta({views: constants.templatedir});
|
|
61
|
-
const variables=
|
|
62
|
-
backendPort:config.backendPort,
|
|
63
|
-
mongoConnectStr:config.mongoConnectStr
|
|
64
|
-
}
|
|
67
|
+
const variables=config
|
|
65
68
|
const txtEnv = eta.render('./nest/nest.env.eta', variables);
|
|
66
69
|
const txtMain = eta.render('./nest/nest.main.eta', variables);
|
|
70
|
+
const txtRedirectHtml = eta.render('./nest/oauth2-redirect.eta', variables);
|
|
67
71
|
|
|
68
72
|
fs.writeFileSync(`${targetfolder}/.env`, txtEnv);
|
|
69
73
|
fs.writeFileSync(`${targetfolder}/src/main.ts`, txtMain);
|
|
74
|
+
fs.writeFileSync(`${targetfolder}/public_html/oauth2-redirect.html`, txtRedirectHtml);
|
|
70
75
|
const tsconfigpath = process.cwd()+'/'+`${targetfolder}/tsconfig.json`
|
|
71
76
|
const tsconfig = require(tsconfigpath)
|
|
72
77
|
tsconfig.compilerOptions.esModuleInterop=true
|
|
@@ -91,23 +96,21 @@ export const prepareNuxt = (callback:Function)=>{
|
|
|
91
96
|
const targetfolder = config.frontendFolder
|
|
92
97
|
if(!fs.existsSync(`${targetfolder}/.env`)){
|
|
93
98
|
//asume no environment. prepare now
|
|
94
|
-
exec(`cd ${targetfolder};pnpm install;pnpm install -D @nuxt/ui @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core nuxt-security prettier `, (error, stdout, stderr)=>{
|
|
99
|
+
exec(`cd ${targetfolder};pnpm install;pnpm install -D @sidebase/nuxt-auth @nuxt/ui @types/node @vueuse/nuxt @sidebase/nuxt-auth @vueuse/core nuxt-security prettier `, (error, stdout, stderr)=>{
|
|
95
100
|
//;pnpm install
|
|
96
101
|
console.log(error, stdout, stderr)
|
|
97
|
-
exec(`cd ${targetfolder};pnpm install --save
|
|
102
|
+
exec(`cd ${targetfolder};pnpm install --save next-auth@4.21.1 @darkwolf/base64url @nuxt/ui ajv dotenv @fullcalendar/core @fullcalendar/vue3 quill uuid ajv-formats primeflex primeicons prettier primevue axios json-schema mitt @simitgroup/simpleapp-vue-component@latest`, (error, stdout, stderr)=>{
|
|
98
103
|
console.log(error, stdout, stderr)
|
|
99
104
|
|
|
100
105
|
fs.mkdirSync(`${targetfolder}/assets/css/`,{recursive:true})
|
|
101
106
|
fs.mkdirSync(`${targetfolder}/layouts`,{recursive:true})
|
|
102
107
|
fs.mkdirSync(`${targetfolder}/components`,{recursive:true})
|
|
103
108
|
fs.mkdirSync(`${targetfolder}/server/api/[xorg]`,{recursive:true})
|
|
104
|
-
fs.mkdirSync(`${targetfolder}/
|
|
109
|
+
fs.mkdirSync(`${targetfolder}/server/api/auth`,{recursive:true})
|
|
110
|
+
fs.mkdirSync(`${targetfolder}/pages/[xorg]`,{recursive:true})
|
|
105
111
|
fs.mkdirSync(`${targetfolder}/plugins`,{recursive:true})
|
|
106
112
|
const eta = new Eta({views: `${constants.templatedir}/nuxt`});
|
|
107
|
-
const variables=
|
|
108
|
-
backendPort:config.backendPort,
|
|
109
|
-
frontendPort:config.frontendPort
|
|
110
|
-
}
|
|
113
|
+
const variables=config
|
|
111
114
|
const writes = {
|
|
112
115
|
'./app.vue.eta':'app.vue',
|
|
113
116
|
'./components.eventmonitor.vue.eta':'components/EventMonitor.vue',
|
|
@@ -116,11 +119,15 @@ export const prepareNuxt = (callback:Function)=>{
|
|
|
116
119
|
'./components.debugdocdata.vue.eta':'components/DebugDocumentData.vue',
|
|
117
120
|
'./layouts.default.vue.eta':'layouts/default.vue',
|
|
118
121
|
'./server.api.ts.eta':'server/api/[xorg]/[...].ts',
|
|
122
|
+
'./server.api.auth.logout.ts.eta':'server/api/auth/logout.ts',
|
|
123
|
+
'./server.api.auth[...].ts.eta':'server/api/auth/[...].ts',
|
|
119
124
|
'./nuxt.config.ts.eta':'nuxt.config.ts',
|
|
120
125
|
'./pages.index.vue.eta':'pages/index.vue',
|
|
126
|
+
'./pages.[xorg].index.vue.eta':'pages/[xorg]/index.vue',
|
|
127
|
+
'./pages.login.vue.eta':'pages/login.vue',
|
|
121
128
|
'./plugins.simpleapp.ts.eta':'plugins/simpleapp.ts',
|
|
122
129
|
'./tailwind.config.ts.eta':'tailwind.config.ts',
|
|
123
|
-
'./tailwind.css.eta':'assets/css/tailwind.css',
|
|
130
|
+
'./tailwind.css.eta':'assets/css/tailwind.css',
|
|
124
131
|
'./env.eta':'.env',
|
|
125
132
|
}
|
|
126
133
|
|
|
@@ -23,9 +23,10 @@ const schemasetting = {
|
|
|
23
23
|
<% }else if( schema[key].type == 'array'){%>
|
|
24
24
|
<%= key %>: [{type: <%= schema[key].item.type %>, required:false}] //basic array
|
|
25
25
|
<% }else{%>
|
|
26
|
-
<%= key %>: {type: <%= capitalizeFirstLetter(schema[key].type) %>, required:false}, //field
|
|
26
|
+
<%= key %>: {type: <%= capitalizeFirstLetter(schema[key].type) %>, required: <% if(key==it.autocompletecode || key==it.autocompletename){%>true<%}else{%>false<%}%>}, //field
|
|
27
27
|
<% } %>
|
|
28
28
|
<%}) %>
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export const <%= it.doctype %>MongoSchema = new Schema(schemasetting,{collection: '<%= it.name %>'})
|
|
32
|
+
.index({<%=it.autocompletecode%>:1,orgId:1},{unique:true});
|
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
import { Injectable, NestMiddleware,Scope } from '@nestjs/common';
|
|
1
|
+
import { Injectable, NestMiddleware, Scope } from '@nestjs/common';
|
|
3
2
|
import { Request, Response, NextFunction } from 'express';
|
|
4
|
-
import
|
|
3
|
+
// import * as jwt from 'nestjs-jwt'
|
|
4
|
+
|
|
5
5
|
|
|
6
|
+
import { User } from './User';
|
|
7
|
+
// import {KeycloakConfigService} from "../keycloak/keycloak.service"
|
|
6
8
|
@Injectable({
|
|
7
|
-
|
|
9
|
+
scope: Scope.REQUEST,
|
|
8
10
|
})
|
|
11
|
+
|
|
9
12
|
export class TenantMiddleware implements NestMiddleware {
|
|
10
13
|
use(req: Request, res: Response, next: NextFunction) {
|
|
11
|
-
req.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
}else{
|
|
25
|
-
return res.status(401).send("undefine header string x-org")
|
|
14
|
+
if (req.baseUrl == '/oauth2-redirect.html') {
|
|
15
|
+
next();
|
|
16
|
+
return ;
|
|
17
|
+
}
|
|
18
|
+
if(!req.headers['authorization']){
|
|
19
|
+
return res.status(401).send('Undefine bearer token');
|
|
20
|
+
}
|
|
21
|
+
if (!req.headers['x-org']){
|
|
22
|
+
return res.status(401).send('undefine header string x-org');
|
|
23
|
+
}
|
|
24
|
+
const u = User.getInstance();
|
|
26
25
|
|
|
26
|
+
try {
|
|
27
|
+
u.setXorg(req.headers['x-org'].toString());
|
|
28
|
+
let tokenstr:string = req.headers['authorization']
|
|
29
|
+
tokenstr = tokenstr.replace("Bearer ",'')
|
|
30
|
+
u.setUserToken(tokenstr);
|
|
31
|
+
next();
|
|
32
|
+
} catch {
|
|
33
|
+
return res.status(401).send('Invalid x-org or user info');
|
|
27
34
|
}
|
|
35
|
+
|
|
36
|
+
|
|
28
37
|
|
|
29
38
|
}
|
|
30
39
|
}
|
package/templates/nest/User.eta
CHANGED
|
@@ -1,80 +1,115 @@
|
|
|
1
1
|
import { Injectable, Scope } from '@nestjs/common';
|
|
2
|
-
import Base64URL from '@darkwolf/base64url'
|
|
2
|
+
import Base64URL from '@darkwolf/base64url';
|
|
3
|
+
import * as jwt from 'jsonwebtoken'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
@Injectable({
|
|
5
|
-
|
|
10
|
+
scope: Scope.REQUEST,
|
|
6
11
|
})
|
|
7
12
|
export class User {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
User.getInstance().uid=uid
|
|
25
|
-
}
|
|
26
|
-
getInfo=()=>{
|
|
27
|
-
return User.getInstance()
|
|
28
|
-
}
|
|
29
|
-
getBranchFilter=()=>{
|
|
30
|
-
return {
|
|
31
|
-
tenantId:User.getInstance().tenantId,
|
|
32
|
-
orgId: User.getInstance().orgId,
|
|
33
|
-
branchId:User.getInstance().branchId
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
getTenantFilter=()=>{
|
|
37
|
-
return {tenantId:User.getInstance().tenantId}
|
|
38
|
-
}
|
|
39
|
-
getOrgFilter=()=>{
|
|
40
|
-
return {tenantId:User.getInstance().tenantId,orgId: User.getInstance().orgId}
|
|
13
|
+
private static instance: User;
|
|
14
|
+
protected uid: string = '';
|
|
15
|
+
protected uname: string = '';
|
|
16
|
+
protected email: string = '';
|
|
17
|
+
protected fullname:string=''
|
|
18
|
+
protected xOrg: string = '';
|
|
19
|
+
protected tenantId: number = 0;
|
|
20
|
+
protected orgId: number = 0;
|
|
21
|
+
protected branchId: number = 0;
|
|
22
|
+
protected accessrights:any = {}
|
|
23
|
+
protected token:string = ''
|
|
24
|
+
protected refreshtoken:string = ''
|
|
25
|
+
constructor() {}
|
|
26
|
+
public static getInstance(): User {
|
|
27
|
+
if (!User.instance) {
|
|
28
|
+
User.instance = new User();
|
|
41
29
|
}
|
|
30
|
+
return User.instance;
|
|
31
|
+
}
|
|
32
|
+
setUserToken = (tokenstr: string) => {
|
|
33
|
+
const tokeninfo = jwt.decode(tokenstr)
|
|
34
|
+
// realm_access: {
|
|
35
|
+
// roles: [
|
|
36
|
+
// 'default-roles-simitdeveloper',
|
|
37
|
+
// 'offline_access',
|
|
38
|
+
// 'uma_authorization'
|
|
39
|
+
// ]
|
|
40
|
+
// },
|
|
41
|
+
// resource_access: { account: { roles: [Array] } },
|
|
42
|
+
// scope: 'openid email profile',
|
|
43
|
+
// sid: '53192f53-d4af-413b-b8d7-1e186419fe53',
|
|
44
|
+
// email_verified: false,
|
|
45
|
+
// name: 'kstan kstan',
|
|
46
|
+
// preferred_username: 'kstan',
|
|
47
|
+
// given_name: 'kstan',
|
|
48
|
+
// family_name: 'kstan',
|
|
49
|
+
// email: 'kstan@simitgroup.com'
|
|
50
|
+
|
|
51
|
+
const u = User.getInstance()
|
|
52
|
+
u.token = tokenstr
|
|
53
|
+
u.uid = tokeninfo.sid;
|
|
54
|
+
u.email = tokeninfo.email
|
|
55
|
+
u.uname = tokeninfo.preferred_username
|
|
56
|
+
u.fullname = tokeninfo.name
|
|
57
|
+
u.accessrights = tokeninfo.resource_access
|
|
58
|
+
};
|
|
59
|
+
getInfo = () => {
|
|
60
|
+
return User.getInstance();
|
|
61
|
+
};
|
|
62
|
+
getBranchFilter = () => {
|
|
63
|
+
return {
|
|
64
|
+
tenantId: User.getInstance().tenantId,
|
|
65
|
+
orgId: User.getInstance().orgId,
|
|
66
|
+
branchId: User.getInstance().branchId,
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
getTenantFilter = () => {
|
|
70
|
+
return { tenantId: User.getInstance().tenantId };
|
|
71
|
+
};
|
|
72
|
+
getOrgFilter = () => {
|
|
73
|
+
return {
|
|
74
|
+
tenantId: User.getInstance().tenantId,
|
|
75
|
+
orgId: User.getInstance().orgId,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
42
78
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
+
getCreateFilter = () => {
|
|
80
|
+
const u = User.getInstance();
|
|
81
|
+
return {
|
|
82
|
+
tenantId: u.tenantId,
|
|
83
|
+
orgId: u.orgId,
|
|
84
|
+
branchId: u.branchId,
|
|
85
|
+
createdby: u.uid,
|
|
86
|
+
updatedby: u.uid,
|
|
87
|
+
created: new Date().getTime().toString(),
|
|
88
|
+
updated: new Date().getTime().toString(),
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
getUpdateFilter = () => {
|
|
92
|
+
const u = User.getInstance();
|
|
93
|
+
return {
|
|
94
|
+
updatedby: u.uid,
|
|
95
|
+
updated: new Date().getTime().toString(),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
setXorg = (xorg) => {
|
|
99
|
+
try {
|
|
100
|
+
const decodedText: string = Base64URL.decodeText(xorg);
|
|
101
|
+
const arrXorg = decodedText.split('-');
|
|
102
|
+
|
|
103
|
+
if (arrXorg.length == 3) {
|
|
104
|
+
const u = User.getInstance();
|
|
105
|
+
u.tenantId = Number(arrXorg[0]);
|
|
106
|
+
u.orgId = Number(arrXorg[1]);
|
|
107
|
+
u.branchId = Number(arrXorg[2]);
|
|
108
|
+
} else {
|
|
109
|
+
throw 'invalid x-org';
|
|
110
|
+
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
throw err;
|
|
79
113
|
}
|
|
114
|
+
};
|
|
80
115
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Module,MiddlewareConsumer,NestModule } from '@nestjs/common';
|
|
2
2
|
import { MongooseModule } from '@nestjs/mongoose';
|
|
3
3
|
import { ConfigModule } from '@nestjs/config';
|
|
4
|
+
import { ServeStaticModule } from '@nestjs/serve-static';
|
|
5
|
+
import { join } from 'path';
|
|
4
6
|
import {TenantMiddleware} from './class/TenantMiddleware'
|
|
5
7
|
<% for(let i=0;i<it.length; i++){ %>
|
|
6
8
|
import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].doctype %>.module'
|
|
@@ -8,7 +10,14 @@ import {<%= it[i].docname %>Module} from './docs/<%= it[i].doctype %>/<%= it[i].
|
|
|
8
10
|
|
|
9
11
|
@Module({
|
|
10
12
|
//define environment variables: MONGODB_URL='mongodb://<user>:<pass>@<host>:<port>/<db>?authMechanism=DEFAULT'
|
|
11
|
-
imports: [
|
|
13
|
+
imports: [
|
|
14
|
+
ConfigModule.forRoot(),
|
|
15
|
+
MongooseModule.forRoot(process.env.MONGODB_URL),
|
|
16
|
+
ServeStaticModule.forRoot({
|
|
17
|
+
rootPath: join(__dirname, '..', 'public_html'),
|
|
18
|
+
exclude: ['/api/(.*)'],
|
|
19
|
+
}),
|
|
20
|
+
<% for(let i=0;i<it.length; i++){ %><%= it[i].docname %>Module,<%}%>],
|
|
12
21
|
controllers: [],
|
|
13
22
|
providers: [],
|
|
14
23
|
})
|
|
@@ -4,4 +4,15 @@ HTTP_PORT=<%=it.backendPort%>
|
|
|
4
4
|
|
|
5
5
|
PROJECT_NAME=SimpleApp Demo1
|
|
6
6
|
PROJECT_DESCRIPTION=Try CRUD
|
|
7
|
-
PROJECT_Version=1.0.0
|
|
7
|
+
PROJECT_Version=1.0.0
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
OAUTH2_CONFIGURL=<%=it.keycloaksetting.OAUTH2_CONFIGURL%>
|
|
11
|
+
|
|
12
|
+
OAUTH2_CLIENTID=<%=it.keycloaksetting.OAUTH2_CLIENTID%>
|
|
13
|
+
|
|
14
|
+
OAUTH2_CLIENTSECRET=<%=it.keycloaksetting.OAUTH2_CLIENTSECRET%>
|
|
15
|
+
|
|
16
|
+
AUTH_SECRET_KEY=<%=it.keycloaksetting.AUTH_SECRET_KEY%>
|
|
17
|
+
|
|
18
|
+
AUTH_ORIGIN=http://localhost:8080
|
|
@@ -9,14 +9,23 @@ async function bootstrap() {
|
|
|
9
9
|
.setTitle(process.env.PROJECT_NAME)
|
|
10
10
|
.setDescription(process.env.PROJECT_DESCRIPTION)
|
|
11
11
|
.setVersion(process.env.PROJECT_VERSION)
|
|
12
|
-
.addApiKey({
|
|
12
|
+
.addApiKey({
|
|
13
|
+
in: 'header',name: 'x-org',type: 'apiKey',description: 'base 64 url encode. example: MS0xLTE',
|
|
14
|
+
},'x-org',)
|
|
15
|
+
.addOAuth2({
|
|
16
|
+
name:'oauth2',in:'header',type:'oauth2',flows:{
|
|
17
|
+
implicit:{
|
|
18
|
+
authorizationUrl: `${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/auth`,
|
|
19
|
+
scopes:[],
|
|
20
|
+
}}},'oauth2')
|
|
13
21
|
.addSecurityRequirements('x-org')
|
|
22
|
+
.addSecurityRequirements('oauth2')
|
|
14
23
|
.build();
|
|
15
24
|
const document = SwaggerModule.createDocument(app, config);
|
|
16
25
|
SwaggerModule.setup('api', app, document, {
|
|
17
|
-
swaggerOptions: { showExtensions: true },
|
|
26
|
+
swaggerOptions: { showExtensions: true, persistAuthorization: true },
|
|
18
27
|
});
|
|
19
28
|
|
|
20
|
-
await app.listen(process.env.HTTP_PORT ??
|
|
29
|
+
await app.listen(process.env.HTTP_PORT ?? 8000); //listen which port
|
|
21
30
|
}
|
|
22
|
-
bootstrap();
|
|
31
|
+
bootstrap();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
4
|
+
<title>Swagger UI: OAuth2 Redirect</title>
|
|
5
|
+
</head>
|
|
6
|
+
<body>
|
|
7
|
+
<script>
|
|
8
|
+
'use strict';
|
|
9
|
+
function run () {
|
|
10
|
+
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
|
11
|
+
var sentState = oauth2.state;
|
|
12
|
+
var redirectUrl = oauth2.redirectUrl;
|
|
13
|
+
var isValid, qp, arr;
|
|
14
|
+
|
|
15
|
+
if (/code|token|error/.test(window.location.hash)) {
|
|
16
|
+
qp = window.location.hash.substring(1).replace('?', '&');
|
|
17
|
+
} else {
|
|
18
|
+
qp = location.search.substring(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
arr = qp.split("&");
|
|
22
|
+
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
|
23
|
+
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
|
24
|
+
function (key, value) {
|
|
25
|
+
return key === "" ? value : decodeURIComponent(value);
|
|
26
|
+
}
|
|
27
|
+
) : {};
|
|
28
|
+
|
|
29
|
+
isValid = qp.state === sentState;
|
|
30
|
+
|
|
31
|
+
if ((
|
|
32
|
+
oauth2.auth.schema.get("flow") === "accessCode" ||
|
|
33
|
+
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
|
34
|
+
oauth2.auth.schema.get("flow") === "authorization_code"
|
|
35
|
+
) && !oauth2.auth.code) {
|
|
36
|
+
if (!isValid) {
|
|
37
|
+
oauth2.errCb({
|
|
38
|
+
authId: oauth2.auth.name,
|
|
39
|
+
source: "auth",
|
|
40
|
+
level: "warning",
|
|
41
|
+
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (qp.code) {
|
|
46
|
+
delete oauth2.state;
|
|
47
|
+
oauth2.auth.code = qp.code;
|
|
48
|
+
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
|
49
|
+
} else {
|
|
50
|
+
let oauthErrorMsg;
|
|
51
|
+
if (qp.error) {
|
|
52
|
+
oauthErrorMsg = "["+qp.error+"]: " +
|
|
53
|
+
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
|
54
|
+
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
oauth2.errCb({
|
|
58
|
+
authId: oauth2.auth.name,
|
|
59
|
+
source: "auth",
|
|
60
|
+
level: "error",
|
|
61
|
+
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
|
66
|
+
}
|
|
67
|
+
window.close();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (document.readyState !== 'loading') {
|
|
71
|
+
run();
|
|
72
|
+
} else {
|
|
73
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
74
|
+
run();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
@@ -47,7 +47,6 @@ const newData = () => {
|
|
|
47
47
|
|
|
48
48
|
const triggerEdit = (event: any) => {
|
|
49
49
|
let id = event.data._id.toString()
|
|
50
|
-
editRecord(event.data._id);
|
|
51
50
|
router.push({ path: `${props.path}/${id}` })
|
|
52
51
|
};
|
|
53
52
|
const editRecord = (id:string) => {
|
|
@@ -95,7 +94,7 @@ refresh();
|
|
|
95
94
|
<button class="bg-primary" @click="newData" v-tooltip="'Add new(ctrl+i)'" >New</button>
|
|
96
95
|
<SimpleAppDatatable
|
|
97
96
|
@row-dblclick="triggerEdit"
|
|
98
|
-
v-model="recordlist"
|
|
97
|
+
v-model="recordlist"
|
|
99
98
|
:setting="{}"
|
|
100
99
|
:columns="listColumns"
|
|
101
100
|
>
|
|
@@ -6,18 +6,23 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as o from "../simpleapp/openapi";
|
|
9
|
-
|
|
9
|
+
import axios from 'axios'
|
|
10
10
|
const getAutoComplete = (apiname: string): any => {
|
|
11
|
+
const { csrf } = useCsrf()
|
|
12
|
+
axios.defaults.headers.common = {"CSRF-TOKEN": csrf};
|
|
13
|
+
const route = useRoute();
|
|
14
|
+
|
|
11
15
|
const config: o.Configuration = {
|
|
12
|
-
basePath: useRuntimeConfig().public.APP_URL
|
|
16
|
+
basePath: `${useRuntimeConfig().public.APP_URL}/api/${route.params.xorg}`,
|
|
13
17
|
isJsonMime: () => true,
|
|
14
18
|
};
|
|
15
19
|
const docsOpenapi: any = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
'category' : new o.CATApi(config),
|
|
21
|
+
'leadtype' : new o.LEADTApi(config),
|
|
22
|
+
'level' : new o.LVLApi(config),
|
|
23
|
+
'product' : new o.PRDApi(config),
|
|
24
|
+
'studentgroup' : new o.STGApi(config),
|
|
25
|
+
};
|
|
21
26
|
if (!docsOpenapi[apiname]) {
|
|
22
27
|
console.error(
|
|
23
28
|
`api for '${apiname}' does not exists, most probably define wrong x-foreignkey`,
|
|
@@ -4,13 +4,24 @@
|
|
|
4
4
|
* last change 2023-09-10
|
|
5
5
|
* author: Ks Tan
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
export const getMenus =(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
|
|
8
|
+
export const getMenus =()=>{
|
|
9
|
+
|
|
10
|
+
const route = useRoute();
|
|
11
|
+
const xorg = route.params.xorg
|
|
12
|
+
let data =[];
|
|
13
|
+
if(xorg){
|
|
14
|
+
data =[
|
|
15
|
+
{label: 'Home',icon: 'pi pi-fw pi-home', url:'/'},
|
|
16
|
+
{label: 'Cruds',icon: 'pi pi-fw pi-pencil',items:[
|
|
17
|
+
<% for(let i=0;i<it.length; i++){ %>
|
|
18
|
+
<% let obj = it[i]%>
|
|
19
|
+
{label: '<%=obj.docname.toLowerCase()%>', to:`/${xorg}/<%=obj.docname.toLowerCase()%>`},
|
|
20
|
+
<%}%>
|
|
21
|
+
]},
|
|
22
|
+
]
|
|
23
|
+
}else{
|
|
24
|
+
data= [{label: 'Home',icon: 'pi pi-fw pi-home', url:'/'},]
|
|
25
|
+
}
|
|
26
|
+
return data
|
|
27
|
+
}
|
package/templates/nuxt/env.eta
CHANGED
|
@@ -4,4 +4,14 @@ SIMPLEAPP_BACKEND_URL=http://localhost:<%=it.backendPort%>
|
|
|
4
4
|
|
|
5
5
|
APP_URL=http://localhost:<%=it.frontendPort%>
|
|
6
6
|
|
|
7
|
-
DEBUGDATA=1
|
|
7
|
+
DEBUGDATA=1
|
|
8
|
+
|
|
9
|
+
OAUTH2_CONFIGURL=<%=it.keycloaksetting.OAUTH2_CONFIGURL%>
|
|
10
|
+
|
|
11
|
+
OAUTH2_CLIENTID=<%=it.keycloaksetting.OAUTH2_CLIENTID%>
|
|
12
|
+
|
|
13
|
+
OAUTH2_CLIENTSECRET=<%=it.keycloaksetting.OAUTH2_CLIENTSECRET%>
|
|
14
|
+
|
|
15
|
+
AUTH_SECRET_KEY=<%=it.keycloaksetting.AUTH_SECRET_KEY%>
|
|
16
|
+
|
|
17
|
+
AUTH_ORIGIN=http://localhost:<%=it.frontendPort%>
|
|
@@ -19,19 +19,19 @@ tailwindcss: {
|
|
|
19
19
|
// Options
|
|
20
20
|
},
|
|
21
21
|
modules: [
|
|
22
|
-
|
|
23
|
-
"nuxt-security",
|
|
24
|
-
|
|
22
|
+
'@sidebase/nuxt-auth',
|
|
23
|
+
"nuxt-security",
|
|
25
24
|
'@vueuse/nuxt',
|
|
26
25
|
'@nuxt/ui'
|
|
27
|
-
//'@nuxtjs/tailwindcss', //use @nuxt/ui own tailwind
|
|
28
|
-
// '@nuxtjs/color-mode'
|
|
29
|
-
|
|
30
26
|
],
|
|
31
|
-
|
|
27
|
+
auth: {
|
|
28
|
+
globalAppMiddleware: true
|
|
29
|
+
},
|
|
32
30
|
security: {
|
|
33
31
|
csrf: true,
|
|
34
32
|
},
|
|
33
|
+
ssr: true,
|
|
34
|
+
|
|
35
35
|
css: [
|
|
36
36
|
"primevue/resources/themes/lara-light-blue/theme.css",
|
|
37
37
|
'primeicons/primeicons.css'
|
|
@@ -41,5 +41,6 @@ tailwindcss: {
|
|
|
41
41
|
transpile: ["primevue"]
|
|
42
42
|
},
|
|
43
43
|
|
|
44
|
+
|
|
44
45
|
|
|
45
46
|
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
/**
|
|
3
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
4
|
+
* You may modify it for your need
|
|
5
|
+
* last change 2023-09-09
|
|
6
|
+
* author: Ks Tan
|
|
7
|
+
*/
|
|
8
|
+
</script>
|
|
9
|
+
<template>
|
|
10
|
+
<div>
|
|
11
|
+
<h1>index page</h1>
|
|
12
|
+
<ul>
|
|
13
|
+
<li><NuxtLink :external="true" to="/MS0xLTE" >MS0xLTE (1-1-1)</NuxtLink></li>
|
|
14
|
+
<li><NuxtLink :external="true" to="/Mi0yLTI" >Mi0yLTI (2-2-2)</NuxtLink></li>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
</template>
|
|
@@ -7,5 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
</script>
|
|
9
9
|
<template>
|
|
10
|
-
<div>
|
|
10
|
+
<div>
|
|
11
|
+
<h1>index page</h1>
|
|
12
|
+
<ul>
|
|
13
|
+
<li><NuxtLink :external="true" to="/MS0xLTE" >MS0xLTE (1-1-1)</NuxtLink></li>
|
|
14
|
+
<li><NuxtLink :external="true" to="/Mi0yLTI" >Mi0yLTI (2-2-2)</NuxtLink></li>
|
|
15
|
+
</ul>
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
11
19
|
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NuxtPage />
|
|
3
|
+
</template>
|
|
4
|
+
<script setup lang="ts">
|
|
5
|
+
definePageMeta({
|
|
6
|
+
name: 'Login',
|
|
7
|
+
auth: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
// const route = useRoute();
|
|
11
|
+
const { signIn } = useAuth()
|
|
12
|
+
onMounted(async () => {
|
|
13
|
+
let callbackUrl = '/';
|
|
14
|
+
// if(route.params.redirect) {
|
|
15
|
+
// callbackUrl = <string>route.params.redirect;
|
|
16
|
+
// }
|
|
17
|
+
await signIn('keycloak', { callbackUrl: callbackUrl })
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
</script>
|
|
@@ -40,9 +40,8 @@ const emitter = mitt()
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
const { csrf } = useCsrf()
|
|
44
|
+
axios.defaults.headers.common = {"CSRF-TOKEN": csrf};
|
|
46
45
|
nuxtApp.vueApp.use(PrimeVue, { ripple: true });
|
|
47
46
|
nuxtApp.vueApp
|
|
48
47
|
.component("SimpleAppAutocomplete",SimpleAppAutocomplete)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// give keycloak for
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const path = `${
|
|
4
|
+
process.env.OAUTH2_CONFIGURL
|
|
5
|
+
}/protocol/openid-connect/logout?redirect_uri=${encodeURIComponent(
|
|
6
|
+
process.env.AUTH_ORIGIN ?? ""
|
|
7
|
+
)}`;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
path: path
|
|
11
|
+
}
|
|
12
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated by simpleapp generator during initialization.
|
|
3
|
+
* DO NOT MODIFY IT BY HAND.
|
|
4
|
+
* last change 2023-09-09
|
|
5
|
+
* author: Ks Tan
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import axios from 'axios';
|
|
10
|
+
import { getServerSession } from '#auth'
|
|
11
|
+
import type { Session } from 'next-auth';
|
|
12
|
+
|
|
13
|
+
export default defineEventHandler(async (event) => {
|
|
14
|
+
let session:any=null
|
|
15
|
+
// console.log('---------hihi---------')
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
session = await getServerSession(event)
|
|
19
|
+
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return sendRedirect(event, '/login', 401)
|
|
22
|
+
}
|
|
23
|
+
// console.log(session)
|
|
24
|
+
return new Promise<any>(async (resolve, reject) => {
|
|
25
|
+
if(!session) {
|
|
26
|
+
//if(!session || !session.accessToken) {
|
|
27
|
+
reject({ statusMessage: 'Unauthorized', statusCode: 401 });
|
|
28
|
+
throw createError({ statusMessage: 'Unauthorized', statusCode: 401 })
|
|
29
|
+
}
|
|
30
|
+
// console.log("------hihi------")
|
|
31
|
+
const seperateSymbol = '.';
|
|
32
|
+
// const seperateSymbol = '&';
|
|
33
|
+
const xOrg = event.context.params?.xorg ?? ''
|
|
34
|
+
const documentLink = event.context.params?._ ?? ''
|
|
35
|
+
// const platform = event.context.params?.platform ?? ''
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
// console.error("event.context???",event.context)
|
|
39
|
+
const accessToken = session?.accessToken;
|
|
40
|
+
|
|
41
|
+
// const allowPlatform = ['report-api', 'cloudapi'];
|
|
42
|
+
// if(!key || !platform || !allowPlatform.includes(platform) || !accessToken) {
|
|
43
|
+
// reject({ statusMessage: 'Unauthorized', statusCode: 401 });
|
|
44
|
+
// // throw createError({ statusMessage: 'Unauthorized', statusCode: 401 })
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
// let tenantKey = '', organizationKey = '';
|
|
48
|
+
// let xOrg = '';
|
|
49
|
+
|
|
50
|
+
// if(key !== 'system') {
|
|
51
|
+
// [tenantKey, organizationKey] = key.split(seperateSymbol);
|
|
52
|
+
// xOrg = `${tenantKey}/${organizationKey}/`;
|
|
53
|
+
// }
|
|
54
|
+
|
|
55
|
+
// if(key === 'system' && platform == 'cloudapi') {
|
|
56
|
+
// // xOrg = 'MC0wLTA'
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
let forwardData: any = {};
|
|
60
|
+
|
|
61
|
+
const req = event.node.req;
|
|
62
|
+
|
|
63
|
+
if(req.method == 'POST' || req.method == 'PUT') {
|
|
64
|
+
|
|
65
|
+
forwardData = await readBody(event);
|
|
66
|
+
} else {
|
|
67
|
+
forwardData = getQuery(event);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// if(typeof forwardData === "object" && "_branch" in forwardData) {
|
|
71
|
+
// xOrg = xOrg + forwardData._branch;
|
|
72
|
+
// delete forwardData._branch;
|
|
73
|
+
// }
|
|
74
|
+
|
|
75
|
+
const frontEndRes = event.node.res;
|
|
76
|
+
const url = process.env.SIMPLEAPP_BACKEND_URL + '/' + documentLink;
|
|
77
|
+
// console.warn('backend server-----',url,'xorg',xOrg,'documentLink',documentLink)
|
|
78
|
+
const axiosConfig: any = {
|
|
79
|
+
method: req.method,
|
|
80
|
+
url: url,
|
|
81
|
+
headers: {
|
|
82
|
+
Authorization: `Bearer ${accessToken}`,
|
|
83
|
+
'X-Org': xOrg,
|
|
84
|
+
},
|
|
85
|
+
data: forwardData,
|
|
86
|
+
params: forwardData,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// if(key === 'system') {
|
|
90
|
+
// axiosConfig.headers["X-Global"] = true;
|
|
91
|
+
// delete axiosConfig.headers["X-Org"];
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
// if(otherLink.includes('avatar')) {
|
|
95
|
+
// axiosConfig.responseType = 'arraybuffer';
|
|
96
|
+
// // axiosConfig.headers['Acceptable'] = 'text/html,image/avif,image/webp,image/apng';
|
|
97
|
+
// }
|
|
98
|
+
|
|
99
|
+
axios(axiosConfig).then((res) => {
|
|
100
|
+
if (res.headers['content-type'] === 'image/png') {
|
|
101
|
+
// Set the response headers for the image
|
|
102
|
+
frontEndRes.setHeader('Content-Type', 'image/png');
|
|
103
|
+
frontEndRes.setHeader('Content-Disposition', 'inline');
|
|
104
|
+
|
|
105
|
+
// Send the image data as the response body
|
|
106
|
+
frontEndRes.end(Buffer.from(res.data, 'binary'));
|
|
107
|
+
} else {
|
|
108
|
+
// For non-image responses, set the Content-Type header and send the response body
|
|
109
|
+
// setHeader(event, 'Content-type', <string>res.headers['Content-Type']);
|
|
110
|
+
|
|
111
|
+
frontEndRes.statusCode = res.status;
|
|
112
|
+
if(res.statusText) {
|
|
113
|
+
frontEndRes.statusMessage = res.statusText;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resolve(res.data);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
}).catch((error) => {
|
|
120
|
+
// console.log("==============================================================")
|
|
121
|
+
// console.log('@@@@@@@@@@@@@ API error', error)
|
|
122
|
+
// console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
|
|
123
|
+
// console.log('######### response', error.response)
|
|
124
|
+
// console.log('#####################################')
|
|
125
|
+
// console.log(axiosConfig);
|
|
126
|
+
// console.log('#####################################')
|
|
127
|
+
|
|
128
|
+
if (error.response?.status && error.response.status == '401') {
|
|
129
|
+
return reject({ statusMessage: 'Unauthorized', statusCode: 401 });
|
|
130
|
+
// throw createError({ statusMessage: 'Unauthorized', statusCode: 401 })
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// reject(error.data)
|
|
134
|
+
reject({ statusMessage: error.response.statusText, statusCode: error.response.status });
|
|
135
|
+
// resolve({ status: 'ok' })
|
|
136
|
+
// throw createError({ statusMessage: 'Bad Requests', statusCode: 404 })
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// resolve({
|
|
140
|
+
// status: 'ok'
|
|
141
|
+
// })
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
})
|
|
@@ -7,22 +7,27 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
import axios from 'axios';
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import { getServerSession } from '#auth'
|
|
11
|
+
import type { Session } from 'next-auth';
|
|
12
12
|
|
|
13
13
|
export default defineEventHandler(async (event) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
type additionalprops = {accessToken?:string}
|
|
15
|
+
let session:any=null
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
session = await getServerSession(event)
|
|
20
|
+
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return sendRedirect(event, '/login', 401)
|
|
23
|
+
}
|
|
20
24
|
|
|
21
25
|
return new Promise<any>(async (resolve, reject) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
if(!session) {
|
|
27
|
+
//if(!session || !session.accessToken) {
|
|
28
|
+
reject({ statusMessage: 'Unauthorized', statusCode: 401 });
|
|
29
|
+
throw createError({ statusMessage: 'Unauthorized', statusCode: 401 })
|
|
30
|
+
}
|
|
26
31
|
// console.log("------hihi------")
|
|
27
32
|
const seperateSymbol = '.';
|
|
28
33
|
// const seperateSymbol = '&';
|
|
@@ -32,7 +37,7 @@ export default defineEventHandler(async (event) => {
|
|
|
32
37
|
|
|
33
38
|
|
|
34
39
|
// console.error("event.context???",event.context)
|
|
35
|
-
|
|
40
|
+
const accessToken = session?.accessToken;
|
|
36
41
|
|
|
37
42
|
// const allowPlatform = ['report-api', 'cloudapi'];
|
|
38
43
|
// if(!key || !platform || !allowPlatform.includes(platform) || !accessToken) {
|
|
@@ -75,7 +80,7 @@ export default defineEventHandler(async (event) => {
|
|
|
75
80
|
method: req.method,
|
|
76
81
|
url: url,
|
|
77
82
|
headers: {
|
|
78
|
-
|
|
83
|
+
Authorization: `Bearer ${accessToken}`,
|
|
79
84
|
'X-Org': xOrg,
|
|
80
85
|
},
|
|
81
86
|
data: forwardData,
|