@etsoo/react 1.3.40 → 1.3.44
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/lib/app/RefreshTokenRQ.d.ts +8 -0
- package/lib/app/ServiceApp.d.ts +6 -6
- package/lib/app/ServiceApp.js +110 -42
- package/package.json +4 -4
- package/src/app/RefreshTokenRQ.ts +10 -0
- package/src/app/ServiceApp.ts +142 -50
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
* Refresh token request data
|
|
3
3
|
*/
|
|
4
4
|
export declare type RefreshTokenRQ = {
|
|
5
|
+
/**
|
|
6
|
+
* Login password
|
|
7
|
+
*/
|
|
8
|
+
pwd?: string;
|
|
5
9
|
/**
|
|
6
10
|
* Service id
|
|
7
11
|
*/
|
|
8
12
|
serviceId?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Service Uid
|
|
15
|
+
*/
|
|
16
|
+
serviceUid?: string;
|
|
9
17
|
/**
|
|
10
18
|
* Time zone
|
|
11
19
|
*/
|
package/lib/app/ServiceApp.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ApiDataError } from '@etsoo/restclient';
|
|
1
|
+
import { IApi, RefreshTokenProps } from '@etsoo/appscript';
|
|
3
2
|
import { IServiceAppSettings } from './IServiceAppSettings';
|
|
4
3
|
import { IServicePageData } from './IServicePage';
|
|
5
4
|
import { IServiceUser } from './IServiceUser';
|
|
6
5
|
import { ISmartERPUser } from './ISmartERPUser';
|
|
7
6
|
import { ReactApp } from './ReactApp';
|
|
7
|
+
import { RefreshTokenRQ } from './RefreshTokenRQ';
|
|
8
8
|
/**
|
|
9
9
|
* Core Service App
|
|
10
10
|
* Service login to core system, get the refesh token and access token
|
|
@@ -31,14 +31,14 @@ export declare class ServiceApp<P extends IServicePageData = IServicePageData, U
|
|
|
31
31
|
*/
|
|
32
32
|
toLoginPage(): void;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
* @param
|
|
34
|
+
* Refresh token
|
|
35
|
+
* @param props Props
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
refreshToken<D = RefreshTokenRQ>(props?: RefreshTokenProps<D>): Promise<boolean>;
|
|
38
38
|
/**
|
|
39
39
|
* Try login
|
|
40
40
|
*/
|
|
41
|
-
tryLogin(): Promise<boolean>;
|
|
41
|
+
tryLogin<D extends {} = {}>(data?: D): Promise<boolean>;
|
|
42
42
|
/**
|
|
43
43
|
* User login extended
|
|
44
44
|
* @param user New user
|
package/lib/app/ServiceApp.js
CHANGED
|
@@ -41,72 +41,140 @@ export class ServiceApp extends ReactApp {
|
|
|
41
41
|
this.culture;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
* @param
|
|
44
|
+
* Refresh token
|
|
45
|
+
* @param props Props
|
|
46
46
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*/
|
|
51
|
-
async tryLogin() {
|
|
47
|
+
async refreshToken(props) {
|
|
48
|
+
// Destruct
|
|
49
|
+
const { callback, data, relogin = false, showLoading = false } = props !== null && props !== void 0 ? props : {};
|
|
52
50
|
// Token
|
|
53
51
|
const token = this.getCacheToken();
|
|
54
52
|
if (token == null || token === '') {
|
|
55
|
-
|
|
53
|
+
if (callback)
|
|
54
|
+
callback(false);
|
|
56
55
|
return false;
|
|
57
56
|
}
|
|
58
57
|
// Reqest data
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
// Merge additional data passed
|
|
59
|
+
const rq = {
|
|
60
|
+
timezone: this.getTimeZone(),
|
|
61
|
+
...data
|
|
61
62
|
};
|
|
62
63
|
// Payload
|
|
63
64
|
const payload = {
|
|
65
|
+
showLoading,
|
|
64
66
|
config: { headers: { [CoreConstants.TokenHeaderRefresh]: token } },
|
|
65
67
|
onError: (error) => {
|
|
66
|
-
|
|
68
|
+
if (callback)
|
|
69
|
+
callback(error);
|
|
67
70
|
// Prevent further processing
|
|
68
71
|
return false;
|
|
69
72
|
}
|
|
70
73
|
};
|
|
74
|
+
// Success callback
|
|
75
|
+
const success = async (result, failCallback) => {
|
|
76
|
+
// Token
|
|
77
|
+
const refreshToken = this.getResponseToken(payload.response);
|
|
78
|
+
if (refreshToken == null || result.data == null) {
|
|
79
|
+
if (failCallback)
|
|
80
|
+
failCallback(this.get('noData'));
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
// User data
|
|
84
|
+
const userData = result.data;
|
|
85
|
+
// Use core system access token to service api to exchange service access token
|
|
86
|
+
const serviceResult = await this.api.put('Auth/ExchangeToken', {
|
|
87
|
+
token: userData.token
|
|
88
|
+
}, {
|
|
89
|
+
showLoading,
|
|
90
|
+
onError: (error) => {
|
|
91
|
+
if (failCallback)
|
|
92
|
+
failCallback(error);
|
|
93
|
+
// Prevent further processing
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (serviceResult == null)
|
|
98
|
+
return false;
|
|
99
|
+
if (!serviceResult.ok) {
|
|
100
|
+
if (failCallback)
|
|
101
|
+
failCallback(serviceResult);
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (serviceResult.data == null) {
|
|
105
|
+
if (failCallback)
|
|
106
|
+
failCallback(this.get('noData'));
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
this.userLoginEx(serviceResult.data, refreshToken, userData);
|
|
110
|
+
return true;
|
|
111
|
+
};
|
|
71
112
|
// Call API
|
|
72
|
-
const result = await this.coreApi.put('Auth/RefreshToken',
|
|
113
|
+
const result = await this.coreApi.put('Auth/RefreshToken', rq, payload);
|
|
73
114
|
if (result == null)
|
|
74
115
|
return false;
|
|
75
116
|
if (!result.ok) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
if (result.type === 'TokenExpired' && relogin) {
|
|
118
|
+
// Try login
|
|
119
|
+
// Dialog to receive password
|
|
120
|
+
var labels = this.getLabels('reloginTip', 'login');
|
|
121
|
+
this.notifier.prompt(labels.reloginTip, async (pwd) => {
|
|
122
|
+
if (pwd == null) {
|
|
123
|
+
this.toLoginPage();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Set password for the action
|
|
127
|
+
rq.pwd = pwd;
|
|
128
|
+
// Submit again
|
|
129
|
+
const result = await this.api.put('Auth/RefreshToken', data, payload);
|
|
130
|
+
if (result == null)
|
|
131
|
+
return;
|
|
132
|
+
if (result.ok) {
|
|
133
|
+
await success(result, (loginResult) => {
|
|
134
|
+
const message = this.formatRefreshTokenResult(loginResult);
|
|
135
|
+
if (message)
|
|
136
|
+
this.notifier.alert(message);
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Popup message
|
|
141
|
+
this.alertResult(result);
|
|
142
|
+
return false;
|
|
143
|
+
}, labels.login, { type: 'password' });
|
|
144
|
+
// Fake truth to avoid reloading
|
|
145
|
+
return true;
|
|
96
146
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return false;
|
|
100
|
-
if (!serviceResult.ok) {
|
|
101
|
-
this.tryLoginResult(result);
|
|
147
|
+
if (callback)
|
|
148
|
+
callback(result);
|
|
102
149
|
return false;
|
|
103
150
|
}
|
|
104
|
-
|
|
105
|
-
|
|
151
|
+
return await success(result, callback);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Try login
|
|
155
|
+
*/
|
|
156
|
+
async tryLogin(data) {
|
|
157
|
+
// Reset user state
|
|
158
|
+
const result = await super.tryLogin(data);
|
|
159
|
+
if (!result)
|
|
106
160
|
return false;
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
|
|
161
|
+
// Refresh token
|
|
162
|
+
return await this.refreshToken({
|
|
163
|
+
callback: (result) => {
|
|
164
|
+
const message = this.formatRefreshTokenResult(result);
|
|
165
|
+
if (message == null) {
|
|
166
|
+
this.toLoginPage();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.notifier.alert(message, () => {
|
|
171
|
+
this.toLoginPage();
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
data,
|
|
176
|
+
relogin: true
|
|
177
|
+
});
|
|
110
178
|
}
|
|
111
179
|
/**
|
|
112
180
|
* User login extended
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.44",
|
|
4
4
|
"description": "TypeScript ReactJs framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@emotion/react": "^11.7.0",
|
|
51
51
|
"@emotion/style": "^0.8.0",
|
|
52
52
|
"@emotion/styled": "^11.6.0",
|
|
53
|
-
"@etsoo/appscript": "^1.1.
|
|
53
|
+
"@etsoo/appscript": "^1.1.61",
|
|
54
54
|
"@etsoo/notificationbase": "^1.0.94",
|
|
55
55
|
"@etsoo/shared": "^1.0.75",
|
|
56
56
|
"@mui/icons-material": "^5.2.0",
|
|
@@ -83,13 +83,13 @@
|
|
|
83
83
|
"@types/react-test-renderer": "^17.0.1",
|
|
84
84
|
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
|
85
85
|
"@typescript-eslint/parser": "^5.5.0",
|
|
86
|
-
"eslint": "^8.
|
|
86
|
+
"eslint": "^8.4.0",
|
|
87
87
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
88
88
|
"eslint-plugin-import": "^2.25.3",
|
|
89
89
|
"eslint-plugin-react": "^7.27.1",
|
|
90
90
|
"jest": "^27.4.3",
|
|
91
91
|
"react-test-renderer": "^17.0.2",
|
|
92
|
-
"ts-jest": "^27.0
|
|
92
|
+
"ts-jest": "^27.1.0",
|
|
93
93
|
"typescript": "^4.5.2"
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
* Refresh token request data
|
|
3
3
|
*/
|
|
4
4
|
export type RefreshTokenRQ = {
|
|
5
|
+
/**
|
|
6
|
+
* Login password
|
|
7
|
+
*/
|
|
8
|
+
pwd?: string;
|
|
9
|
+
|
|
5
10
|
/**
|
|
6
11
|
* Service id
|
|
7
12
|
*/
|
|
8
13
|
serviceId?: number;
|
|
9
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Service Uid
|
|
17
|
+
*/
|
|
18
|
+
serviceUid?: string;
|
|
19
|
+
|
|
10
20
|
/**
|
|
11
21
|
* Time zone
|
|
12
22
|
*/
|
package/src/app/ServiceApp.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createClient,
|
|
3
|
-
IActionResult,
|
|
4
3
|
IApi,
|
|
5
|
-
IApiPayload
|
|
4
|
+
IApiPayload,
|
|
5
|
+
RefreshTokenProps,
|
|
6
|
+
RefreshTokenResult
|
|
6
7
|
} from '@etsoo/appscript';
|
|
7
|
-
import { ApiDataError } from '@etsoo/restclient';
|
|
8
8
|
import { DomUtils } from '@etsoo/shared';
|
|
9
9
|
import { CoreConstants } from './CoreConstants';
|
|
10
10
|
import { IServiceAppSettings } from './IServiceAppSettings';
|
|
@@ -72,93 +72,185 @@ export class ServiceApp<
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
76
|
-
* @param
|
|
75
|
+
* Refresh token
|
|
76
|
+
* @param props Props
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
override async refreshToken<D = RefreshTokenRQ>(
|
|
79
|
+
props?: RefreshTokenProps<D>
|
|
80
|
+
) {
|
|
81
|
+
// Destruct
|
|
82
|
+
const {
|
|
83
|
+
callback,
|
|
84
|
+
data,
|
|
85
|
+
relogin = false,
|
|
86
|
+
showLoading = false
|
|
87
|
+
} = props ?? {};
|
|
79
88
|
|
|
80
|
-
/**
|
|
81
|
-
* Try login
|
|
82
|
-
*/
|
|
83
|
-
override async tryLogin() {
|
|
84
89
|
// Token
|
|
85
90
|
const token = this.getCacheToken();
|
|
86
91
|
if (token == null || token === '') {
|
|
87
|
-
|
|
92
|
+
if (callback) callback(false);
|
|
88
93
|
return false;
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
// Reqest data
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
// Merge additional data passed
|
|
98
|
+
const rq: RefreshTokenRQ = {
|
|
99
|
+
timezone: this.getTimeZone(),
|
|
100
|
+
...data
|
|
94
101
|
};
|
|
95
102
|
|
|
96
103
|
// Payload
|
|
97
104
|
const payload: IApiPayload<SmartERPLoginResult, any> = {
|
|
105
|
+
showLoading,
|
|
98
106
|
config: { headers: { [CoreConstants.TokenHeaderRefresh]: token } },
|
|
99
107
|
onError: (error) => {
|
|
100
|
-
|
|
108
|
+
if (callback) callback(error);
|
|
101
109
|
|
|
102
110
|
// Prevent further processing
|
|
103
111
|
return false;
|
|
104
112
|
}
|
|
105
113
|
};
|
|
106
114
|
|
|
115
|
+
// Success callback
|
|
116
|
+
const success = async (
|
|
117
|
+
result: SmartERPLoginResult,
|
|
118
|
+
failCallback?: (result: RefreshTokenResult) => void
|
|
119
|
+
) => {
|
|
120
|
+
// Token
|
|
121
|
+
const refreshToken = this.getResponseToken(payload.response);
|
|
122
|
+
if (refreshToken == null || result.data == null) {
|
|
123
|
+
if (failCallback) failCallback(this.get('noData')!);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// User data
|
|
128
|
+
const userData = result.data;
|
|
129
|
+
|
|
130
|
+
// Use core system access token to service api to exchange service access token
|
|
131
|
+
const serviceResult = await this.api.put<ServiceLoginResult>(
|
|
132
|
+
'Auth/ExchangeToken',
|
|
133
|
+
{
|
|
134
|
+
token: userData.token
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
showLoading,
|
|
138
|
+
onError: (error) => {
|
|
139
|
+
if (failCallback) failCallback(error);
|
|
140
|
+
|
|
141
|
+
// Prevent further processing
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (serviceResult == null) return false;
|
|
148
|
+
|
|
149
|
+
if (!serviceResult.ok) {
|
|
150
|
+
if (failCallback) failCallback(serviceResult);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (serviceResult.data == null) {
|
|
155
|
+
if (failCallback) failCallback(this.get('noData')!);
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
this.userLoginEx(serviceResult.data, refreshToken, userData);
|
|
160
|
+
|
|
161
|
+
return true;
|
|
162
|
+
};
|
|
163
|
+
|
|
107
164
|
// Call API
|
|
108
165
|
const result = await this.coreApi.put<SmartERPLoginResult>(
|
|
109
166
|
'Auth/RefreshToken',
|
|
110
|
-
|
|
167
|
+
rq,
|
|
111
168
|
payload
|
|
112
169
|
);
|
|
113
170
|
if (result == null) return false;
|
|
114
171
|
|
|
115
172
|
if (!result.ok) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
173
|
+
if (result.type === 'TokenExpired' && relogin) {
|
|
174
|
+
// Try login
|
|
175
|
+
// Dialog to receive password
|
|
176
|
+
var labels = this.getLabels('reloginTip', 'login');
|
|
177
|
+
this.notifier.prompt(
|
|
178
|
+
labels.reloginTip,
|
|
179
|
+
async (pwd) => {
|
|
180
|
+
if (pwd == null) {
|
|
181
|
+
this.toLoginPage();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
119
184
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (refreshToken == null || result.data == null) {
|
|
123
|
-
this.tryLoginResult(this.get('noData')!);
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
185
|
+
// Set password for the action
|
|
186
|
+
rq.pwd = pwd;
|
|
126
187
|
|
|
127
|
-
|
|
128
|
-
|
|
188
|
+
// Submit again
|
|
189
|
+
const result = await this.api.put<SmartERPLoginResult>(
|
|
190
|
+
'Auth/RefreshToken',
|
|
191
|
+
data,
|
|
192
|
+
payload
|
|
193
|
+
);
|
|
129
194
|
|
|
130
|
-
|
|
131
|
-
const serviceResult = await this.api.put<ServiceLoginResult>(
|
|
132
|
-
'Auth/ExchangeToken',
|
|
133
|
-
{
|
|
134
|
-
token: userData.token
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
onError: (error) => {
|
|
138
|
-
// Set message
|
|
139
|
-
this.tryLoginResult(error);
|
|
195
|
+
if (result == null) return;
|
|
140
196
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
197
|
+
if (result.ok) {
|
|
198
|
+
await success(
|
|
199
|
+
result,
|
|
200
|
+
(loginResult: RefreshTokenResult) => {
|
|
201
|
+
const message =
|
|
202
|
+
this.formatRefreshTokenResult(
|
|
203
|
+
loginResult
|
|
204
|
+
);
|
|
205
|
+
if (message) this.notifier.alert(message);
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
146
210
|
|
|
147
|
-
|
|
211
|
+
// Popup message
|
|
212
|
+
this.alertResult(result);
|
|
213
|
+
return false;
|
|
214
|
+
},
|
|
215
|
+
labels.login,
|
|
216
|
+
{ type: 'password' }
|
|
217
|
+
);
|
|
148
218
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
219
|
+
// Fake truth to avoid reloading
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
153
222
|
|
|
154
|
-
|
|
155
|
-
this.tryLoginResult(this.get('noData')!);
|
|
223
|
+
if (callback) callback(result);
|
|
156
224
|
return false;
|
|
157
225
|
}
|
|
158
226
|
|
|
159
|
-
|
|
227
|
+
return await success(result, callback);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Try login
|
|
232
|
+
*/
|
|
233
|
+
override async tryLogin<D extends {} = {}>(data?: D) {
|
|
234
|
+
// Reset user state
|
|
235
|
+
const result = await super.tryLogin(data);
|
|
236
|
+
if (!result) return false;
|
|
160
237
|
|
|
161
|
-
|
|
238
|
+
// Refresh token
|
|
239
|
+
return await this.refreshToken({
|
|
240
|
+
callback: (result) => {
|
|
241
|
+
const message = this.formatRefreshTokenResult(result);
|
|
242
|
+
if (message == null) {
|
|
243
|
+
this.toLoginPage();
|
|
244
|
+
return;
|
|
245
|
+
} else {
|
|
246
|
+
this.notifier.alert(message, () => {
|
|
247
|
+
this.toLoginPage();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
data,
|
|
252
|
+
relogin: true
|
|
253
|
+
});
|
|
162
254
|
}
|
|
163
255
|
|
|
164
256
|
/**
|