@etsoo/materialui 1.3.87 → 1.3.89

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.
@@ -56,16 +56,9 @@ export abstract class CommonApp<
56
56
  * Refresh token
57
57
  * @param props Props
58
58
  */
59
- override async refreshToken<D extends object = Partial<RefreshTokenRQ>>(
60
- props?: RefreshTokenProps<D>
61
- ) {
59
+ override async refreshToken(props?: RefreshTokenProps) {
62
60
  // Destruct
63
- const {
64
- callback,
65
- data,
66
- relogin = false,
67
- showLoading = false
68
- } = props ?? {};
61
+ const { callback, showLoading = false } = props ?? {};
69
62
 
70
63
  // Token
71
64
  const token = this.getCacheToken();
@@ -76,10 +69,7 @@ export abstract class CommonApp<
76
69
 
77
70
  // Reqest data
78
71
  const rq: RefreshTokenRQ = {
79
- deviceId: this.deviceId,
80
- region: this.region,
81
- timezone: this.getTimeZone(),
82
- ...data
72
+ deviceId: this.deviceId
83
73
  };
84
74
 
85
75
  // Login result type
@@ -132,56 +122,12 @@ export abstract class CommonApp<
132
122
  if (result == null) return false;
133
123
 
134
124
  if (!result.ok) {
135
- if (result.type === "TokenExpired" && relogin) {
136
- // Try login
137
- // Dialog to receive password
138
- var labels = this.getLabels("reloginTip", "login");
139
- this.notifier.prompt(
140
- labels.reloginTip,
141
- async (pwd) => {
142
- if (pwd == null) {
143
- this.toLoginPage();
144
- return;
145
- }
146
-
147
- // Set password for the action
148
- rq.pwd = this.encrypt(this.hash(pwd));
149
-
150
- // Submit again
151
- const result = await this.api.put<LoginResult>(
152
- "Auth/RefreshToken",
153
- rq,
154
- payload
155
- );
156
-
157
- if (result == null) return;
158
-
159
- if (result.ok) {
160
- success(result, (loginResult: RefreshTokenResult) => {
161
- if (loginResult === true) {
162
- if (callback) callback(true);
163
- return;
164
- }
165
-
166
- const message = this.formatRefreshTokenResult(loginResult);
167
- if (message) this.notifier.alert(message);
168
- });
169
- return;
170
- }
171
-
172
- // Popup message
173
- this.alertResult(result);
174
- return false;
175
- },
176
- labels.login,
177
- { type: "password" }
178
- );
179
-
180
- // Fake truth to avoid reloading
181
- return true;
182
- }
125
+ // Remove the wrong token
126
+ this.clearCacheToken();
183
127
 
128
+ // Callback
184
129
  if (callback) callback(result);
130
+
185
131
  return false;
186
132
  }
187
133
 
@@ -190,24 +136,18 @@ export abstract class CommonApp<
190
136
 
191
137
  /**
192
138
  * Try login
193
- * @param data Additional data
194
139
  * @param showLoading Show loading bar or not
195
140
  * @returns Result
196
141
  */
197
- override async tryLogin<D extends object = RefreshTokenRQ>(
198
- data?: D,
199
- showLoading?: boolean
200
- ) {
142
+ override async tryLogin(showLoading?: boolean) {
201
143
  // Reset user state
202
- const result = await super.tryLogin(data);
144
+ const result = await super.tryLogin(showLoading);
203
145
  if (!result) return false;
204
146
 
205
147
  // Refresh token
206
148
  return await this.refreshToken({
207
149
  callback: (result) => this.doRefreshTokenResult(result),
208
- data,
209
- showLoading,
210
- relogin: true
150
+ showLoading
211
151
  });
212
152
  }
213
153
  }
@@ -1,36 +1,13 @@
1
- import { IApi, RefreshTokenResult } from "@etsoo/appscript";
2
- import { IServiceUser } from "./IServiceUser";
3
1
  import { ReactAppType } from "./ReactApp";
4
- import { IAppApi } from "./IAppApi";
5
2
 
6
3
  /**
7
4
  * Service application interface
8
5
  */
9
6
  export interface IServiceApp extends ReactAppType {
10
7
  /**
11
- * Service API
8
+ * Load core system UI
12
9
  */
13
- readonly serviceApi: IApi;
14
-
15
- /**
16
- * Service user
17
- */
18
- readonly serviceUser?: IServiceUser;
19
-
20
- /**
21
- * Service application API login
22
- * @param appApi Service application API
23
- * @param callback Callback
24
- */
25
- apiLogin(
26
- appApi: IAppApi,
27
- callback?: (result: RefreshTokenResult, successData?: string) => void
28
- ): Promise<boolean>;
29
-
30
- /**
31
- * Load SmartERP core
32
- */
33
- loadSmartERP(): void;
10
+ loadCore(): void;
34
11
 
35
12
  /**
36
13
  * Service decrypt message
@@ -7,7 +7,7 @@ import { IdType } from "@etsoo/shared";
7
7
  export interface IServiceAppSettings<S extends IdType = number>
8
8
  extends IAppSettings {
9
9
  /**
10
- * Service id
10
+ * Service application id
11
11
  */
12
- readonly serviceId: S;
12
+ readonly appId: S;
13
13
  }
@@ -16,11 +16,6 @@ export interface IServiceUser extends IUser {
16
16
  */
17
17
  readonly organizationName: string;
18
18
 
19
- /**
20
- * Service (App) device id
21
- */
22
- readonly serviceDeviceId: string;
23
-
24
19
  /**
25
20
  * Service (App) passphrase encrypted
26
21
  */
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  BridgeUtils,
3
3
  CoreApp,
4
- createClient,
5
4
  FormatResultCustomCallback,
6
5
  IApp,
7
6
  IAppSettings,
@@ -253,7 +252,7 @@ export class ReactApp<
253
252
  constructor(settings: S, name: string, debug: boolean = false) {
254
253
  super(
255
254
  settings,
256
- createClient(),
255
+ null,
257
256
  ReactApp.createNotifier(debug),
258
257
  new WindowStorage(),
259
258
  name,
@@ -1,29 +1,11 @@
1
- import {
2
- BridgeUtils,
3
- createClient,
4
- IApi,
5
- IApiPayload,
6
- RefreshTokenProps,
7
- RefreshTokenResult,
8
- RefreshTokenRQ
9
- } from "@etsoo/appscript";
10
- import { CoreConstants } from "@etsoo/react";
11
- import { DomUtils, IActionResult } from "@etsoo/shared";
1
+ import { BridgeUtils, ExternalEndpoint, IApi } from "@etsoo/appscript";
12
2
  import { IServiceApp } from "./IServiceApp";
13
3
  import { IServiceAppSettings } from "./IServiceAppSettings";
14
4
  import { IServicePageData } from "./IServicePage";
15
- import { IServiceUser, ServiceLoginResult } from "./IServiceUser";
16
- import { ISmartERPUser } from "./ISmartERPUser";
5
+ import { IServiceUser } from "./IServiceUser";
17
6
  import { ReactApp } from "./ReactApp";
18
- import { IAppApi } from "./IAppApi";
19
7
 
20
- /**
21
- * Service application refresh token properties
22
- */
23
- export interface ServiceRefreshTokenProps
24
- extends RefreshTokenProps<Partial<RefreshTokenRQ>> {
25
- appApi?: IAppApi;
26
- }
8
+ const coreName = "core";
27
9
 
28
10
  /**
29
11
  * Core Service App
@@ -36,24 +18,18 @@ export class ServiceApp<
36
18
  P extends IServicePageData = IServicePageData,
37
19
  S extends IServiceAppSettings = IServiceAppSettings
38
20
  >
39
- extends ReactApp<S, ISmartERPUser, P>
21
+ extends ReactApp<S, U, P>
40
22
  implements IServiceApp
41
23
  {
42
24
  /**
43
- * Service API
25
+ * Core endpoint
44
26
  */
45
- readonly serviceApi: IApi;
27
+ protected coreEndpoint: ExternalEndpoint;
46
28
 
47
- private _serviceUser?: U;
48
29
  /**
49
- * Service user
30
+ * Core system API
50
31
  */
51
- get serviceUser() {
52
- return this._serviceUser;
53
- }
54
- protected set serviceUser(value: U | undefined) {
55
- this._serviceUser = value;
56
- }
32
+ readonly coreApi: IApi;
57
33
 
58
34
  /**
59
35
  * Service passphrase
@@ -70,46 +46,27 @@ export class ServiceApp<
70
46
  super(settings, name, debug);
71
47
 
72
48
  // Check
73
- if (settings.serviceId == null || settings.serviceEndpoint == null) {
74
- throw new Error("No service settings");
49
+ if (settings.appId == null) {
50
+ throw new Error("Service Application ID is required.");
75
51
  }
76
52
 
77
- // Service API
78
- const api = createClient();
79
- this.setApi(api);
80
-
81
- // Fix the baseUrl done by setupApi (Default is the settings.endpoint)
82
- api.baseUrl = settings.serviceEndpoint;
83
-
84
- this.serviceApi = api;
85
- }
53
+ const coreEndpoint = settings.endpoints?.core;
54
+ if (coreEndpoint == null) {
55
+ throw new Error("Core API endpont is required.");
56
+ }
57
+ this.coreEndpoint = coreEndpoint;
86
58
 
87
- /**
88
- * Service application API login
89
- * @param appApi Service application API
90
- * @param callback Callback
91
- */
92
- apiLogin(
93
- appApi: IAppApi,
94
- callback?: (result: RefreshTokenResult, successData?: string) => void
95
- ) {
96
- return this.refreshToken({
97
- callback,
98
- data: appApi.getRefreshTokenData(),
99
- relogin: false,
100
- showLoading: false,
101
- appApi
102
- });
59
+ this.coreApi = this.createApi(coreName, coreEndpoint);
103
60
  }
104
61
 
105
62
  /**
106
- * Load SmartERP core
63
+ * Load core system UI
107
64
  */
108
- loadSmartERP() {
65
+ loadCore() {
109
66
  if (BridgeUtils.host == null) {
110
- window.location.href = this.settings.webUrl;
67
+ globalThis.location.href = this.coreEndpoint.webUrl;
111
68
  } else {
112
- BridgeUtils.host.loadApp("core");
69
+ BridgeUtils.host.loadApp(coreName);
113
70
  }
114
71
  }
115
72
 
@@ -119,193 +76,53 @@ export class ServiceApp<
119
76
  * @param removeUrl Remove current URL for reuse
120
77
  */
121
78
  override toLoginPage(tryLogin?: boolean, removeUrl?: boolean) {
122
- const parameters = `?serviceId=${this.settings.serviceId}&${
123
- DomUtils.CultureField
124
- }=${this.culture}${tryLogin ? "" : "&tryLogin=false"}${
125
- removeUrl ? "" : "&url=" + encodeURIComponent(location.href)
126
- }`;
79
+ // Cache current URL
80
+ this.cachedUrl = removeUrl ? undefined : globalThis.location.href;
81
+
127
82
  // Make sure apply new device id for new login
128
83
  this.clearDeviceId();
129
84
 
130
- if (BridgeUtils.host == null) {
131
- const coreUrl = this.settings.webUrl;
132
- window.location.href = coreUrl + parameters;
133
- } else {
134
- BridgeUtils.host.loadApp("core", parameters);
135
- }
85
+ // Get the redirect URL
86
+ this.api
87
+ .get<string>("Auth/GetLogInUrl", {
88
+ region: this.region,
89
+ device: this.deviceId
90
+ })
91
+ .then((url) => {
92
+ if (!url) return;
93
+
94
+ url += `?tryLogin=${tryLogin ?? false}`;
95
+
96
+ if (BridgeUtils.host == null) {
97
+ globalThis.location.href = url;
98
+ } else {
99
+ BridgeUtils.host.loadApp(coreName, url);
100
+ }
101
+ });
136
102
  }
137
103
 
138
104
  /**
139
- * Refresh token
140
- * @param props Props
105
+ * User login extended
106
+ * @param user New user
107
+ * @param refreshToken Refresh token
108
+ * @param keep Keep in local storage or not
109
+ * @param dispatch User state dispatch
141
110
  */
142
- override async refreshToken(props?: ServiceRefreshTokenProps) {
143
- // Destruct
144
- const {
145
- appApi,
146
- callback,
147
- data,
148
- relogin = false,
149
- showLoading = false
150
- } = props ?? {};
151
-
152
- // Token
153
- const token = this.getCacheToken();
154
- if (token == null || token === "") {
155
- if (callback) callback(false);
156
- return false;
157
- }
158
-
159
- // Reqest data
160
- // Merge additional data passed
161
- const rq: RefreshTokenRQ = {
162
- deviceId: this.deviceId,
163
- region: this.region,
164
- timezone: this.getTimeZone(),
165
- ...data
166
- };
167
-
168
- // Login result type
169
- type LoginResult = IActionResult<U>;
170
-
171
- // Payload
172
- const payload: IApiPayload<LoginResult, any> = {
173
- showLoading,
174
- config: { headers: { [CoreConstants.TokenHeaderRefresh]: token } },
175
- onError: (error) => {
176
- if (callback) callback(error);
177
-
178
- // Prevent further processing
179
- return false;
180
- }
181
- };
182
-
183
- // Success callback
184
- const success = async (
185
- result: LoginResult,
186
- failCallback?: (result: RefreshTokenResult) => void
187
- ) => {
188
- // Token
189
- const refreshToken = this.getResponseToken(payload.response);
190
- if (refreshToken == null || result.data == null) {
191
- if (failCallback) failCallback(this.get("noData")!);
192
- return false;
193
- }
194
-
195
- // User data
196
- const userData = result.data;
197
-
198
- // Use core system access token to service api to exchange service access token
199
- const api = appApi ? appApi.api : this.serviceApi;
200
- const serviceResult = await api.put<ServiceLoginResult<U>>(
201
- "Auth/ExchangeToken",
202
- {
203
- token: this.encryptEnhanced(
204
- userData.token,
205
- (appApi?.serviceId ?? this.settings.serviceId).toString()
206
- )
207
- },
208
- {
209
- showLoading,
210
- onError: (error) => {
211
- if (failCallback) failCallback(error);
212
-
213
- // Prevent further processing
214
- return false;
215
- }
216
- }
217
- );
218
-
219
- if (serviceResult == null) return false;
220
-
221
- if (!serviceResult.ok) {
222
- if (failCallback) failCallback(serviceResult);
223
- return false;
224
- }
225
-
226
- if (serviceResult.data == null) {
227
- if (failCallback) failCallback(this.get("noData")!);
228
- return false;
229
- }
230
-
231
- // Login
232
- if (appApi) {
233
- // Authorize external service application API
234
- appApi.authorize(userData, refreshToken, serviceResult.data);
235
- } else {
236
- // Authorize local service
237
- this.userLoginEx(userData, refreshToken, serviceResult.data);
238
- }
239
-
240
- // Success callback
241
- if (failCallback) failCallback(true);
242
-
243
- return true;
244
- };
245
-
246
- // Call API
247
- const result = await this.api.put<LoginResult>(
248
- "Auth/RefreshToken",
249
- rq,
250
- payload
251
- );
252
- if (result == null) return false;
253
-
254
- if (!result.ok) {
255
- if (result.type === "TokenExpired" && relogin) {
256
- // Try login
257
- // Dialog to receive password
258
- var labels = this.getLabels("reloginTip", "login");
259
- this.notifier.prompt(
260
- labels.reloginTip,
261
- async (pwd) => {
262
- if (pwd == null) {
263
- this.toLoginPage();
264
- return;
265
- }
266
-
267
- // Set password for the action
268
- rq.pwd = this.encrypt(this.hash(pwd));
269
-
270
- // Submit again
271
- const result = await this.api.put<LoginResult>(
272
- "Auth/RefreshToken",
273
- rq,
274
- payload
275
- );
276
-
277
- if (result == null) return;
278
-
279
- if (result.ok) {
280
- await success(result, (loginResult: RefreshTokenResult) => {
281
- if (loginResult === true) {
282
- if (callback) callback(true);
283
- return;
284
- }
285
-
286
- const message = this.formatRefreshTokenResult(loginResult);
287
- if (message) this.notifier.alert(message);
288
- });
289
- return;
290
- }
291
-
292
- // Popup message
293
- this.alertResult(result);
294
- return false;
295
- },
296
- labels.login,
297
- { type: "password" }
298
- );
299
-
300
- // Fake truth to avoid reloading
301
- return true;
302
- }
303
-
304
- if (callback) callback(result);
305
- return false;
306
- }
307
-
308
- return await success(result, callback);
111
+ override userLogin(
112
+ user: U,
113
+ refreshToken: string,
114
+ keep?: boolean,
115
+ dispatch?: boolean
116
+ ): void {
117
+ // Super call, set token
118
+ super.userLogin(user, refreshToken, keep, dispatch);
119
+
120
+ // Set service passphrase
121
+ this.servicePassphrase =
122
+ this.decrypt(
123
+ user.servicePassphrase,
124
+ `${user.uid}-${this.settings.appId}`
125
+ ) ?? "";
309
126
  }
310
127
 
311
128
  /**
@@ -332,55 +149,4 @@ export class ServiceApp<
332
149
  iterations
333
150
  );
334
151
  }
335
-
336
- /**
337
- * Try login
338
- * @param data Additional data
339
- * @param showLoading Show loading bar or not
340
- * @returns Result
341
- */
342
- override async tryLogin<D extends object = {}>(
343
- data?: D,
344
- showLoading?: boolean
345
- ) {
346
- // Reset user state
347
- const result = await super.tryLogin(data, showLoading);
348
- if (!result) return false;
349
-
350
- // Refresh token
351
- return await this.refreshToken({
352
- callback: (result) => this.doRefreshTokenResult(result),
353
- data,
354
- showLoading,
355
- relogin: true
356
- });
357
- }
358
-
359
- /**
360
- * User login extended
361
- * @param user Core system user
362
- * @param refreshToken Refresh token
363
- * @param serviceUser Service user
364
- */
365
- userLoginEx(user: ISmartERPUser, refreshToken: string, serviceUser: U) {
366
- // Service user login
367
- this.servicePassphrase =
368
- this.decrypt(
369
- serviceUser.servicePassphrase,
370
- this.settings.serviceId.toString()
371
- ) ?? "";
372
-
373
- // Service user
374
- this.serviceUser = serviceUser;
375
-
376
- // Service API token
377
- this.serviceApi.authorize(
378
- serviceUser.tokenScheme ?? "Bearer",
379
- serviceUser.token
380
- );
381
-
382
- // Keep = true, means service could hold the refresh token for long access
383
- // Trigger Context change and serviceUser is ready then
384
- super.userLogin(user, refreshToken, true);
385
- }
386
152
  }
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./app/CommonApp";
2
- export * from "./app/IAppApi";
3
2
  export * from "./app/IServiceApp";
4
3
  export * from "./app/IServiceAppSettings";
5
4
  export * from "./app/IServicePage";
@@ -1,29 +0,0 @@
1
- import { IApi } from "@etsoo/restclient";
2
- import { ISmartERPUser } from "./ISmartERPUser";
3
- import { RefreshTokenRQ } from "@etsoo/appscript";
4
- import { IServiceUser } from "./IServiceUser";
5
- /**
6
- * Service application API, Implement interface calls between different services
7
- * 服务程序接口,实现不同服务之间的接口调用
8
- */
9
- export interface IAppApi {
10
- /**
11
- * API
12
- */
13
- readonly api: IApi<any>;
14
- /**
15
- * Service id
16
- */
17
- readonly serviceId: number;
18
- /**
19
- * Authorize the API
20
- * @param user SmartERP user
21
- * @param refreshToken SmartERP user refresh token
22
- * @param serviceUser Service user
23
- */
24
- authorize(user: ISmartERPUser, refreshToken: string, serviceUser: IServiceUser): void;
25
- /**
26
- * Get refresh token data
27
- */
28
- getRefreshTokenData(): Partial<RefreshTokenRQ>;
29
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,37 +0,0 @@
1
- import { IApi } from "@etsoo/restclient";
2
- import { ISmartERPUser } from "./ISmartERPUser";
3
- import { RefreshTokenRQ } from "@etsoo/appscript";
4
- import { IServiceUser } from "./IServiceUser";
5
-
6
- /**
7
- * Service application API, Implement interface calls between different services
8
- * 服务程序接口,实现不同服务之间的接口调用
9
- */
10
- export interface IAppApi {
11
- /**
12
- * API
13
- */
14
- readonly api: IApi<any>;
15
-
16
- /**
17
- * Service id
18
- */
19
- readonly serviceId: number;
20
-
21
- /**
22
- * Authorize the API
23
- * @param user SmartERP user
24
- * @param refreshToken SmartERP user refresh token
25
- * @param serviceUser Service user
26
- */
27
- authorize(
28
- user: ISmartERPUser,
29
- refreshToken: string,
30
- serviceUser: IServiceUser
31
- ): void;
32
-
33
- /**
34
- * Get refresh token data
35
- */
36
- getRefreshTokenData(): Partial<RefreshTokenRQ>;
37
- }