@simitgroup/simpleapp-generator 1.0.23 → 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.
Files changed (66) hide show
  1. package/README.md +48 -0
  2. package/dist/createproject.js +1 -1
  3. package/dist/createproject.js.map +1 -1
  4. package/dist/framework.js +37 -25
  5. package/dist/framework.js.map +1 -1
  6. package/dist/generate.js +38 -16
  7. package/dist/generate.js.map +1 -1
  8. package/dist/index.js +2 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/processors/jsonschemabuilder.js +9 -9
  11. package/dist/processors/jsonschemabuilder.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/framework.ts +50 -36
  14. package/src/generate.ts +37 -21
  15. package/src/index.ts +2 -1
  16. package/src/processors/jsonschemabuilder.ts +9 -9
  17. package/src/type.ts +1 -0
  18. package/templates/basic/apischema.eta +8 -4
  19. package/templates/basic/controller.eta +21 -5
  20. package/templates/basic/jsonschema.eta +2 -0
  21. package/templates/basic/model.eta +4 -7
  22. package/templates/basic/module.eta +2 -0
  23. package/templates/basic/pageindex.vue.eta +28 -15
  24. package/templates/basic/pageindexwithid.vue.eta +13 -1
  25. package/templates/basic/service.eta +11 -9
  26. package/templates/basic/simpleappclient.eta +9 -8
  27. package/templates/basic/type.eta +2 -1
  28. package/templates/nest/SimpleAppController.eta +5 -5
  29. package/templates/nest/SimpleAppService.eta +87 -31
  30. package/templates/nest/TenantMiddleware.eta +39 -0
  31. package/templates/nest/User.eta +115 -0
  32. package/templates/nest/app.module.eta +24 -4
  33. package/templates/nest/inputvalidation-exception.eta +6 -0
  34. package/templates/nest/nest.env.eta +12 -1
  35. package/templates/nest/nest.main.eta +14 -3
  36. package/templates/nest/oauth2-redirect.eta +79 -0
  37. package/templates/nuxt/components.crudsimple.vue.eta +60 -48
  38. package/templates/nuxt/components.debugdocdata.vue.eta +12 -4
  39. package/templates/nuxt/components.eventmonitor.vue.eta +17 -11
  40. package/templates/nuxt/components.menus.vue.eta +14 -12
  41. package/templates/nuxt/composables.getautocomplete.ts.eta +19 -8
  42. package/templates/nuxt/composables.getmenus.ts.eta +27 -9
  43. package/templates/nuxt/env.eta +12 -0
  44. package/templates/nuxt/layouts.default.vue.eta +10 -3
  45. package/templates/nuxt/nuxt.config.ts.eta +10 -6
  46. package/templates/nuxt/pages.[xorg].index.vue.eta +19 -0
  47. package/templates/nuxt/pages.index.vue.eta +17 -1
  48. package/templates/nuxt/pages.login.vue.eta +20 -0
  49. package/templates/nuxt/plugins.simpleapp.ts.eta +12 -4
  50. package/templates/nuxt/server.api.auth.logout.ts.eta +12 -0
  51. package/templates/nuxt/server.api.auth[...].ts.eta +144 -0
  52. package/templates/nuxt/server.api.ts.eta +33 -19
  53. package/src/createproject.ts +0 -121
  54. package/src/index2.ts-old +0 -132
  55. package/src/installdependency.sh +0 -5
  56. package/src/installnest.ts +0 -0
  57. package/src/installnuxt.ts +0 -0
  58. package/templates/basic/backend.config.eta +0 -1
  59. package/templates/basic/beforesave.eta +0 -7
  60. package/templates/basic/controller2.eta +0 -86
  61. package/templates/basic/frontend.config.eta +0 -1
  62. package/templates/basic/model-converter.etabackup +0 -21
  63. package/templates/basic/readme.eta +0 -3
  64. package/templates/basic/service.etabackupe +0 -106
  65. package/templates/basic/type.etabackup +0 -23
  66. package/templates/basic/uischema.eta +0 -13
@@ -13,6 +13,7 @@ import { ApiTags, ApiBody, ApiResponse, ApiOperation } from '@nestjs/swagger';
13
13
  const doctype = 'person'.toUpperCase();
14
14
  type ServiceType = {
15
15
  list: Function;
16
+ search: Function;
16
17
  create: Function;
17
18
  update: Function;
18
19
  delete: Function;
@@ -34,10 +35,12 @@ export class SimpleAppController<TService extends ServiceType, TApiSchema, T> {
34
35
  this.service = service;
35
36
  }
36
37
 
37
-
38
38
  async _list() {
39
39
  return this.service.list();
40
40
  }
41
+ async _search(searchObject:Object) {
42
+ return this.service.search(searchObject);
43
+ }
41
44
  async _autocomplete(keyword: string) {
42
45
  return this.service.getAutoComplete(keyword);
43
46
  }
@@ -47,7 +50,6 @@ export class SimpleAppController<TService extends ServiceType, TApiSchema, T> {
47
50
  return result as Type<TApiSchema>;
48
51
  }
49
52
 
50
-
51
53
  async _create(data: TApiSchema) {
52
54
  //const newdata: persontype.Person = { ...data };
53
55
  const newdata: T = {} as T; //= { ...data };
@@ -55,14 +57,12 @@ export class SimpleAppController<TService extends ServiceType, TApiSchema, T> {
55
57
  return this.service.setData(newdata).create() as TApiSchema;
56
58
  }
57
59
 
58
-
59
- async _update( id: string,data: TApiSchema) {
60
+ async _update(id: string, data: TApiSchema) {
60
61
  const newdata: T = {} as T; //= { ...data };
61
62
  Object.assign(newdata, data); //
62
63
  return this.service.findIdThenUpdate(id, newdata) as TApiSchema;
63
64
  }
64
65
 
65
-
66
66
  async _delete(id: string) {
67
67
  return this.service.findIdThenDelete(id);
68
68
  }
@@ -4,10 +4,18 @@ import { Model } from 'mongoose';
4
4
  import Ajv from 'ajv';
5
5
  import addFormats from 'ajv-formats';
6
6
  import foreignkeys from '../dicts/foreignkeys.json';
7
+
7
8
  import {
8
9
  NotFoundException,
9
10
  InternalServerErrorException,
10
11
  } from '@nestjs/common/exceptions';
12
+ import { User } from './User';
13
+
14
+ export enum IsolationType {
15
+ 'org' = 'org',
16
+ 'tenant' = 'tenant',
17
+ 'branch' = 'branch',
18
+ }
11
19
  @Injectable()
12
20
  export class SimpleAppService<T extends { _id?: string }> {
13
21
  protected jsonschema = { type: 'object', properties: {}, required: [] };
@@ -16,11 +24,19 @@ export class SimpleAppService<T extends { _id?: string }> {
16
24
  protected documentName = 'category';
17
25
  protected documentType = 'CAT';
18
26
  protected LIMITPERPAGE = 20;
27
+ protected isolationtype: IsolationType = IsolationType.org;
28
+ protected isolationFilter: any = {};
19
29
  protected data: T = { _id: '' } as T;
20
- protected doc: Model<T>;
30
+ private doc: Model<T>; //set private to prevent developer break data isolation control
21
31
  protected errorlist = [];
22
- constructor(newdoc: Model<T>) {
32
+ constructor(
33
+ newdoc: Model<T>,
34
+ isolationtype: IsolationType = IsolationType.org,
35
+ ) {
23
36
  this.doc = newdoc;
37
+ this.isolationtype = isolationtype;
38
+
39
+ // this.tenantdoc = tenantdoc
24
40
  }
25
41
  getRecordId = (): string => this.data._id;
26
42
  setSchema = (newschema) => (this.jsonschema = newschema);
@@ -34,9 +50,27 @@ export class SimpleAppService<T extends { _id?: string }> {
34
50
  this.data = { ...newdata };
35
51
  return this;
36
52
  };
53
+ getIsolationFilter = () => {
54
+ let isolationFilter = {};
55
+ switch (this.isolationtype) {
56
+ case 'branch':
57
+ isolationFilter = User.getInstance().getBranchFilter();
58
+ break;
59
+ case 'tenant':
60
+ isolationFilter = User.getInstance().getTenantFilter();
61
+ break;
62
+ case 'org':
63
+ default:
64
+ isolationFilter = User.getInstance().getOrgFilter();
65
+ break;
66
+ }
67
+ return isolationFilter;
68
+ };
37
69
  async list() {
38
70
  try {
39
- const products = await this.doc.find();
71
+ //console.log("this.isolationFilter",this.getIsolationFilter())
72
+ const products = await this.doc.find(this.getIsolationFilter());
73
+ // console.log(products)
40
74
  const productlist = products.map((p: T) => {
41
75
  return p;
42
76
  });
@@ -53,6 +87,8 @@ export class SimpleAppService<T extends { _id?: string }> {
53
87
  filter1[this.documentIdentityCode] = { $regex: keyword };
54
88
  filter2[this.documentIdentityName] = { $regex: keyword };
55
89
  const filterobj = { $or: [filter1, filter2] };
90
+
91
+ Object.assign(filterobj, this.getIsolationFilter());
56
92
  const projections = {
57
93
  id: `\$_id`,
58
94
  label: `\$${this.documentIdentityCode}`,
@@ -69,31 +105,37 @@ export class SimpleAppService<T extends { _id?: string }> {
69
105
  throw new InternalServerErrorException(err.message);
70
106
  }
71
107
  }
72
- async findById(id: string) {
108
+ async search(filters: Object) {
73
109
  try {
74
- //console.log('findById', id);
75
- this.data = await this.doc.findById(id);
76
- //console.log('findById done', this.data);
110
+ Object.assign(filters, this.getIsolationFilter());
111
+ const products = await this.doc.find(filters);
112
+ const productlist = products.map((p: T) => {
113
+ return p;
114
+ });
115
+ // console.log(products);
116
+ return productlist;
77
117
  } catch (err) {
78
- //error
79
118
  throw new InternalServerErrorException(err.message);
80
119
  }
81
-
82
- if (!this.data) {
83
- //data not found
84
- throw new NotFoundException('Document Not found:');
85
- }
86
- //console.log('this.data', this.data);
87
- return this.data;
88
120
  // return this;
89
121
  }
122
+ async findById(id: string) {
123
+ const data = await this.search({ _id: id });
124
+ if (data.length == 1) {
125
+ // console.log('data0', data[0]);
126
+ return data[0];
127
+ } else {
128
+ return null;
129
+ }
130
+ }
90
131
 
91
132
  async create() {
92
133
  let result;
93
134
 
94
135
  try {
136
+ Object.assign(this.data, User.getInstance().getCreateFilter());
95
137
  delete this.data._id;
96
- this.validateData(this.data);
138
+ this.validateData(this.data);
97
139
  const newdoc = new this.doc(this.data);
98
140
  result = await newdoc.save();
99
141
  } catch (err) {
@@ -103,14 +145,14 @@ export class SimpleAppService<T extends { _id?: string }> {
103
145
  }
104
146
  async update() {
105
147
  const id: string = this.getRecordId();
148
+ Object.assign(this.data, User.getInstance().getUpdateFilter());
106
149
  this.findIdThenUpdate(id, this.data);
107
150
  }
108
151
  async delete() {
109
-
110
152
  const id: string = this.getRecordId();
111
153
  const dependency = await this.getRelatedRecords(id);
112
154
  if (!dependency) {
113
- return await this.findIdThenDelete(id);
155
+ return await this.findIdThenDelete(id);
114
156
  } else {
115
157
  return dependency;
116
158
  }
@@ -121,10 +163,10 @@ export class SimpleAppService<T extends { _id?: string }> {
121
163
  validateData(data: T) {
122
164
  const ajv = new Ajv({ allErrors: true });
123
165
  addFormats(ajv);
124
- ajv.addFormat('field-autocomplete-code', /.*$/);
125
- ajv.addFormat('field-autocomplete-name', /.*$/);
126
- ajv.addFormat('x-text',/.*$/)
127
- ajv.addFormat('x-html',/.*$/)
166
+ ajv.addFormat('x-document-no', /.*$/);
167
+ ajv.addFormat('x-document-name', /.*$/);
168
+ ajv.addFormat('x-text', /.*$/);
169
+ ajv.addFormat('x-html', /.*$/);
128
170
  ajv.addKeyword({
129
171
  keyword: 'x-foreignkey',
130
172
  type: 'string',
@@ -135,28 +177,36 @@ export class SimpleAppService<T extends { _id?: string }> {
135
177
  for (let i = 0; i < this.errorlist.length; i++) {
136
178
  erromsg.push(this.errorlist[i].message);
137
179
  }
180
+ console.log("pre-validation:",erromsg)
138
181
  throw new InternalServerErrorException(erromsg.join('\n'));
139
182
  }
140
183
  const validate = ajv.compile(this.jsonschema);
141
184
  const valid = validate(data);
185
+ //console.log(validate.errors);
142
186
  if (!valid) {
143
- //console.log(validate.errors);
187
+ // console.log(validate.errors);
144
188
  const erromsg: string[] = [];
145
189
  for (let i = 0; i < validate.errors.length; i++) {
146
190
  erromsg.push(validate.errors[i].message);
147
191
  }
192
+ console.log("ajv erromsg: ",erromsg)
148
193
  throw new InternalServerErrorException(erromsg.join('\n'));
149
194
  }
150
195
  this.hook('post-validation', data);
151
196
  }
152
197
 
153
- async findIdThenDelete(id: string) {
198
+ async findIdThenDelete(id: string): Promise<any> {
154
199
  // const data = await this.findById(id);
155
200
  try {
156
201
  //console.log('deletedeletedeletedelete');
157
202
  const dependency = await this.getRelatedRecords(id);
158
203
  if (!dependency) {
159
- const deleteresult = await this.doc.findByIdAndDelete(id);
204
+ let filter = this.getIsolationFilter();
205
+ filter['_id'] = id;
206
+ const deleteresult = await this.doc.deleteOne(filter);
207
+ // this.doc.findByIdAndDelete(id)
208
+
209
+ //this.doc.findByIdAndDelete(id);
160
210
  return deleteresult;
161
211
  } else {
162
212
  return Promise.reject(dependency);
@@ -166,20 +216,26 @@ export class SimpleAppService<T extends { _id?: string }> {
166
216
  }
167
217
  }
168
218
 
169
- async findIdThenUpdate(id: string, data: T) {
170
- // const existingdata = await this.findById(id);
219
+ updateOne = async (data: T) => {
220
+ this.doc.updateOne(data);
221
+ };
222
+
223
+ findIdThenUpdate = async (id: string, data: T) => {
224
+ const existingdata = await this.findById(id);
171
225
 
172
226
  try {
173
- //console.log('findIdThenUpdate', id);
227
+ Object.assign(data, User.getInstance().getUpdateFilter());
228
+ Object.assign(existingdata, data);
174
229
  this.validateData(data);
175
- // const result = await existingdata.doc.updateOne(data);
176
- const result = await this.doc.findByIdAndUpdate(id, data);
230
+ let filter = this.getIsolationFilter();
231
+ filter['_id'] = id;
232
+ const result = await this.doc.findOneAndUpdate(filter, data);
177
233
 
178
234
  return result;
179
235
  } catch (err) {
180
236
  throw new InternalServerErrorException(err.message);
181
237
  }
182
- }
238
+ };
183
239
 
184
240
  //find what foreign key constraint
185
241
  async getRelatedRecords(id: string) {
@@ -0,0 +1,39 @@
1
+ import { Injectable, NestMiddleware, Scope } from '@nestjs/common';
2
+ import { Request, Response, NextFunction } from 'express';
3
+ // import * as jwt from 'nestjs-jwt'
4
+
5
+
6
+ import { User } from './User';
7
+ // import {KeycloakConfigService} from "../keycloak/keycloak.service"
8
+ @Injectable({
9
+ scope: Scope.REQUEST,
10
+ })
11
+
12
+ export class TenantMiddleware implements NestMiddleware {
13
+ use(req: Request, res: Response, next: NextFunction) {
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();
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');
34
+ }
35
+
36
+
37
+
38
+ }
39
+ }
@@ -0,0 +1,115 @@
1
+ import { Injectable, Scope } from '@nestjs/common';
2
+ import Base64URL from '@darkwolf/base64url';
3
+ import * as jwt from 'jsonwebtoken'
4
+
5
+
6
+
7
+
8
+
9
+ @Injectable({
10
+ scope: Scope.REQUEST,
11
+ })
12
+ export class User {
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();
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
+ };
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;
113
+ }
114
+ };
115
+ }
@@ -1,15 +1,35 @@
1
- import { Module } from '@nestjs/common';
1
+ import { Module,MiddlewareConsumer,NestModule } from '@nestjs/common';
2
2
  import { MongooseModule } from '@nestjs/mongoose';
3
3
  import { ConfigModule } from '@nestjs/config';
4
-
4
+ import { ServeStaticModule } from '@nestjs/serve-static';
5
+ import { join } from 'path';
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'
7
9
  <%}%>
8
10
 
9
11
  @Module({
10
12
  //define environment variables: MONGODB_URL='mongodb://<user>:<pass>@<host>:<port>/<db>?authMechanism=DEFAULT'
11
- imports: [ConfigModule.forRoot(),MongooseModule.forRoot(process.env.MONGODB_URL),<% for(let i=0;i<it.length; i++){ %><%= it[i].docname %>Module,<%}%>],
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
  })
15
- export class AppModule {}
24
+ export class AppModule implements NestModule{
25
+ configure(consumer: MiddlewareConsumer) {
26
+ consumer
27
+ .apply(TenantMiddleware)
28
+ // .exclude('/api-yaml')
29
+ // .exclude('/api-json')
30
+ // .exclude('/api')
31
+ .forRoutes('*')
32
+
33
+
34
+ }
35
+ }
@@ -0,0 +1,6 @@
1
+ import {HttpException,HttpStatus} from '@nestjs/common'
2
+ export class InputValidationExceptions extends HttpException {
3
+ constructor() {
4
+ super('input error', HttpStatus.INTERNAL_SERVER_ERROR);
5
+ }
6
+ }
@@ -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,12 +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({
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')
21
+ .addSecurityRequirements('x-org')
22
+ .addSecurityRequirements('oauth2')
12
23
  .build();
13
24
  const document = SwaggerModule.createDocument(app, config);
14
25
  SwaggerModule.setup('api', app, document, {
15
- swaggerOptions: { showExtensions: true },
26
+ swaggerOptions: { showExtensions: true, persistAuthorization: true },
16
27
  });
17
28
 
18
- await app.listen(process.env.HTTP_PORT ?? <%=it.backendPort%>); //listen which port
29
+ await app.listen(process.env.HTTP_PORT ?? 8000); //listen which port
19
30
  }
20
- 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>