@etsoo/appscript 1.1.83 → 1.1.87

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.
@@ -129,6 +129,17 @@ test('Tests for encrypt / decrypt', () => {
129
129
  expect(plain).toEqual(input);
130
130
  });
131
131
 
132
+ test('Tests for encryptEnhanced / decryptEnhanced', () => {
133
+ // Arrange
134
+ const input = 'Hello, world!';
135
+ const passphrase = 'My password';
136
+
137
+ // Act
138
+ const encrypted = app.encryptEnhanced(input, passphrase);
139
+ const plain = app.decryptEnhanced(encrypted, passphrase);
140
+ expect(plain).toEqual(input);
141
+ });
142
+
132
143
  test('Tests for initCallUpdateLocal', () => {
133
144
  // Act
134
145
  const passphrase = app.initCallUpdateLocal(
@@ -2,6 +2,7 @@ import { INotifier, NotificationAlign, NotificationCallProps, NotificationConten
2
2
  import { ApiDataError, IApi, IPData } from '@etsoo/restclient';
3
3
  import { DataTypes, DateUtils } from '@etsoo/shared';
4
4
  import { AddressRegion } from '../address/AddressRegion';
5
+ import { IdLabelDto } from '../dto/IdLabelDto';
5
6
  import { InitCallDto } from '../dto/InitCallDto';
6
7
  import { IActionResult } from '../result/IActionResult';
7
8
  import { InitCallResult, InitCallResultData } from '../result/InitCallResult';
@@ -118,6 +119,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
119
  * @param culture New culture definition
119
120
  */
120
121
  changeCulture(culture: DataTypes.CultureDefinition): void;
122
+ /**
123
+ * Clear cache data
124
+ */
125
+ clearCacheData(): void;
121
126
  /**
122
127
  * Clear cached token
123
128
  */
@@ -221,7 +226,7 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
221
226
  * Get cached token
222
227
  * @returns Cached token
223
228
  */
224
- getCacheToken(): string | null;
229
+ getCacheToken(): string | undefined;
225
230
  /**
226
231
  * Get all regions
227
232
  * @returns Regions
@@ -278,6 +283,13 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
278
283
  * @param apiUrl Signout API URL
279
284
  */
280
285
  signout(apiUrl?: string): Promise<void>;
286
+ /**
287
+ * Get organization list
288
+ * @param items Max items
289
+ * @param serviceId Service id
290
+ * @returns Result
291
+ */
292
+ orgList(items?: number, serviceId?: number): Promise<IdLabelDto[] | undefined>;
281
293
  /**
282
294
  * Switch organization
283
295
  * @param apiOrOrg API URL or organization id
@@ -367,18 +379,26 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
367
379
  * Label delegate
368
380
  */
369
381
  get labelDelegate(): <T = string>(key: string) => T | undefined;
382
+ private _ipData?;
370
383
  /**
371
384
  * IP data
372
385
  */
373
- ipData?: IPData;
386
+ get ipData(): IPData | undefined;
387
+ protected set ipData(value: IPData | undefined);
388
+ private _userData?;
374
389
  /**
375
390
  * User data
376
391
  */
377
- userData?: IUserData;
392
+ get userData(): IUserData | undefined;
393
+ protected set userData(value: IUserData | undefined);
378
394
  /**
379
395
  * Response token header field name
380
396
  */
381
- headerTokenField: string;
397
+ readonly headerTokenField = "SmartERPRefreshToken";
398
+ /**
399
+ * Serverside device id encrypted field name
400
+ */
401
+ protected readonly serversideDeviceIdField = "SmartERPServersideDeviceId";
382
402
  private ipDetectCallbacks?;
383
403
  /**
384
404
  * Search input element
@@ -402,7 +422,11 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
402
422
  /**
403
423
  * Device id field name
404
424
  */
405
- protected deviceIdField: string;
425
+ protected readonly deviceIdField: string;
426
+ /**
427
+ * Device id update time field name
428
+ */
429
+ protected readonly deviceIdUpdateTimeField: string;
406
430
  /**
407
431
  * Init call Api URL
408
432
  */
@@ -427,6 +451,11 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
427
451
  * @returns Result
428
452
  */
429
453
  protected apiInitCall(data: InitCallDto): Promise<InitCallResult | undefined>;
454
+ /**
455
+ * Get device last updte miliseconds
456
+ * @returns Miliseconds
457
+ */
458
+ protected getDeviceUpdateTime(): number;
430
459
  /**
431
460
  * Init call
432
461
  * @param callback Callback
@@ -465,6 +494,10 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
465
494
  * @param culture New culture definition
466
495
  */
467
496
  changeCulture(culture: DataTypes.CultureDefinition): void;
497
+ /**
498
+ * Clear cache data
499
+ */
500
+ clearCacheData(): void;
468
501
  /**
469
502
  * Clear cached token
470
503
  */
@@ -571,7 +604,7 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
571
604
  * Get cached token
572
605
  * @returns Cached token
573
606
  */
574
- getCacheToken(): string | null;
607
+ getCacheToken(): string | undefined;
575
608
  /**
576
609
  * Get all regions
577
610
  * @returns Regions
@@ -637,11 +670,18 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
637
670
  * @param apiUrl Signout API URL
638
671
  */
639
672
  signout(apiUrl?: string): Promise<void>;
673
+ /**
674
+ * Get organization list
675
+ * @param items Max items
676
+ * @param serviceId Service id
677
+ * @returns Result
678
+ */
679
+ orgList(items?: number, serviceId?: number): Promise<IdLabelDto<number>[] | undefined>;
640
680
  /**
641
681
  * Switch organization
642
- * @param apiOrOrg API URL or organization id
682
+ * @param id Organization id
643
683
  */
644
- switchOrg(apiOrOrg: string | number): Promise<boolean | undefined>;
684
+ switchOrg(id: number): Promise<boolean | undefined>;
645
685
  /**
646
686
  * Go to the login page
647
687
  */
@@ -20,11 +20,15 @@ class CoreApp {
20
20
  * @param name Application name
21
21
  */
22
22
  constructor(settings, api, notifier, name) {
23
- this._deviceId = '***';
23
+ this._deviceId = '';
24
24
  /**
25
25
  * Response token header field name
26
26
  */
27
27
  this.headerTokenField = 'SmartERPRefreshToken';
28
+ /**
29
+ * Serverside device id encrypted field name
30
+ */
31
+ this.serversideDeviceIdField = 'SmartERPServersideDeviceId';
28
32
  this._authorized = false;
29
33
  this._isTryingLogin = false;
30
34
  /**
@@ -39,6 +43,10 @@ class CoreApp {
39
43
  * Device id field name
40
44
  */
41
45
  this.deviceIdField = 'SmartERPDeviceId';
46
+ /**
47
+ * Device id update time field name
48
+ */
49
+ this.deviceIdUpdateTimeField = 'SmartERPDeviceIdUpdateTime';
42
50
  /**
43
51
  * Init call Api URL
44
52
  */
@@ -92,6 +100,24 @@ class CoreApp {
92
100
  get labelDelegate() {
93
101
  return this.get.bind(this);
94
102
  }
103
+ /**
104
+ * IP data
105
+ */
106
+ get ipData() {
107
+ return this._ipData;
108
+ }
109
+ set ipData(value) {
110
+ this._ipData = value;
111
+ }
112
+ /**
113
+ * User data
114
+ */
115
+ get userData() {
116
+ return this._userData;
117
+ }
118
+ set userData(value) {
119
+ this._userData = value;
120
+ }
95
121
  /**
96
122
  * Is current authorized
97
123
  */
@@ -139,6 +165,13 @@ class CoreApp {
139
165
  async apiInitCall(data) {
140
166
  return await this.api.put(this.initCallApi, data);
141
167
  }
168
+ /**
169
+ * Get device last updte miliseconds
170
+ * @returns Miliseconds
171
+ */
172
+ getDeviceUpdateTime() {
173
+ return shared_1.StorageUtils.getLocalData(this.deviceIdUpdateTimeField, 0);
174
+ }
142
175
  /**
143
176
  * Init call
144
177
  * @param callback Callback
@@ -146,9 +179,24 @@ class CoreApp {
146
179
  */
147
180
  async initCall(callback) {
148
181
  var _a;
182
+ // Device
183
+ let hasDeviceId = this.deviceId != null && this.deviceId !== '';
184
+ const timestamp = new Date().getTime();
185
+ const lastTimestamp = this.getDeviceUpdateTime();
186
+ if (hasDeviceId &&
187
+ lastTimestamp > 0 &&
188
+ timestamp - lastTimestamp <= 1296000000) {
189
+ // When deviceId is there and less than 15 days = 1000 * 60 * 60 * 24 * 15
190
+ if (callback)
191
+ callback(true);
192
+ return;
193
+ }
194
+ // Serverside encrypted device id
195
+ const identifier = shared_1.StorageUtils.getLocalData(this.serversideDeviceIdField);
149
196
  const data = {
150
- timestamp: new Date().getTime(),
151
- deviceId: this.deviceId === '' ? undefined : this.deviceId
197
+ timestamp,
198
+ identifier,
199
+ deviceId: hasDeviceId ? this.deviceId : undefined
152
200
  };
153
201
  const result = await this.apiInitCall(data);
154
202
  if (result == null) {
@@ -200,6 +248,7 @@ class CoreApp {
200
248
  // Update device id and cache it
201
249
  this.deviceId = data.deviceId;
202
250
  shared_1.StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
251
+ shared_1.StorageUtils.setLocalData(this.deviceIdUpdateTimeField, timestamp);
203
252
  // Current passphrase
204
253
  this.passphrase = passphrase;
205
254
  // Previous passphrase
@@ -208,8 +257,8 @@ class CoreApp {
208
257
  // Update
209
258
  const fields = this.initCallUpdateFields();
210
259
  for (const field of fields) {
211
- const currentValue = shared_1.StorageUtils.getLocalData(field, '');
212
- if (currentValue === '')
260
+ const currentValue = shared_1.StorageUtils.getLocalData(field);
261
+ if (currentValue == null || currentValue === '')
213
262
  continue;
214
263
  const enhanced = currentValue.indexOf('!') >= 8;
215
264
  let newValueSource = null;
@@ -325,6 +374,15 @@ class CoreApp {
325
374
  region.name = AddressUtils_1.AddressUtils.getRegionLabel(id, this.labelDelegate);
326
375
  });
327
376
  }
377
+ /**
378
+ * Clear cache data
379
+ */
380
+ clearCacheData() {
381
+ shared_1.StorageUtils.setLocalData(this.serversideDeviceIdField, undefined);
382
+ shared_1.StorageUtils.setLocalData(this.deviceIdField, undefined);
383
+ shared_1.StorageUtils.setLocalData(this.deviceIdUpdateTimeField, undefined);
384
+ shared_1.StorageUtils.setLocalData(this.headerTokenField, undefined);
385
+ }
328
386
  /**
329
387
  * Clear cached token
330
388
  */
@@ -578,10 +636,7 @@ class CoreApp {
578
636
  // Temp refresh token
579
637
  if (this.cachedRefreshToken)
580
638
  return this.cachedRefreshToken;
581
- const refreshToken = shared_1.StorageUtils.getLocalData(this.headerTokenField, '');
582
- if (refreshToken === '')
583
- return null;
584
- return refreshToken;
639
+ return shared_1.StorageUtils.getLocalData(this.headerTokenField);
585
640
  }
586
641
  /**
587
642
  * Get all regions
@@ -723,14 +778,24 @@ class CoreApp {
723
778
  // Go to login page
724
779
  this.toLoginPage();
725
780
  }
781
+ /**
782
+ * Get organization list
783
+ * @param items Max items
784
+ * @param serviceId Service id
785
+ * @returns Result
786
+ */
787
+ async orgList(items, serviceId) {
788
+ return await this.api.post('Organization/List', {
789
+ items,
790
+ serviceId
791
+ }, { defaultValue: [], showLoading: false });
792
+ }
726
793
  /**
727
794
  * Switch organization
728
- * @param apiOrOrg API URL or organization id
795
+ * @param id Organization id
729
796
  */
730
- async switchOrg(apiOrOrg) {
731
- const api = typeof apiOrOrg === 'number'
732
- ? `Organization/Switch/${apiOrOrg}`
733
- : apiOrOrg;
797
+ async switchOrg(id) {
798
+ const api = `Organization/Switch/${id}`;
734
799
  const result = await this.api.put(api);
735
800
  if (result)
736
801
  return await this.refreshToken();
@@ -783,6 +848,8 @@ class CoreApp {
783
848
  */
784
849
  userLogin(user, refreshToken, keep) {
785
850
  this.userData = user;
851
+ // Cache the encrypted serverside device id
852
+ shared_1.StorageUtils.setLocalData(this.serversideDeviceIdField, user.deviceId);
786
853
  if (keep) {
787
854
  this.authorize(user.token, refreshToken);
788
855
  }
@@ -3,25 +3,25 @@
3
3
  */
4
4
  export interface IExternalSettings {
5
5
  /**
6
- * API endpoint
6
+ * Core system API endpoint
7
7
  */
8
8
  readonly endpoint: string;
9
9
  /**
10
- * App root url
10
+ * Core system app root url
11
11
  */
12
12
  readonly homepage: string;
13
13
  /**
14
- * Cloud web url
14
+ * Core system web url
15
15
  */
16
16
  readonly webUrl: string;
17
17
  /**
18
- * Core system Url
18
+ * Service API endpoint
19
19
  */
20
- readonly coreUrl?: string;
20
+ readonly serviceEndpoint?: string;
21
21
  /**
22
- * Core system API
22
+ * Service web Url
23
23
  */
24
- readonly coreApi?: string;
24
+ readonly serviceUrl?: string;
25
25
  }
26
26
  /**
27
27
  * External settings namespace
@@ -6,6 +6,10 @@ export declare type InitCallDto = {
6
6
  * Device id
7
7
  */
8
8
  deviceId?: string;
9
+ /**
10
+ * Serverside identifier
11
+ */
12
+ identifier?: string;
9
13
  /**
10
14
  * Timestamp
11
15
  */
@@ -3,6 +3,10 @@ import { IState } from './State';
3
3
  * User data interface
4
4
  */
5
5
  export interface IUserData {
6
+ /**
7
+ * Serverside device id encrypted
8
+ */
9
+ readonly deviceId: string;
6
10
  /**
7
11
  * User name
8
12
  */
@@ -2,6 +2,7 @@ import { INotifier, NotificationAlign, NotificationCallProps, NotificationConten
2
2
  import { ApiDataError, IApi, IPData } from '@etsoo/restclient';
3
3
  import { DataTypes, DateUtils } from '@etsoo/shared';
4
4
  import { AddressRegion } from '../address/AddressRegion';
5
+ import { IdLabelDto } from '../dto/IdLabelDto';
5
6
  import { InitCallDto } from '../dto/InitCallDto';
6
7
  import { IActionResult } from '../result/IActionResult';
7
8
  import { InitCallResult, InitCallResultData } from '../result/InitCallResult';
@@ -118,6 +119,10 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
118
119
  * @param culture New culture definition
119
120
  */
120
121
  changeCulture(culture: DataTypes.CultureDefinition): void;
122
+ /**
123
+ * Clear cache data
124
+ */
125
+ clearCacheData(): void;
121
126
  /**
122
127
  * Clear cached token
123
128
  */
@@ -221,7 +226,7 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
221
226
  * Get cached token
222
227
  * @returns Cached token
223
228
  */
224
- getCacheToken(): string | null;
229
+ getCacheToken(): string | undefined;
225
230
  /**
226
231
  * Get all regions
227
232
  * @returns Regions
@@ -278,6 +283,13 @@ export interface ICoreApp<S extends IAppSettings, N, C extends NotificationCallP
278
283
  * @param apiUrl Signout API URL
279
284
  */
280
285
  signout(apiUrl?: string): Promise<void>;
286
+ /**
287
+ * Get organization list
288
+ * @param items Max items
289
+ * @param serviceId Service id
290
+ * @returns Result
291
+ */
292
+ orgList(items?: number, serviceId?: number): Promise<IdLabelDto[] | undefined>;
281
293
  /**
282
294
  * Switch organization
283
295
  * @param apiOrOrg API URL or organization id
@@ -367,18 +379,26 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
367
379
  * Label delegate
368
380
  */
369
381
  get labelDelegate(): <T = string>(key: string) => T | undefined;
382
+ private _ipData?;
370
383
  /**
371
384
  * IP data
372
385
  */
373
- ipData?: IPData;
386
+ get ipData(): IPData | undefined;
387
+ protected set ipData(value: IPData | undefined);
388
+ private _userData?;
374
389
  /**
375
390
  * User data
376
391
  */
377
- userData?: IUserData;
392
+ get userData(): IUserData | undefined;
393
+ protected set userData(value: IUserData | undefined);
378
394
  /**
379
395
  * Response token header field name
380
396
  */
381
- headerTokenField: string;
397
+ readonly headerTokenField = "SmartERPRefreshToken";
398
+ /**
399
+ * Serverside device id encrypted field name
400
+ */
401
+ protected readonly serversideDeviceIdField = "SmartERPServersideDeviceId";
382
402
  private ipDetectCallbacks?;
383
403
  /**
384
404
  * Search input element
@@ -402,7 +422,11 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
402
422
  /**
403
423
  * Device id field name
404
424
  */
405
- protected deviceIdField: string;
425
+ protected readonly deviceIdField: string;
426
+ /**
427
+ * Device id update time field name
428
+ */
429
+ protected readonly deviceIdUpdateTimeField: string;
406
430
  /**
407
431
  * Init call Api URL
408
432
  */
@@ -427,6 +451,11 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
427
451
  * @returns Result
428
452
  */
429
453
  protected apiInitCall(data: InitCallDto): Promise<InitCallResult | undefined>;
454
+ /**
455
+ * Get device last updte miliseconds
456
+ * @returns Miliseconds
457
+ */
458
+ protected getDeviceUpdateTime(): number;
430
459
  /**
431
460
  * Init call
432
461
  * @param callback Callback
@@ -465,6 +494,10 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
465
494
  * @param culture New culture definition
466
495
  */
467
496
  changeCulture(culture: DataTypes.CultureDefinition): void;
497
+ /**
498
+ * Clear cache data
499
+ */
500
+ clearCacheData(): void;
468
501
  /**
469
502
  * Clear cached token
470
503
  */
@@ -571,7 +604,7 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
571
604
  * Get cached token
572
605
  * @returns Cached token
573
606
  */
574
- getCacheToken(): string | null;
607
+ getCacheToken(): string | undefined;
575
608
  /**
576
609
  * Get all regions
577
610
  * @returns Regions
@@ -637,11 +670,18 @@ export declare abstract class CoreApp<S extends IAppSettings, N, C extends Notif
637
670
  * @param apiUrl Signout API URL
638
671
  */
639
672
  signout(apiUrl?: string): Promise<void>;
673
+ /**
674
+ * Get organization list
675
+ * @param items Max items
676
+ * @param serviceId Service id
677
+ * @returns Result
678
+ */
679
+ orgList(items?: number, serviceId?: number): Promise<IdLabelDto<number>[] | undefined>;
640
680
  /**
641
681
  * Switch organization
642
- * @param apiOrOrg API URL or organization id
682
+ * @param id Organization id
643
683
  */
644
- switchOrg(apiOrOrg: string | number): Promise<boolean | undefined>;
684
+ switchOrg(id: number): Promise<boolean | undefined>;
645
685
  /**
646
686
  * Go to the login page
647
687
  */
@@ -17,11 +17,15 @@ export class CoreApp {
17
17
  * @param name Application name
18
18
  */
19
19
  constructor(settings, api, notifier, name) {
20
- this._deviceId = '***';
20
+ this._deviceId = '';
21
21
  /**
22
22
  * Response token header field name
23
23
  */
24
24
  this.headerTokenField = 'SmartERPRefreshToken';
25
+ /**
26
+ * Serverside device id encrypted field name
27
+ */
28
+ this.serversideDeviceIdField = 'SmartERPServersideDeviceId';
25
29
  this._authorized = false;
26
30
  this._isTryingLogin = false;
27
31
  /**
@@ -36,6 +40,10 @@ export class CoreApp {
36
40
  * Device id field name
37
41
  */
38
42
  this.deviceIdField = 'SmartERPDeviceId';
43
+ /**
44
+ * Device id update time field name
45
+ */
46
+ this.deviceIdUpdateTimeField = 'SmartERPDeviceIdUpdateTime';
39
47
  /**
40
48
  * Init call Api URL
41
49
  */
@@ -89,6 +97,24 @@ export class CoreApp {
89
97
  get labelDelegate() {
90
98
  return this.get.bind(this);
91
99
  }
100
+ /**
101
+ * IP data
102
+ */
103
+ get ipData() {
104
+ return this._ipData;
105
+ }
106
+ set ipData(value) {
107
+ this._ipData = value;
108
+ }
109
+ /**
110
+ * User data
111
+ */
112
+ get userData() {
113
+ return this._userData;
114
+ }
115
+ set userData(value) {
116
+ this._userData = value;
117
+ }
92
118
  /**
93
119
  * Is current authorized
94
120
  */
@@ -136,6 +162,13 @@ export class CoreApp {
136
162
  async apiInitCall(data) {
137
163
  return await this.api.put(this.initCallApi, data);
138
164
  }
165
+ /**
166
+ * Get device last updte miliseconds
167
+ * @returns Miliseconds
168
+ */
169
+ getDeviceUpdateTime() {
170
+ return StorageUtils.getLocalData(this.deviceIdUpdateTimeField, 0);
171
+ }
139
172
  /**
140
173
  * Init call
141
174
  * @param callback Callback
@@ -143,9 +176,24 @@ export class CoreApp {
143
176
  */
144
177
  async initCall(callback) {
145
178
  var _a;
179
+ // Device
180
+ let hasDeviceId = this.deviceId != null && this.deviceId !== '';
181
+ const timestamp = new Date().getTime();
182
+ const lastTimestamp = this.getDeviceUpdateTime();
183
+ if (hasDeviceId &&
184
+ lastTimestamp > 0 &&
185
+ timestamp - lastTimestamp <= 1296000000) {
186
+ // When deviceId is there and less than 15 days = 1000 * 60 * 60 * 24 * 15
187
+ if (callback)
188
+ callback(true);
189
+ return;
190
+ }
191
+ // Serverside encrypted device id
192
+ const identifier = StorageUtils.getLocalData(this.serversideDeviceIdField);
146
193
  const data = {
147
- timestamp: new Date().getTime(),
148
- deviceId: this.deviceId === '' ? undefined : this.deviceId
194
+ timestamp,
195
+ identifier,
196
+ deviceId: hasDeviceId ? this.deviceId : undefined
149
197
  };
150
198
  const result = await this.apiInitCall(data);
151
199
  if (result == null) {
@@ -197,6 +245,7 @@ export class CoreApp {
197
245
  // Update device id and cache it
198
246
  this.deviceId = data.deviceId;
199
247
  StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
248
+ StorageUtils.setLocalData(this.deviceIdUpdateTimeField, timestamp);
200
249
  // Current passphrase
201
250
  this.passphrase = passphrase;
202
251
  // Previous passphrase
@@ -205,8 +254,8 @@ export class CoreApp {
205
254
  // Update
206
255
  const fields = this.initCallUpdateFields();
207
256
  for (const field of fields) {
208
- const currentValue = StorageUtils.getLocalData(field, '');
209
- if (currentValue === '')
257
+ const currentValue = StorageUtils.getLocalData(field);
258
+ if (currentValue == null || currentValue === '')
210
259
  continue;
211
260
  const enhanced = currentValue.indexOf('!') >= 8;
212
261
  let newValueSource = null;
@@ -322,6 +371,15 @@ export class CoreApp {
322
371
  region.name = AddressUtils.getRegionLabel(id, this.labelDelegate);
323
372
  });
324
373
  }
374
+ /**
375
+ * Clear cache data
376
+ */
377
+ clearCacheData() {
378
+ StorageUtils.setLocalData(this.serversideDeviceIdField, undefined);
379
+ StorageUtils.setLocalData(this.deviceIdField, undefined);
380
+ StorageUtils.setLocalData(this.deviceIdUpdateTimeField, undefined);
381
+ StorageUtils.setLocalData(this.headerTokenField, undefined);
382
+ }
325
383
  /**
326
384
  * Clear cached token
327
385
  */
@@ -575,10 +633,7 @@ export class CoreApp {
575
633
  // Temp refresh token
576
634
  if (this.cachedRefreshToken)
577
635
  return this.cachedRefreshToken;
578
- const refreshToken = StorageUtils.getLocalData(this.headerTokenField, '');
579
- if (refreshToken === '')
580
- return null;
581
- return refreshToken;
636
+ return StorageUtils.getLocalData(this.headerTokenField);
582
637
  }
583
638
  /**
584
639
  * Get all regions
@@ -720,14 +775,24 @@ export class CoreApp {
720
775
  // Go to login page
721
776
  this.toLoginPage();
722
777
  }
778
+ /**
779
+ * Get organization list
780
+ * @param items Max items
781
+ * @param serviceId Service id
782
+ * @returns Result
783
+ */
784
+ async orgList(items, serviceId) {
785
+ return await this.api.post('Organization/List', {
786
+ items,
787
+ serviceId
788
+ }, { defaultValue: [], showLoading: false });
789
+ }
723
790
  /**
724
791
  * Switch organization
725
- * @param apiOrOrg API URL or organization id
792
+ * @param id Organization id
726
793
  */
727
- async switchOrg(apiOrOrg) {
728
- const api = typeof apiOrOrg === 'number'
729
- ? `Organization/Switch/${apiOrOrg}`
730
- : apiOrOrg;
794
+ async switchOrg(id) {
795
+ const api = `Organization/Switch/${id}`;
731
796
  const result = await this.api.put(api);
732
797
  if (result)
733
798
  return await this.refreshToken();
@@ -780,6 +845,8 @@ export class CoreApp {
780
845
  */
781
846
  userLogin(user, refreshToken, keep) {
782
847
  this.userData = user;
848
+ // Cache the encrypted serverside device id
849
+ StorageUtils.setLocalData(this.serversideDeviceIdField, user.deviceId);
783
850
  if (keep) {
784
851
  this.authorize(user.token, refreshToken);
785
852
  }
@@ -3,25 +3,25 @@
3
3
  */
4
4
  export interface IExternalSettings {
5
5
  /**
6
- * API endpoint
6
+ * Core system API endpoint
7
7
  */
8
8
  readonly endpoint: string;
9
9
  /**
10
- * App root url
10
+ * Core system app root url
11
11
  */
12
12
  readonly homepage: string;
13
13
  /**
14
- * Cloud web url
14
+ * Core system web url
15
15
  */
16
16
  readonly webUrl: string;
17
17
  /**
18
- * Core system Url
18
+ * Service API endpoint
19
19
  */
20
- readonly coreUrl?: string;
20
+ readonly serviceEndpoint?: string;
21
21
  /**
22
- * Core system API
22
+ * Service web Url
23
23
  */
24
- readonly coreApi?: string;
24
+ readonly serviceUrl?: string;
25
25
  }
26
26
  /**
27
27
  * External settings namespace
@@ -6,6 +6,10 @@ export declare type InitCallDto = {
6
6
  * Device id
7
7
  */
8
8
  deviceId?: string;
9
+ /**
10
+ * Serverside identifier
11
+ */
12
+ identifier?: string;
9
13
  /**
10
14
  * Timestamp
11
15
  */
@@ -3,6 +3,10 @@ import { IState } from './State';
3
3
  * User data interface
4
4
  */
5
5
  export interface IUserData {
6
+ /**
7
+ * Serverside device id encrypted
8
+ */
9
+ readonly deviceId: string;
6
10
  /**
7
11
  * User name
8
12
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.1.83",
3
+ "version": "1.1.87",
4
4
  "description": "Applications shared TypeScript framework",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -52,9 +52,9 @@
52
52
  },
53
53
  "homepage": "https://github.com/ETSOO/AppScript#readme",
54
54
  "dependencies": {
55
- "@etsoo/notificationbase": "^1.0.94",
56
- "@etsoo/restclient": "^1.0.62",
57
- "@etsoo/shared": "^1.0.78",
55
+ "@etsoo/notificationbase": "^1.0.95",
56
+ "@etsoo/restclient": "^1.0.63",
57
+ "@etsoo/shared": "^1.0.82",
58
58
  "@types/crypto-js": "^4.0.2",
59
59
  "crypto-js": "^4.1.1"
60
60
  },
@@ -65,8 +65,8 @@
65
65
  "@babel/preset-env": "^7.16.5",
66
66
  "@babel/runtime-corejs3": "^7.16.5",
67
67
  "@types/jest": "^27.0.3",
68
- "@typescript-eslint/eslint-plugin": "^5.7.0",
69
- "@typescript-eslint/parser": "^5.7.0",
68
+ "@typescript-eslint/eslint-plugin": "^5.8.0",
69
+ "@typescript-eslint/parser": "^5.8.0",
70
70
  "eslint": "^8.5.0",
71
71
  "eslint-config-airbnb-base": "^15.0.0",
72
72
  "eslint-plugin-import": "^2.25.3",
@@ -28,6 +28,7 @@ import {
28
28
  } from 'crypto-js';
29
29
  import { AddressRegion } from '../address/AddressRegion';
30
30
  import { AddressUtils } from '../address/AddressUtils';
31
+ import { IdLabelDto } from '../dto/IdLabelDto';
31
32
  import { InitCallDto } from '../dto/InitCallDto';
32
33
  import { ActionResultError } from '../result/ActionResultError';
33
34
  import { IActionResult } from '../result/IActionResult';
@@ -177,6 +178,11 @@ export interface ICoreApp<
177
178
  */
178
179
  changeCulture(culture: DataTypes.CultureDefinition): void;
179
180
 
181
+ /**
182
+ * Clear cache data
183
+ */
184
+ clearCacheData(): void;
185
+
180
186
  /**
181
187
  * Clear cached token
182
188
  */
@@ -312,7 +318,7 @@ export interface ICoreApp<
312
318
  * Get cached token
313
319
  * @returns Cached token
314
320
  */
315
- getCacheToken(): string | null;
321
+ getCacheToken(): string | undefined;
316
322
 
317
323
  /**
318
324
  * Get all regions
@@ -382,6 +388,17 @@ export interface ICoreApp<
382
388
  */
383
389
  signout(apiUrl?: string): Promise<void>;
384
390
 
391
+ /**
392
+ * Get organization list
393
+ * @param items Max items
394
+ * @param serviceId Service id
395
+ * @returns Result
396
+ */
397
+ orgList(
398
+ items?: number,
399
+ serviceId?: number
400
+ ): Promise<IdLabelDto[] | undefined>;
401
+
385
402
  /**
386
403
  * Switch organization
387
404
  * @param apiOrOrg API URL or organization id
@@ -487,7 +504,7 @@ export abstract class CoreApp<
487
504
  return this._region;
488
505
  }
489
506
 
490
- private _deviceId: string = '***';
507
+ private _deviceId: string = '';
491
508
  /**
492
509
  * Country or region, like CN
493
510
  */
@@ -505,20 +522,37 @@ export abstract class CoreApp<
505
522
  return this.get.bind(this);
506
523
  }
507
524
 
525
+ private _ipData?: IPData;
508
526
  /**
509
527
  * IP data
510
528
  */
511
- ipData?: IPData;
529
+ get ipData() {
530
+ return this._ipData;
531
+ }
532
+ protected set ipData(value: IPData | undefined) {
533
+ this._ipData = value;
534
+ }
512
535
 
536
+ private _userData?: IUserData;
513
537
  /**
514
538
  * User data
515
539
  */
516
- userData?: IUserData;
540
+ get userData() {
541
+ return this._userData;
542
+ }
543
+ protected set userData(value: IUserData | undefined) {
544
+ this._userData = value;
545
+ }
517
546
 
518
547
  /**
519
548
  * Response token header field name
520
549
  */
521
- headerTokenField = 'SmartERPRefreshToken';
550
+ readonly headerTokenField = 'SmartERPRefreshToken';
551
+
552
+ /**
553
+ * Serverside device id encrypted field name
554
+ */
555
+ protected readonly serversideDeviceIdField = 'SmartERPServersideDeviceId';
522
556
 
523
557
  // IP detect ready callbacks
524
558
  private ipDetectCallbacks?: IDetectIPCallback[];
@@ -555,7 +589,13 @@ export abstract class CoreApp<
555
589
  /**
556
590
  * Device id field name
557
591
  */
558
- protected deviceIdField: string = 'SmartERPDeviceId';
592
+ protected readonly deviceIdField: string = 'SmartERPDeviceId';
593
+
594
+ /**
595
+ * Device id update time field name
596
+ */
597
+ protected readonly deviceIdUpdateTimeField: string =
598
+ 'SmartERPDeviceIdUpdateTime';
559
599
 
560
600
  /**
561
601
  * Init call Api URL
@@ -645,15 +685,43 @@ export abstract class CoreApp<
645
685
  return await this.api.put<InitCallResult>(this.initCallApi, data);
646
686
  }
647
687
 
688
+ /**
689
+ * Get device last updte miliseconds
690
+ * @returns Miliseconds
691
+ */
692
+ protected getDeviceUpdateTime() {
693
+ return StorageUtils.getLocalData(this.deviceIdUpdateTimeField, 0);
694
+ }
695
+
648
696
  /**
649
697
  * Init call
650
698
  * @param callback Callback
651
699
  * @returns Result
652
700
  */
653
701
  async initCall(callback?: (result: boolean) => void) {
702
+ // Device
703
+ let hasDeviceId = this.deviceId != null && this.deviceId !== '';
704
+ const timestamp = new Date().getTime();
705
+ const lastTimestamp = this.getDeviceUpdateTime();
706
+ if (
707
+ hasDeviceId &&
708
+ lastTimestamp > 0 &&
709
+ timestamp - lastTimestamp <= 1296000000
710
+ ) {
711
+ // When deviceId is there and less than 15 days = 1000 * 60 * 60 * 24 * 15
712
+ if (callback) callback(true);
713
+ return;
714
+ }
715
+
716
+ // Serverside encrypted device id
717
+ const identifier = StorageUtils.getLocalData<string>(
718
+ this.serversideDeviceIdField
719
+ );
720
+
654
721
  const data: InitCallDto = {
655
- timestamp: new Date().getTime(),
656
- deviceId: this.deviceId === '' ? undefined : this.deviceId
722
+ timestamp,
723
+ identifier,
724
+ deviceId: hasDeviceId ? this.deviceId : undefined
657
725
  };
658
726
  const result = await this.apiInitCall(data);
659
727
  if (result == null) {
@@ -713,6 +781,7 @@ export abstract class CoreApp<
713
781
  // Update device id and cache it
714
782
  this.deviceId = data.deviceId;
715
783
  StorageUtils.setLocalData(this.deviceIdField, this.deviceId);
784
+ StorageUtils.setLocalData(this.deviceIdUpdateTimeField, timestamp);
716
785
 
717
786
  // Current passphrase
718
787
  this.passphrase = passphrase;
@@ -727,11 +796,8 @@ export abstract class CoreApp<
727
796
  // Update
728
797
  const fields = this.initCallUpdateFields();
729
798
  for (const field of fields) {
730
- const currentValue = StorageUtils.getLocalData<string>(
731
- field,
732
- ''
733
- );
734
- if (currentValue === '') continue;
799
+ const currentValue = StorageUtils.getLocalData<string>(field);
800
+ if (currentValue == null || currentValue === '') continue;
735
801
 
736
802
  const enhanced = currentValue.indexOf('!') >= 8;
737
803
  let newValueSource = null;
@@ -872,6 +938,18 @@ export abstract class CoreApp<
872
938
  });
873
939
  }
874
940
 
941
+ /**
942
+ * Clear cache data
943
+ */
944
+ clearCacheData() {
945
+ StorageUtils.setLocalData(this.serversideDeviceIdField, undefined);
946
+
947
+ StorageUtils.setLocalData(this.deviceIdField, undefined);
948
+ StorageUtils.setLocalData(this.deviceIdUpdateTimeField, undefined);
949
+
950
+ StorageUtils.setLocalData(this.headerTokenField, undefined);
951
+ }
952
+
875
953
  /**
876
954
  * Clear cached token
877
955
  */
@@ -1180,18 +1258,10 @@ export abstract class CoreApp<
1180
1258
  * Get cached token
1181
1259
  * @returns Cached token
1182
1260
  */
1183
- getCacheToken(): string | null {
1261
+ getCacheToken(): string | undefined {
1184
1262
  // Temp refresh token
1185
1263
  if (this.cachedRefreshToken) return this.cachedRefreshToken;
1186
-
1187
- const refreshToken = StorageUtils.getLocalData<string>(
1188
- this.headerTokenField,
1189
- ''
1190
- );
1191
-
1192
- if (refreshToken === '') return null;
1193
-
1194
- return refreshToken;
1264
+ return StorageUtils.getLocalData<string>(this.headerTokenField);
1195
1265
  }
1196
1266
 
1197
1267
  /**
@@ -1350,15 +1420,29 @@ export abstract class CoreApp<
1350
1420
  this.toLoginPage();
1351
1421
  }
1352
1422
 
1423
+ /**
1424
+ * Get organization list
1425
+ * @param items Max items
1426
+ * @param serviceId Service id
1427
+ * @returns Result
1428
+ */
1429
+ async orgList(items?: number, serviceId?: number) {
1430
+ return await this.api.post<IdLabelDto[]>(
1431
+ 'Organization/List',
1432
+ {
1433
+ items,
1434
+ serviceId
1435
+ },
1436
+ { defaultValue: [], showLoading: false }
1437
+ );
1438
+ }
1439
+
1353
1440
  /**
1354
1441
  * Switch organization
1355
- * @param apiOrOrg API URL or organization id
1442
+ * @param id Organization id
1356
1443
  */
1357
- async switchOrg(apiOrOrg: string | number) {
1358
- const api =
1359
- typeof apiOrOrg === 'number'
1360
- ? `Organization/Switch/${apiOrOrg}`
1361
- : apiOrOrg;
1444
+ async switchOrg(id: number) {
1445
+ const api = `Organization/Switch/${id}`;
1362
1446
  const result = await this.api.put<boolean>(api);
1363
1447
  if (result) return await this.refreshToken();
1364
1448
  return result;
@@ -1416,6 +1500,9 @@ export abstract class CoreApp<
1416
1500
  userLogin(user: IUserData, refreshToken: string, keep?: boolean) {
1417
1501
  this.userData = user;
1418
1502
 
1503
+ // Cache the encrypted serverside device id
1504
+ StorageUtils.setLocalData(this.serversideDeviceIdField, user.deviceId);
1505
+
1419
1506
  if (keep) {
1420
1507
  this.authorize(user.token, refreshToken);
1421
1508
  } else {
@@ -3,29 +3,29 @@
3
3
  */
4
4
  export interface IExternalSettings {
5
5
  /**
6
- * API endpoint
6
+ * Core system API endpoint
7
7
  */
8
8
  readonly endpoint: string;
9
9
 
10
10
  /**
11
- * App root url
11
+ * Core system app root url
12
12
  */
13
13
  readonly homepage: string;
14
14
 
15
15
  /**
16
- * Cloud web url
16
+ * Core system web url
17
17
  */
18
18
  readonly webUrl: string;
19
19
 
20
20
  /**
21
- * Core system Url
21
+ * Service API endpoint
22
22
  */
23
- readonly coreUrl?: string;
23
+ readonly serviceEndpoint?: string;
24
24
 
25
25
  /**
26
- * Core system API
26
+ * Service web Url
27
27
  */
28
- readonly coreApi?: string;
28
+ readonly serviceUrl?: string;
29
29
  }
30
30
 
31
31
  /**
@@ -7,6 +7,11 @@ export type InitCallDto = {
7
7
  */
8
8
  deviceId?: string;
9
9
 
10
+ /**
11
+ * Serverside identifier
12
+ */
13
+ identifier?: string;
14
+
10
15
  /**
11
16
  * Timestamp
12
17
  */
package/src/state/User.ts CHANGED
@@ -4,6 +4,11 @@ import { IState } from './State';
4
4
  * User data interface
5
5
  */
6
6
  export interface IUserData {
7
+ /**
8
+ * Serverside device id encrypted
9
+ */
10
+ readonly deviceId: string;
11
+
7
12
  /**
8
13
  * User name
9
14
  */