@sambath999/localize-token 19.0.3 → 19.0.5
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/fesm2022/sambath999-localize-token.mjs +719 -295
- package/fesm2022/sambath999-localize-token.mjs.map +1 -1
- package/localize-api-token/localize-api-token.module.d.ts +9 -0
- package/localize-api-token/localize-api-token.service.d.ts +15 -0
- package/localize-logindlg/localize-logindlg.component.d.ts +7 -2
- package/localize-logindlg/localize-logindlg.module.d.ts +1 -4
- package/localize-logindlg/localize-logindlg.service.d.ts +44 -0
- package/localize-token/helpers/interfaces.d.ts +87 -0
- package/localize-token/helpers/localize.api.assets.d.ts +5 -0
- package/localize-token/helpers/loccalize.api.helper.d.ts +32 -0
- package/localize-token/localize.api.service.d.ts +29 -46
- package/localize-token/localize.token.d.ts +8 -10
- package/localize-token/localize.token.service.d.ts +12 -5
- package/package.json +1 -1
- package/public-api.d.ts +13 -2
- package/localize-logindlg/public-api.d.ts +0 -3
- package/localize-token/public-api.d.ts +0 -5
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable,
|
|
3
|
-
import
|
|
4
|
-
import * as jwt_decode from 'jwt-decode';
|
|
5
|
-
import * as i1 from '@angular/common/http';
|
|
6
|
-
import { HttpHeaders } from '@angular/common/http';
|
|
7
|
-
import * as i1$1 from 'primeng/api';
|
|
2
|
+
import { Injectable, Component, ViewEncapsulation, NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
3
|
+
import * as i1 from 'primeng/api';
|
|
8
4
|
import { MessageService } from 'primeng/api';
|
|
9
5
|
import * as i2 from 'primeng/dynamicdialog';
|
|
10
|
-
import { DialogService
|
|
11
|
-
import
|
|
6
|
+
import { DialogService } from 'primeng/dynamicdialog';
|
|
7
|
+
import { BehaviorSubject, takeUntil, catchError, throwError, Subject } from 'rxjs';
|
|
8
|
+
import * as jwt_decode from 'jwt-decode';
|
|
9
|
+
import * as i4 from '@angular/common/http';
|
|
10
|
+
import { HttpHeaders } from '@angular/common/http';
|
|
11
|
+
import * as i5 from '@angular/platform-browser';
|
|
12
|
+
import { BrowserModule } from '@angular/platform-browser';
|
|
13
|
+
import * as i6 from '@angular/common';
|
|
12
14
|
import { CommonModule } from '@angular/common';
|
|
13
|
-
import * as
|
|
15
|
+
import * as i7 from 'primeng/toast';
|
|
14
16
|
import { ToastModule } from 'primeng/toast';
|
|
15
|
-
import * as
|
|
17
|
+
import * as i8 from 'primeng/inputtext';
|
|
16
18
|
import { InputTextModule } from 'primeng/inputtext';
|
|
17
|
-
import * as
|
|
19
|
+
import * as i9 from '@angular/forms';
|
|
18
20
|
import { FormsModule } from '@angular/forms';
|
|
19
|
-
import * as
|
|
21
|
+
import * as i10 from 'primeng/button';
|
|
20
22
|
import { ButtonModule } from 'primeng/button';
|
|
21
|
-
import * as i10 from 'primeng/inputgroup';
|
|
22
|
-
import { InputGroupModule } from 'primeng/inputgroup';
|
|
23
|
-
import * as i11 from 'primeng/inputgroupaddon';
|
|
24
|
-
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
|
|
25
|
-
import { BrowserModule } from '@angular/platform-browser';
|
|
26
23
|
|
|
27
24
|
/**
|
|
28
25
|
* Assembly of @package ng2-cookies @see https://www.npmjs.com/package/ng2-cookies
|
|
@@ -132,18 +129,6 @@ class LocalizeTokenStorage {
|
|
|
132
129
|
}
|
|
133
130
|
|
|
134
131
|
class LocalizeToken {
|
|
135
|
-
static init(config) {
|
|
136
|
-
LocalizeToken.config = { ...LocalizeToken.config, ...config };
|
|
137
|
-
}
|
|
138
|
-
static config = {
|
|
139
|
-
mainDomain: extractMainDomain(),
|
|
140
|
-
authTokenName: 'auth-token',
|
|
141
|
-
tenantTokenName: '_lze_tnt_01',
|
|
142
|
-
refreshTokenName: '_lze_rftkp_',
|
|
143
|
-
needTenant: false,
|
|
144
|
-
isProduction: false,
|
|
145
|
-
revokeTokenUrl: ''
|
|
146
|
-
};
|
|
147
132
|
static storage = new LocalizeTokenStorage();
|
|
148
133
|
static httpHeaders = {
|
|
149
134
|
AUTHORIZATION: 'Authorization',
|
|
@@ -169,11 +154,18 @@ async function waitFor(milliseconds, when = true) {
|
|
|
169
154
|
* @param intervalNumber - The interval number in milliseconds to check the condition. Default is 50.
|
|
170
155
|
*/
|
|
171
156
|
async function waitUntil(when, intervalNumber = 50) {
|
|
157
|
+
async function isConditionMet() {
|
|
158
|
+
const cond = when();
|
|
159
|
+
const result = cond instanceof Promise
|
|
160
|
+
? await cond
|
|
161
|
+
: cond;
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
if (await isConditionMet())
|
|
165
|
+
return;
|
|
172
166
|
await new Promise(resolve => {
|
|
173
167
|
const interval = setInterval(async () => {
|
|
174
|
-
|
|
175
|
-
const result = cond instanceof Promise ? await cond : cond;
|
|
176
|
-
if (result) {
|
|
168
|
+
if (await isConditionMet()) {
|
|
177
169
|
clearInterval(interval);
|
|
178
170
|
resolve(true);
|
|
179
171
|
}
|
|
@@ -187,41 +179,52 @@ function extractMainDomain(subdomain) {
|
|
|
187
179
|
}
|
|
188
180
|
|
|
189
181
|
class LocalizeTokenService {
|
|
182
|
+
configSubject = new BehaviorSubject({});
|
|
190
183
|
isRevokingTokenSubject = new BehaviorSubject(false);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
184
|
+
defaultConfig = {
|
|
185
|
+
mainDomain: extractMainDomain(),
|
|
186
|
+
authToken: {
|
|
187
|
+
name: 'auth-token',
|
|
188
|
+
},
|
|
189
|
+
refreshToken: {
|
|
190
|
+
name: 'refresh-token',
|
|
191
|
+
requestUrl: '/api/token/revoke'
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
get config() {
|
|
195
|
+
this.throwIfNotInitialized();
|
|
196
|
+
return this.configSubject.value;
|
|
197
|
+
}
|
|
198
|
+
isInitialized = false;
|
|
199
|
+
init(config) {
|
|
200
|
+
console.log('LocalizeTokenService is initialized.');
|
|
201
|
+
this.configSubject.next({ ...this.defaultConfig, ...config });
|
|
202
|
+
this.isInitialized = true;
|
|
203
|
+
}
|
|
204
|
+
ngOnDestroy() {
|
|
205
|
+
// this.configSubject.complete();
|
|
206
|
+
// this.isRevokingTokenSubject.complete();
|
|
197
207
|
}
|
|
198
208
|
get authToken() { return this.storageGet(); }
|
|
199
209
|
set authToken(value) {
|
|
200
210
|
value
|
|
201
211
|
? this.storageSet(value)
|
|
202
|
-
: LocalizeToken.storage.delete(this.config.
|
|
212
|
+
: LocalizeToken.storage.delete(this.config.authToken?.name);
|
|
203
213
|
}
|
|
204
|
-
get
|
|
214
|
+
get tenantToken() { return LocalizeToken.storage.get(this.config.tenantToken?.name || ''); }
|
|
215
|
+
get refreshToken() { return LocalizeToken.storage.get(this.config.refreshToken?.name || ''); }
|
|
205
216
|
get accessToken() { return this.authToken?.token; }
|
|
206
217
|
set accessToken(value) {
|
|
207
|
-
|
|
208
|
-
this.authToken = { token: value, revoke: false };
|
|
209
|
-
}
|
|
218
|
+
value && (this.authToken = { token: value, revoke: false });
|
|
210
219
|
}
|
|
211
220
|
get isRevokingToken() { return this.isRevokingTokenSubject.value; /* this.authToken?.revoke ?? false */ }
|
|
212
221
|
set isRevokingToken(value) {
|
|
213
222
|
this.isRevokingTokenSubject.next(value);
|
|
214
|
-
|
|
215
|
-
this.authToken = { ...this.authToken, revoke: value };
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
// get tenantToken() { return LocalizeToken.storage.get(this.config.tenantTokenName!) }
|
|
219
|
-
tenantToken(name) {
|
|
220
|
-
return LocalizeToken.storage.get(name ?? this.config.tenantTokenName);
|
|
223
|
+
this.authToken && (this.authToken = { ...this.authToken, revoke: value });
|
|
221
224
|
}
|
|
222
225
|
storageGet() {
|
|
223
226
|
try {
|
|
224
|
-
const encoded = LocalizeToken.storage.get(this.config.
|
|
227
|
+
const encoded = LocalizeToken.storage.get(this.config.authToken?.name || '');
|
|
225
228
|
const decoded = atob(encoded || '');
|
|
226
229
|
return JSON.parse(decoded);
|
|
227
230
|
}
|
|
@@ -231,17 +234,21 @@ class LocalizeTokenService {
|
|
|
231
234
|
}
|
|
232
235
|
storageSet(value) {
|
|
233
236
|
const base64 = btoa(JSON.stringify(value));
|
|
234
|
-
LocalizeToken.storage.set(this.config.
|
|
237
|
+
LocalizeToken.storage.set(this.config.authToken?.name || '', base64);
|
|
235
238
|
}
|
|
236
239
|
tokensValid() {
|
|
237
|
-
return this.refreshToken?.length
|
|
240
|
+
return !!this.refreshToken?.length
|
|
241
|
+
&& (!this.config.tenantToken || !!this.tenantToken?.length);
|
|
238
242
|
}
|
|
239
243
|
decodeToken = (token) => jwt_decode.jwtDecode(token);
|
|
240
244
|
get decodeRefreshToken() {
|
|
241
|
-
const token =
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
const token = this.refreshToken;
|
|
246
|
+
return !token ? null : this.decodeToken(token);
|
|
247
|
+
}
|
|
248
|
+
throwIfNotInitialized() {
|
|
249
|
+
if (!this.isInitialized) {
|
|
250
|
+
throw new Error('LocalizeTokenService is not initialized. Call init() method before using it.');
|
|
251
|
+
}
|
|
245
252
|
}
|
|
246
253
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
247
254
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenService, providedIn: 'root' });
|
|
@@ -249,161 +256,6 @@ class LocalizeTokenService {
|
|
|
249
256
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenService, decorators: [{
|
|
250
257
|
type: Injectable,
|
|
251
258
|
args: [{ providedIn: 'root' }]
|
|
252
|
-
}], ctorParameters: () => [] });
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Http method options
|
|
256
|
-
*/
|
|
257
|
-
var EMethod;
|
|
258
|
-
(function (EMethod) {
|
|
259
|
-
EMethod[EMethod["POST"] = 1] = "POST";
|
|
260
|
-
EMethod[EMethod["GET"] = 2] = "GET";
|
|
261
|
-
EMethod[EMethod["PUT"] = 3] = "PUT";
|
|
262
|
-
EMethod[EMethod["DELETE"] = 4] = "DELETE";
|
|
263
|
-
EMethod[EMethod["PATCH"] = 5] = "PATCH";
|
|
264
|
-
})(EMethod || (EMethod = {}));
|
|
265
|
-
class LocalizeApiService {
|
|
266
|
-
httpClient;
|
|
267
|
-
localizeTokenService;
|
|
268
|
-
isRequestingSubject = new BehaviorSubject(false);
|
|
269
|
-
isResolvedStartupSubject = new BehaviorSubject(false);
|
|
270
|
-
get isRequesting() { return this.isRequestingSubject.value; }
|
|
271
|
-
get isResolvedStartup() { return this.isResolvedStartupSubject.value; }
|
|
272
|
-
apiConfigs = {};
|
|
273
|
-
isInitialized = false;
|
|
274
|
-
constructor(httpClient, localizeTokenService) {
|
|
275
|
-
this.httpClient = httpClient;
|
|
276
|
-
this.localizeTokenService = localizeTokenService;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Initialize the API service.
|
|
280
|
-
* @param apiConfigs - The API configurations.
|
|
281
|
-
*/
|
|
282
|
-
init(apiConfigs) {
|
|
283
|
-
if (this.isInitialized)
|
|
284
|
-
return;
|
|
285
|
-
this.isInitialized = true;
|
|
286
|
-
this.apiConfigs = apiConfigs;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* A higher-order function that returns a curried function for making API requests.
|
|
290
|
-
*
|
|
291
|
-
* @param baseUrl - The base URL of the API.
|
|
292
|
-
* @returns A curried function that can be used to make API requests.
|
|
293
|
-
*/
|
|
294
|
-
func = (baseUrl) => (path, method = EMethod.GET, value = null, isFormData = false, headers) => this.base(baseUrl, path, method, value, isFormData, headers);
|
|
295
|
-
async base(baseUrl, path, method = EMethod.GET, value = null, isFormData = false, headers) {
|
|
296
|
-
await this.ifPromise(this.apiConfigs.onPrepareRequest);
|
|
297
|
-
const url = `${baseUrl.trim().replace(/\/?$/, '/')}${path.trim().replace(/^\//, '')}`;
|
|
298
|
-
const httpMethod = EMethod[method].toLowerCase();
|
|
299
|
-
const request = () => { return { body: value, headers: this.options(isFormData, headers) }; };
|
|
300
|
-
// Wait for previous request to complete
|
|
301
|
-
await this.toWaitForPreviousRequest();
|
|
302
|
-
// Process request
|
|
303
|
-
try {
|
|
304
|
-
return await this.processRequest(httpMethod, url, request());
|
|
305
|
-
}
|
|
306
|
-
// Handle unauthorized error if any
|
|
307
|
-
catch (error) {
|
|
308
|
-
if (error.status !== 401) {
|
|
309
|
-
throw error;
|
|
310
|
-
}
|
|
311
|
-
return await this.onUnauthorizedError(httpMethod, url, request);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
async onUnauthorizedError(httpMethod, url, request) {
|
|
315
|
-
await this.revokeToken();
|
|
316
|
-
if (!this.isResolvedStartup) {
|
|
317
|
-
return await this.processRequest(httpMethod, url, request());
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
async toWaitForPreviousRequest() {
|
|
321
|
-
if (this.localizeTokenService.isRevokingToken) {
|
|
322
|
-
await waitUntil(() => !this.localizeTokenService.isRevokingToken);
|
|
323
|
-
}
|
|
324
|
-
// to wait for each request in 50ms, even if the request is not completed
|
|
325
|
-
if (this.apiConfigs.waitEachRequest?.milliseconds) {
|
|
326
|
-
await waitFor(this.apiConfigs.waitEachRequest.milliseconds, this.isRequesting);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
async processRequest(method, url, options) {
|
|
330
|
-
this.isRequestingSubject.next(true);
|
|
331
|
-
const result = await new Promise((resolve, reject) => this.httpClient.request(method, url, options).subscribe({ next: resolve, error: reject }));
|
|
332
|
-
this.isRequestingSubject.next(false);
|
|
333
|
-
return result;
|
|
334
|
-
}
|
|
335
|
-
async revokeToken() {
|
|
336
|
-
if (this.localizeTokenService.isRevokingToken) {
|
|
337
|
-
await waitUntil(() => !this.localizeTokenService.isRevokingToken);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
try {
|
|
341
|
-
this.localizeTokenService.isRevokingToken = true;
|
|
342
|
-
const reqUrl = LocalizeToken.config.revokeTokenUrl;
|
|
343
|
-
const reqHeaders = this.options().append(LocalizeToken.httpHeaders.X_REFRESH_TOKEN, `${this.localizeTokenService.refreshToken}`);
|
|
344
|
-
const revokeToken = await new Promise((resolve, reject) => this.httpClient.get(reqUrl, { headers: reqHeaders }).subscribe({ next: resolve, error: reject }));
|
|
345
|
-
if (revokeToken?.status) {
|
|
346
|
-
this.localizeTokenService.accessToken = revokeToken.message;
|
|
347
|
-
}
|
|
348
|
-
else if (!this.localizeTokenService.refreshToken) {
|
|
349
|
-
await this.ifPromise(this.apiConfigs.onAutoLogout);
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
if (this.apiConfigs.onRevokeUnauthorized) {
|
|
353
|
-
await this.ifPromise(this.apiConfigs.onRevokeUnauthorized);
|
|
354
|
-
// await this.revokeToken();
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
finally {
|
|
359
|
-
this.localizeTokenService.isRevokingToken = false;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
/** default http request options */
|
|
363
|
-
options(isFormData = false, headers = {}) {
|
|
364
|
-
const defaultHeaders = { [LocalizeToken.httpHeaders.AUTHORIZATION]: `Bearer ${this.localizeTokenService.accessToken}`, };
|
|
365
|
-
if (LocalizeToken.config.needTenant) {
|
|
366
|
-
defaultHeaders[LocalizeToken.httpHeaders.X_TENANT] = `${this.localizeTokenService.tenantToken(this.apiConfigs.tenantTokenName)}`;
|
|
367
|
-
}
|
|
368
|
-
if (!isFormData) {
|
|
369
|
-
defaultHeaders[LocalizeToken.httpHeaders.CONTENT_TYPE] = 'application/json';
|
|
370
|
-
}
|
|
371
|
-
const filteredHeaders = Object.keys(defaultHeaders).filter(key => !Object.keys(headers).includes(key))
|
|
372
|
-
.reduce((acc, key) => ({ ...acc, [key]: defaultHeaders[key] }), {});
|
|
373
|
-
const mergedHeaders = { ...filteredHeaders, ...headers };
|
|
374
|
-
return new HttpHeaders(mergedHeaders);
|
|
375
|
-
}
|
|
376
|
-
async ifPromise(fn) {
|
|
377
|
-
if (!fn)
|
|
378
|
-
return;
|
|
379
|
-
return fn instanceof Promise ? await fn() : fn();
|
|
380
|
-
}
|
|
381
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, deps: [{ token: i1.HttpClient }, { token: LocalizeTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
382
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, providedIn: 'root' });
|
|
383
|
-
} //class
|
|
384
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, decorators: [{
|
|
385
|
-
type: Injectable,
|
|
386
|
-
args: [{
|
|
387
|
-
providedIn: 'root'
|
|
388
|
-
}]
|
|
389
|
-
}], ctorParameters: () => [{ type: i1.HttpClient }, { type: LocalizeTokenService }] });
|
|
390
|
-
|
|
391
|
-
class LocalizeTokenModule {
|
|
392
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
393
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule });
|
|
394
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, providers: [
|
|
395
|
-
LocalizeTokenService,
|
|
396
|
-
LocalizeApiService
|
|
397
|
-
] });
|
|
398
|
-
}
|
|
399
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, decorators: [{
|
|
400
|
-
type: NgModule,
|
|
401
|
-
args: [{
|
|
402
|
-
providers: [
|
|
403
|
-
LocalizeTokenService,
|
|
404
|
-
LocalizeApiService
|
|
405
|
-
],
|
|
406
|
-
}]
|
|
407
259
|
}] });
|
|
408
260
|
|
|
409
261
|
class LocalizeLogindlgComponent {
|
|
@@ -413,24 +265,28 @@ class LocalizeLogindlgComponent {
|
|
|
413
265
|
dlgConfig;
|
|
414
266
|
tokenService;
|
|
415
267
|
httpClient;
|
|
268
|
+
sanitizer;
|
|
416
269
|
messageKey = "$login-dlg";
|
|
417
270
|
password;
|
|
418
271
|
decodeToken;
|
|
419
272
|
loading = false;
|
|
420
273
|
success = false;
|
|
421
|
-
config
|
|
274
|
+
get config() { return this.tokenService.config; }
|
|
422
275
|
loginConfig;
|
|
423
276
|
logout;
|
|
424
277
|
loginUrl;
|
|
425
|
-
|
|
278
|
+
properties;
|
|
279
|
+
constructor(messageService, cdt, dlgRef, dlgConfig, tokenService, httpClient, sanitizer) {
|
|
426
280
|
this.messageService = messageService;
|
|
427
281
|
this.cdt = cdt;
|
|
428
282
|
this.dlgRef = dlgRef;
|
|
429
283
|
this.dlgConfig = dlgConfig;
|
|
430
284
|
this.tokenService = tokenService;
|
|
431
285
|
this.httpClient = httpClient;
|
|
286
|
+
this.sanitizer = sanitizer;
|
|
432
287
|
this.decodeToken = this.tokenService.decodeRefreshToken;
|
|
433
288
|
this.loginConfig = this.dlgConfig.data.loginConfig;
|
|
289
|
+
this.properties = this.loginConfig.properties;
|
|
434
290
|
}
|
|
435
291
|
ngOnInit() {
|
|
436
292
|
this.dlgConfig.closable = false;
|
|
@@ -446,29 +302,34 @@ class LocalizeLogindlgComponent {
|
|
|
446
302
|
}
|
|
447
303
|
async clickLogin() {
|
|
448
304
|
if (!this.isValidPassword) {
|
|
449
|
-
this.showMessage("error", "Password is required and must be at least 6 characters");
|
|
450
|
-
return;
|
|
305
|
+
return this.showMessage("error", "Password is required and must be at least 6 characters");
|
|
451
306
|
}
|
|
452
307
|
this.loading = true;
|
|
453
308
|
const loginRes = await this.login();
|
|
454
309
|
if (!loginRes?.status) {
|
|
455
|
-
this.showMessage("error", loginRes.message ?? "An error occurred");
|
|
456
|
-
return;
|
|
310
|
+
return this.showMessage("error", loginRes.message ?? "An error occurred");
|
|
457
311
|
}
|
|
458
312
|
this.tokenService.accessToken = loginRes.tokens.accessToken;
|
|
459
|
-
const cookieOptions = { expires: this.loginConfig.expire ??
|
|
460
|
-
LocalizeToken.storage.set(this.config.
|
|
313
|
+
const cookieOptions = { expires: this.loginConfig.expire ?? 365 };
|
|
314
|
+
LocalizeToken.storage.set(this.config.refreshToken?.name || '', loginRes.tokens.refreshToken, cookieOptions);
|
|
461
315
|
this.success = true;
|
|
462
|
-
setTimeout(() =>
|
|
316
|
+
setTimeout(() => {
|
|
317
|
+
this.dlgConfig.dismissableMask = true;
|
|
318
|
+
this.dlgConfig.modal = false;
|
|
319
|
+
this.dlgRef.close(true);
|
|
320
|
+
}, 2000);
|
|
463
321
|
}
|
|
464
322
|
async login() {
|
|
465
|
-
if (!this.loginUrl
|
|
323
|
+
if (!this.loginUrl?.trim().length) {
|
|
466
324
|
this.showMessage("error", "Login url is required");
|
|
467
325
|
throw new Error("Login url is required");
|
|
468
326
|
}
|
|
469
327
|
try {
|
|
470
|
-
|
|
471
|
-
.
|
|
328
|
+
if (this.loginConfig.loginFunction) {
|
|
329
|
+
console.log("Using custom login function");
|
|
330
|
+
return await this.loginConfig.loginFunction(this.decodeToken?.email ?? '', this.password.trim(), this.getHeaders());
|
|
331
|
+
}
|
|
332
|
+
return await new Promise((resolve, reject) => this.httpClient.post(this.loginUrl, { password: this.password.trim() }, { headers: this.getHeaders() }).subscribe({ next: resolve, error: reject }));
|
|
472
333
|
}
|
|
473
334
|
catch (e) {
|
|
474
335
|
this.showMessage("error", e.message);
|
|
@@ -477,26 +338,31 @@ class LocalizeLogindlgComponent {
|
|
|
477
338
|
}
|
|
478
339
|
getHeaders() {
|
|
479
340
|
return {
|
|
480
|
-
[LocalizeToken.httpHeaders.X_REFRESH_TOKEN]:
|
|
481
|
-
[LocalizeToken.httpHeaders.X_TENANT]:
|
|
341
|
+
[LocalizeToken.httpHeaders.X_REFRESH_TOKEN]: this.tokenService.refreshToken ?? "",
|
|
342
|
+
[LocalizeToken.httpHeaders.X_TENANT]: this.tokenService.tenantToken ?? "",
|
|
482
343
|
};
|
|
483
344
|
}
|
|
484
345
|
get isValidPassword() {
|
|
485
346
|
this.loading = false;
|
|
486
|
-
return this.
|
|
347
|
+
return this.properties.passwordValidator
|
|
348
|
+
? this.properties.passwordValidator(this.password)
|
|
349
|
+
: this.password && this.password.trim().length >= 6 && this.password.trim().length <= 50;
|
|
487
350
|
}
|
|
488
351
|
clickLogout = () => this.logout?.();
|
|
489
352
|
showMessage(severity, summary) {
|
|
490
353
|
this.messageService.add({ key: this.messageKey, severity, summary });
|
|
491
354
|
this.loading = false;
|
|
492
355
|
}
|
|
493
|
-
|
|
356
|
+
get sanitizedTitle() {
|
|
357
|
+
return this.sanitizer.bypassSecurityTrustHtml(this.properties.title ?? '');
|
|
358
|
+
}
|
|
359
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgComponent, deps: [{ token: i1.MessageService }, { token: i0.ChangeDetectorRef }, { token: i2.DynamicDialogRef }, { token: i2.DynamicDialogConfig }, { token: LocalizeTokenService }, { token: i4.HttpClient }, { token: i5.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
494
360
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: LocalizeLogindlgComponent, isStandalone: false, selector: "app-localize-logindlg", providers: [MessageService], ngImport: i0, template: `<p-toast key="$login-dlg" position="top-center"></p-toast>
|
|
495
361
|
<div id="login-dlg-wrap">
|
|
496
362
|
<div id="login-dlg-header">
|
|
497
|
-
<div id="login-logo" class="p-mb-2"></div>
|
|
498
|
-
<h3 *ngIf="!success"
|
|
499
|
-
<h3 *ngIf="success" style="color:green !important;">
|
|
363
|
+
<div id="login-logo" class="p-mb-2" style="background: url('{{properties.logoImage}}') no-repeat"></div>
|
|
364
|
+
<h3 *ngIf="!success" [innerHTML]="sanitizedTitle"></h3>
|
|
365
|
+
<h3 *ngIf="success" style="color:green !important;">{{properties.loginSuccessMessage}}</h3>
|
|
500
366
|
</div>
|
|
501
367
|
<div id="login-dlg-content">
|
|
502
368
|
<ng-container *ngIf="!success">
|
|
@@ -504,35 +370,33 @@ class LocalizeLogindlgComponent {
|
|
|
504
370
|
<div class="login-dlg-loader"></div>
|
|
505
371
|
</div>
|
|
506
372
|
<div class="login-dlg-elm">
|
|
507
|
-
<p-inputgroup>
|
|
508
|
-
<
|
|
509
|
-
<
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
<input disabled pInputText type="text" placeholder="Username" [value]="decodeToken?.email" />
|
|
514
|
-
</p-inputgroup>
|
|
373
|
+
<div class="p-inputgroup">
|
|
374
|
+
<span class="p-inputgroup-addon">
|
|
375
|
+
<i class="material-icons-round">person</i>
|
|
376
|
+
</span>
|
|
377
|
+
<input disabled pInputText type="text" placeholder="{{properties.username?.placeHolder}}" [value]="decodeToken?.email" />
|
|
378
|
+
</div>
|
|
515
379
|
</div>
|
|
516
380
|
|
|
517
381
|
<div class="login-dlg-elm">
|
|
518
|
-
<p-inputgroup>
|
|
519
|
-
<p-inputgroup-addon>
|
|
520
|
-
<
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
<input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password" placeholder="Password" [(ngModel)]="password"
|
|
382
|
+
<div class="p-inputgroup">
|
|
383
|
+
<span class="p-inputgroup-addon">
|
|
384
|
+
<i class="material-icons-round">lock</i>
|
|
385
|
+
</span>
|
|
386
|
+
<input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password"
|
|
387
|
+
placeholder="{{properties.password?.placeHolder}}" [(ngModel)]="password"
|
|
525
388
|
autofocus />
|
|
526
|
-
</
|
|
389
|
+
</div>
|
|
527
390
|
</div>
|
|
528
391
|
<div class="login-dlg-elm">
|
|
529
|
-
<button style="width: 100%;" pButton type="button" label="
|
|
392
|
+
<button style="width: 100%;" pButton type="button" label="{{properties.loginButton?.placeHolder}}" (click)="clickLogin()"
|
|
530
393
|
[disabled]="!password || loading"></button>
|
|
531
394
|
</div>
|
|
532
395
|
|
|
533
|
-
<div class="login-dlg-elm" style="display:flex;align-items: center;user-select: none;">
|
|
534
|
-
<span>
|
|
535
|
-
<button class="p-button-text" pButton type="button" label="
|
|
396
|
+
<div class="login-dlg-elm login-dlg-suggest" style="display:flex;align-items: center;user-select: none;">
|
|
397
|
+
<span>{{properties.logoutButton?.message}}</span>
|
|
398
|
+
<button class="p-button-text" pButton type="button" label="{{properties.logoutButton?.placeHolder}}"
|
|
399
|
+
(click)="clickLogout()"></button>
|
|
536
400
|
</div>
|
|
537
401
|
</ng-container>
|
|
538
402
|
|
|
@@ -552,16 +416,16 @@ class LocalizeLogindlgComponent {
|
|
|
552
416
|
</div>
|
|
553
417
|
</ng-container>
|
|
554
418
|
</div>
|
|
555
|
-
</div>`, isInline: true, styles: ["#login-dlg-wrap{width:100%;max-width:400px;margin:0 auto;padding:30px}.login-dlg-elm{margin-top:1rem}#login-dlg-header{display:flex;flex-direction:column;align-items:center;justify-content:center}#login-dlg-header h3{font-weight:700;font-size:.9rem;color:orange;text-align:center}#login-logo{height:
|
|
419
|
+
</div>`, isInline: true, styles: ["#login-dlg-wrap{width:100%;max-width:400px;margin:0 auto;padding:30px;height:100%}.login-dlg-elm{margin-top:1rem}.login-dlg-elm.login-dlg-suggest{display:flex;align-items:center;-webkit-user-select:none;user-select:none;border-bottom:solid 1px #ddd;border-radius:5px;padding:5px 10px;background:#f9f9f9;box-shadow:1px 5px 10px -12px #000}#login-dlg-header{display:flex;flex-direction:column;align-items:center;justify-content:center}#login-dlg-header h3{font-weight:700;font-size:.9rem;color:orange;text-align:center}#login-logo{height:55px;width:55px;background-size:contain!important}#login-dlg-content .p-inputgroup{height:45px}#login-dlg-content .p-inputgroup .p-inputgroup-addon{height:45px;border-radius:15px 0 0 15px;width:50px}#login-dlg-content *{font-size:.9rem}#login-dlg-content .p-inputgroup .p-inputgroup-addon *{font-size:1rem}#login-dlg-content .p-inputgroup input{height:45px;border-radius:0 15px 15px 0}#login-dlg-content button{height:45px;border-radius:15px}.check-animation-wrap{top:0;left:0;position:absolute;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:calc(100% - 200px);min-height:400px}.check-main-container{width:100%;height:100vh;display:flex;flex-flow:column;justify-content:center;align-items:center}.check-container{width:6.25rem;height:7.5rem;display:flex;flex-flow:column;align-items:center;justify-content:space-between}.check-container .check-background{width:100%;height:calc(100% - 1.25rem);background:linear-gradient(to bottom right,#5de593,#41d67c);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset;transform:scale(.84);border-radius:50%;animation:animateContainer .75s ease-out forwards .75s;display:flex;align-items:center;justify-content:center;opacity:0}.check-container .check-background svg{width:65%;transform:translateY(.25rem);stroke-dasharray:80;stroke-dashoffset:80;animation:animateCheck .35s forwards 1.25s ease-out;min-width:auto!important}.check-container .check-shadow{bottom:calc(-15% - 5px);left:0;border-radius:50%;background:radial-gradient(closest-side,rgba(73,218,131,1),transparent);animation:animateShadow .75s ease-out forwards .75s}@keyframes animateContainer{0%{opacity:0;transform:scale(0);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset}25%{opacity:1;transform:scale(.9);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset}43.75%{transform:scale(1.15);box-shadow:0 0 0 43.334px #ffffff40 inset,0 0 0 65px #ffffff40 inset}62.5%{transform:scale(1);box-shadow:0 0 #ffffff40 inset,0 0 0 21.667px #ffffff40 inset}81.25%{box-shadow:0 0 #ffffff40 inset,0 0 #ffffff40 inset}to{opacity:1;box-shadow:0 0 #ffffff40 inset,0 0 #ffffff40 inset}}@keyframes animateCheck{0%{stroke-dashoffset:80}to{stroke-dashoffset:0}}@keyframes animateShadow{0%{opacity:0;width:100%;height:15%}25%{opacity:.25}43.75%{width:40%;height:7%;opacity:.35}to{width:85%;height:15%;opacity:.25}}#login-dlg-wrap .loader-wrap{display:flex;justify-content:center;align-items:center;height:100%;width:100%;position:absolute;top:0;left:0;z-index:100;background:#ffffff42;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}#login-dlg-wrap .login-dlg-loader{border:15px solid #e7e7e7;border-top:15px solid #52dba1;border-radius:50%;width:100px;height:100px;animation:spinloader 2s linear infinite}#login-dlg-wrap .loader-wrap:before{content:\"\";position:absolute;width:70px;height:70px;transform:translate(-50%,-50%);z-index:1;border:15px solid #e7e7e700;border-top:15px solid #52dba1c9;border-radius:50%;animation:spinloader .75s linear infinite}@keyframes spinloader{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i7.Toast, selector: "p-toast", inputs: ["key", "autoZIndex", "baseZIndex", "life", "style", "styleClass", "position", "preventOpenDuplicates", "preventDuplicates", "showTransformOptions", "hideTransformOptions", "showTransitionOptions", "hideTransitionOptions", "breakpoints"], outputs: ["onClose"] }, { kind: "directive", type: i8.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i10.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
556
420
|
}
|
|
557
421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgComponent, decorators: [{
|
|
558
422
|
type: Component,
|
|
559
423
|
args: [{ standalone: false, template: `<p-toast key="$login-dlg" position="top-center"></p-toast>
|
|
560
424
|
<div id="login-dlg-wrap">
|
|
561
425
|
<div id="login-dlg-header">
|
|
562
|
-
<div id="login-logo" class="p-mb-2"></div>
|
|
563
|
-
<h3 *ngIf="!success"
|
|
564
|
-
<h3 *ngIf="success" style="color:green !important;">
|
|
426
|
+
<div id="login-logo" class="p-mb-2" style="background: url('{{properties.logoImage}}') no-repeat"></div>
|
|
427
|
+
<h3 *ngIf="!success" [innerHTML]="sanitizedTitle"></h3>
|
|
428
|
+
<h3 *ngIf="success" style="color:green !important;">{{properties.loginSuccessMessage}}</h3>
|
|
565
429
|
</div>
|
|
566
430
|
<div id="login-dlg-content">
|
|
567
431
|
<ng-container *ngIf="!success">
|
|
@@ -569,35 +433,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
569
433
|
<div class="login-dlg-loader"></div>
|
|
570
434
|
</div>
|
|
571
435
|
<div class="login-dlg-elm">
|
|
572
|
-
<p-inputgroup>
|
|
573
|
-
<
|
|
574
|
-
<
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
<input disabled pInputText type="text" placeholder="Username" [value]="decodeToken?.email" />
|
|
579
|
-
</p-inputgroup>
|
|
436
|
+
<div class="p-inputgroup">
|
|
437
|
+
<span class="p-inputgroup-addon">
|
|
438
|
+
<i class="material-icons-round">person</i>
|
|
439
|
+
</span>
|
|
440
|
+
<input disabled pInputText type="text" placeholder="{{properties.username?.placeHolder}}" [value]="decodeToken?.email" />
|
|
441
|
+
</div>
|
|
580
442
|
</div>
|
|
581
443
|
|
|
582
444
|
<div class="login-dlg-elm">
|
|
583
|
-
<p-inputgroup>
|
|
584
|
-
<p-inputgroup-addon>
|
|
585
|
-
<
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
<input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password" placeholder="Password" [(ngModel)]="password"
|
|
445
|
+
<div class="p-inputgroup">
|
|
446
|
+
<span class="p-inputgroup-addon">
|
|
447
|
+
<i class="material-icons-round">lock</i>
|
|
448
|
+
</span>
|
|
449
|
+
<input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password"
|
|
450
|
+
placeholder="{{properties.password?.placeHolder}}" [(ngModel)]="password"
|
|
590
451
|
autofocus />
|
|
591
|
-
</
|
|
452
|
+
</div>
|
|
592
453
|
</div>
|
|
593
454
|
<div class="login-dlg-elm">
|
|
594
|
-
<button style="width: 100%;" pButton type="button" label="
|
|
455
|
+
<button style="width: 100%;" pButton type="button" label="{{properties.loginButton?.placeHolder}}" (click)="clickLogin()"
|
|
595
456
|
[disabled]="!password || loading"></button>
|
|
596
457
|
</div>
|
|
597
458
|
|
|
598
|
-
<div class="login-dlg-elm" style="display:flex;align-items: center;user-select: none;">
|
|
599
|
-
<span>
|
|
600
|
-
<button class="p-button-text" pButton type="button" label="
|
|
459
|
+
<div class="login-dlg-elm login-dlg-suggest" style="display:flex;align-items: center;user-select: none;">
|
|
460
|
+
<span>{{properties.logoutButton?.message}}</span>
|
|
461
|
+
<button class="p-button-text" pButton type="button" label="{{properties.logoutButton?.placeHolder}}"
|
|
462
|
+
(click)="clickLogout()"></button>
|
|
601
463
|
</div>
|
|
602
464
|
</ng-container>
|
|
603
465
|
|
|
@@ -617,8 +479,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
617
479
|
</div>
|
|
618
480
|
</ng-container>
|
|
619
481
|
</div>
|
|
620
|
-
</div>`, selector: "app-localize-logindlg", providers: [MessageService], encapsulation: ViewEncapsulation.None, styles: ["#login-dlg-wrap{width:100%;max-width:400px;margin:0 auto;padding:30px}.login-dlg-elm{margin-top:1rem}#login-dlg-header{display:flex;flex-direction:column;align-items:center;justify-content:center}#login-dlg-header h3{font-weight:700;font-size:.9rem;color:orange;text-align:center}#login-logo{height:
|
|
621
|
-
}], ctorParameters: () => [{ type: i1
|
|
482
|
+
</div>`, selector: "app-localize-logindlg", providers: [MessageService], encapsulation: ViewEncapsulation.None, styles: ["#login-dlg-wrap{width:100%;max-width:400px;margin:0 auto;padding:30px;height:100%}.login-dlg-elm{margin-top:1rem}.login-dlg-elm.login-dlg-suggest{display:flex;align-items:center;-webkit-user-select:none;user-select:none;border-bottom:solid 1px #ddd;border-radius:5px;padding:5px 10px;background:#f9f9f9;box-shadow:1px 5px 10px -12px #000}#login-dlg-header{display:flex;flex-direction:column;align-items:center;justify-content:center}#login-dlg-header h3{font-weight:700;font-size:.9rem;color:orange;text-align:center}#login-logo{height:55px;width:55px;background-size:contain!important}#login-dlg-content .p-inputgroup{height:45px}#login-dlg-content .p-inputgroup .p-inputgroup-addon{height:45px;border-radius:15px 0 0 15px;width:50px}#login-dlg-content *{font-size:.9rem}#login-dlg-content .p-inputgroup .p-inputgroup-addon *{font-size:1rem}#login-dlg-content .p-inputgroup input{height:45px;border-radius:0 15px 15px 0}#login-dlg-content button{height:45px;border-radius:15px}.check-animation-wrap{top:0;left:0;position:absolute;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:calc(100% - 200px);min-height:400px}.check-main-container{width:100%;height:100vh;display:flex;flex-flow:column;justify-content:center;align-items:center}.check-container{width:6.25rem;height:7.5rem;display:flex;flex-flow:column;align-items:center;justify-content:space-between}.check-container .check-background{width:100%;height:calc(100% - 1.25rem);background:linear-gradient(to bottom right,#5de593,#41d67c);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset;transform:scale(.84);border-radius:50%;animation:animateContainer .75s ease-out forwards .75s;display:flex;align-items:center;justify-content:center;opacity:0}.check-container .check-background svg{width:65%;transform:translateY(.25rem);stroke-dasharray:80;stroke-dashoffset:80;animation:animateCheck .35s forwards 1.25s ease-out;min-width:auto!important}.check-container .check-shadow{bottom:calc(-15% - 5px);left:0;border-radius:50%;background:radial-gradient(closest-side,rgba(73,218,131,1),transparent);animation:animateShadow .75s ease-out forwards .75s}@keyframes animateContainer{0%{opacity:0;transform:scale(0);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset}25%{opacity:1;transform:scale(.9);box-shadow:0 0 0 65px #ffffff40 inset,0 0 0 65px #ffffff40 inset}43.75%{transform:scale(1.15);box-shadow:0 0 0 43.334px #ffffff40 inset,0 0 0 65px #ffffff40 inset}62.5%{transform:scale(1);box-shadow:0 0 #ffffff40 inset,0 0 0 21.667px #ffffff40 inset}81.25%{box-shadow:0 0 #ffffff40 inset,0 0 #ffffff40 inset}to{opacity:1;box-shadow:0 0 #ffffff40 inset,0 0 #ffffff40 inset}}@keyframes animateCheck{0%{stroke-dashoffset:80}to{stroke-dashoffset:0}}@keyframes animateShadow{0%{opacity:0;width:100%;height:15%}25%{opacity:.25}43.75%{width:40%;height:7%;opacity:.35}to{width:85%;height:15%;opacity:.25}}#login-dlg-wrap .loader-wrap{display:flex;justify-content:center;align-items:center;height:100%;width:100%;position:absolute;top:0;left:0;z-index:100;background:#ffffff42;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}#login-dlg-wrap .login-dlg-loader{border:15px solid #e7e7e7;border-top:15px solid #52dba1;border-radius:50%;width:100px;height:100px;animation:spinloader 2s linear infinite}#login-dlg-wrap .loader-wrap:before{content:\"\";position:absolute;width:70px;height:70px;transform:translate(-50%,-50%);z-index:1;border:15px solid #e7e7e700;border-top:15px solid #52dba1c9;border-radius:50%;animation:spinloader .75s linear infinite}@keyframes spinloader{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
|
|
483
|
+
}], ctorParameters: () => [{ type: i1.MessageService }, { type: i0.ChangeDetectorRef }, { type: i2.DynamicDialogRef }, { type: i2.DynamicDialogConfig }, { type: LocalizeTokenService }, { type: i4.HttpClient }, { type: i5.DomSanitizer }] });
|
|
622
484
|
|
|
623
485
|
class LocalizeLogindlgService {
|
|
624
486
|
injector;
|
|
@@ -626,12 +488,9 @@ class LocalizeLogindlgService {
|
|
|
626
488
|
this.injector = injector;
|
|
627
489
|
}
|
|
628
490
|
async openLoginDialog(loginConfig, config) {
|
|
629
|
-
config
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
style: { 'max-width': '400px', width: '100%', 'height': '650px' },
|
|
633
|
-
};
|
|
634
|
-
config.data = { ...config.data || {}, ...{ loginConfig } };
|
|
491
|
+
config = this.intercepDialogConfig(config);
|
|
492
|
+
this.initConfig(loginConfig);
|
|
493
|
+
config.data = { ...(config.data || {}), ...{ loginConfig } };
|
|
635
494
|
const dialogService = this.injector.get(DialogService);
|
|
636
495
|
const dialog = dialogService.open(LocalizeLogindlgComponent, config);
|
|
637
496
|
await new Promise((resolve) => dialog.onClose.subscribe(res => {
|
|
@@ -640,6 +499,37 @@ class LocalizeLogindlgService {
|
|
|
640
499
|
}
|
|
641
500
|
}));
|
|
642
501
|
}
|
|
502
|
+
intercepDialogConfig(config) {
|
|
503
|
+
config ??= {
|
|
504
|
+
header: 'Login',
|
|
505
|
+
style: { 'max-width': '400px', width: '100%', 'height': '650px' },
|
|
506
|
+
modal: true,
|
|
507
|
+
closable: false,
|
|
508
|
+
showHeader: false,
|
|
509
|
+
};
|
|
510
|
+
config = {
|
|
511
|
+
...config, ...{
|
|
512
|
+
contentStyle: { 'height': '100%', 'border-radius': '20px' }
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
config.style = { ...config.style, ...{ 'border-radius': '20px' } };
|
|
516
|
+
return config;
|
|
517
|
+
}
|
|
518
|
+
initConfig(loginConfig) {
|
|
519
|
+
loginConfig ??= {};
|
|
520
|
+
loginConfig.properties ??= {
|
|
521
|
+
title: 'Your session is expired!<br/> Please login again to continue.',
|
|
522
|
+
loginSuccessMessage: 'You have successfully logged in.',
|
|
523
|
+
logoImage: '/assets/images/logo-300px.png',
|
|
524
|
+
username: { placeHolder: 'Username' },
|
|
525
|
+
password: { placeHolder: 'Password' },
|
|
526
|
+
loginButton: { placeHolder: 'Login' },
|
|
527
|
+
logoutButton: {
|
|
528
|
+
message: 'No, I want to login with another user.',
|
|
529
|
+
placeHolder: 'Logout'
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
643
533
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgService, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
644
534
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgService, providedIn: 'root' });
|
|
645
535
|
}
|
|
@@ -657,19 +547,13 @@ class LocalizeLogindlgModule {
|
|
|
657
547
|
InputTextModule,
|
|
658
548
|
BrowserModule,
|
|
659
549
|
FormsModule,
|
|
660
|
-
ButtonModule,
|
|
661
|
-
DynamicDialogModule,
|
|
662
|
-
InputGroupModule,
|
|
663
|
-
InputGroupAddonModule], exports: [LocalizeLogindlgComponent] });
|
|
550
|
+
ButtonModule], exports: [LocalizeLogindlgComponent] });
|
|
664
551
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgModule, providers: [LocalizeLogindlgService], imports: [CommonModule,
|
|
665
552
|
ToastModule,
|
|
666
553
|
InputTextModule,
|
|
667
554
|
BrowserModule,
|
|
668
555
|
FormsModule,
|
|
669
|
-
ButtonModule
|
|
670
|
-
DynamicDialogModule,
|
|
671
|
-
InputGroupModule,
|
|
672
|
-
InputGroupAddonModule] });
|
|
556
|
+
ButtonModule] });
|
|
673
557
|
}
|
|
674
558
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeLogindlgModule, decorators: [{
|
|
675
559
|
type: NgModule,
|
|
@@ -683,18 +567,558 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
683
567
|
BrowserModule,
|
|
684
568
|
FormsModule,
|
|
685
569
|
ButtonModule,
|
|
686
|
-
DynamicDialogModule,
|
|
687
|
-
InputGroupModule,
|
|
688
|
-
InputGroupAddonModule
|
|
689
570
|
],
|
|
690
571
|
providers: [LocalizeLogindlgService],
|
|
691
572
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
692
573
|
}]
|
|
693
574
|
}] });
|
|
694
575
|
|
|
576
|
+
const LOCALIZE_API_ASSETS = {
|
|
577
|
+
network: {
|
|
578
|
+
noConnection: `<?xml version="1.0" encoding="UTF-8"?>
|
|
579
|
+
<svg id="lze-no-connection" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 77.29 70.98">
|
|
580
|
+
<defs>
|
|
581
|
+
<style> .cls-1 { fill: #fff; } .cls-2, .cls-3 { fill: #e30613; } .cls-3 { stroke: #e30613; stroke-miterlimit: 10; stroke-width: .25px; } </style>
|
|
582
|
+
</defs>
|
|
583
|
+
<g id="Layer_3" data-name="Layer 3">
|
|
584
|
+
<g>
|
|
585
|
+
<path class="cls-1" d="m73.29,35c-1.2,0-2.33-.53-3.09-1.46-.48-.57-11.23-13.2-31.55-13.2s-31.11,12.66-31.56,13.2c-1.4,1.71-3.92,1.95-5.63.55-1.71-1.4-1.95-3.92-.55-5.63.54-.66,13.47-16.12,37.74-16.12s37.2,15.46,37.74,16.12c1.4,1.71,1.15,4.23-.56,5.62-.71.58-1.61.9-2.53.9Z"/>
|
|
586
|
+
<path class="cls-1" d="m63.96,45.66c-1.19,0-2.32-.53-3.08-1.44-5.79-6.05-13.86-9.39-22.24-9.21-8.38-.18-16.45,3.16-22.24,9.22-1.46,1.65-3.99,1.81-5.64.35-1.57-1.39-1.8-3.77-.52-5.43,7.32-7.89,17.64-12.29,28.4-12.12,10.76-.17,21.08,4.24,28.4,12.12,1.4,1.71,1.15,4.23-.56,5.62-.71.58-1.6.9-2.53.9Z"/>
|
|
587
|
+
<path class="cls-1" d="m53.3,56.32c-1.24,0-2.41-.57-3.16-1.55-5.73-6.35-15.52-6.85-21.87-1.13-.4.36-.77.73-1.13,1.13-1.36,1.73-3.88,2.03-5.61.67-1.71-1.34-2.03-3.8-.73-5.54,8.39-9.85,23.18-11.04,33.03-2.65.95.81,1.84,1.69,2.65,2.65,1.34,1.75,1,4.26-.75,5.6-.7.53-1.55.82-2.43.82Z"/>
|
|
588
|
+
</g>
|
|
589
|
+
<path class="cls-2" d="m47.21,9.45l-4.06,41.36c-.64,5.42-8.39,5.39-9.01,0,0,0-4.06-41.36-4.06-41.36-.46-4.73,2.99-8.94,7.72-9.4,5.33-.58,9.97,4.09,9.4,9.4h0Z"/>
|
|
590
|
+
<circle class="cls-3" cx="38.64" cy="64.79" r="6.07"/>
|
|
591
|
+
</g>
|
|
592
|
+
</svg>`
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Http method options
|
|
598
|
+
*/
|
|
599
|
+
var EMethod;
|
|
600
|
+
(function (EMethod) {
|
|
601
|
+
EMethod["POST"] = "post";
|
|
602
|
+
EMethod["GET"] = "get";
|
|
603
|
+
EMethod["PUT"] = "put";
|
|
604
|
+
EMethod["DELETE"] = "delete";
|
|
605
|
+
EMethod["PATCH"] = "patch";
|
|
606
|
+
})(EMethod || (EMethod = {}));
|
|
607
|
+
// export interface INormalizedError {
|
|
608
|
+
// error: any;
|
|
609
|
+
// code: string;
|
|
610
|
+
// message: string;
|
|
611
|
+
// details?: any;
|
|
612
|
+
// status: number;
|
|
613
|
+
// }
|
|
614
|
+
|
|
615
|
+
class LocalizeApiHelper {
|
|
616
|
+
defaultRetryOptions = {
|
|
617
|
+
connectionError: {
|
|
618
|
+
message: 'Connection error occurred. Please wait',
|
|
619
|
+
blockScreen: true,
|
|
620
|
+
blockScreenZIndex: 10000
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
async performRetry(options) {
|
|
624
|
+
let attempts = 0;
|
|
625
|
+
let lastError;
|
|
626
|
+
let consoleCount = 0;
|
|
627
|
+
// Merge default retry options with provided options
|
|
628
|
+
options = { ...this.defaultRetryOptions, ...options };
|
|
629
|
+
let styleElement;
|
|
630
|
+
while (attempts < options.maxRetries()) {
|
|
631
|
+
try {
|
|
632
|
+
const result = await options.callback();
|
|
633
|
+
this.removeBlocker(styleElement);
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
lastError = error;
|
|
638
|
+
if (consoleCount >= 7) {
|
|
639
|
+
console.clear();
|
|
640
|
+
consoleCount = 0;
|
|
641
|
+
}
|
|
642
|
+
if (options.retryUnless && !options.retryUnless(error))
|
|
643
|
+
throw error; // If the error should not be retried, rethrow it
|
|
644
|
+
// Handle connection error
|
|
645
|
+
styleElement = await this.onConnectionError(options, error);
|
|
646
|
+
if (options.onError)
|
|
647
|
+
await this.invokeHook(options.onError.bind(this, error));
|
|
648
|
+
if (attempts >= options.maxRetries() - 1)
|
|
649
|
+
throw error;
|
|
650
|
+
attempts++;
|
|
651
|
+
consoleCount++;
|
|
652
|
+
console.warn(`Attempt ${attempts} failed. Retrying...`, error);
|
|
653
|
+
await waitFor(options.delay);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
console.warn(`Failed after ${options.maxRetries} attempts`);
|
|
657
|
+
throw lastError;
|
|
658
|
+
}
|
|
659
|
+
async performRequestWithRetry(options, config, performRequest) {
|
|
660
|
+
const retryUnless = config.retryOptions?.retryFunction
|
|
661
|
+
|| this.isConnectionError;
|
|
662
|
+
return await this.performRetry({
|
|
663
|
+
connectionError: config.retryOptions?.onConnectionError,
|
|
664
|
+
maxRetries: () => config.retryOptions?.maxRetries ?? 1000,
|
|
665
|
+
delay: config.retryOptions?.delay ?? 500,
|
|
666
|
+
callback: () => performRequest(options),
|
|
667
|
+
retryUnless: retryUnless,
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
buildUrl(baseUrl, path) {
|
|
671
|
+
const normalizedUrl = `${baseUrl.trim().replace(/\/?$/, '/')}${path.trim().replace(/^\//, '')}`;
|
|
672
|
+
return normalizedUrl.endsWith('/')
|
|
673
|
+
? normalizedUrl.slice(0, -1)
|
|
674
|
+
: normalizedUrl;
|
|
675
|
+
}
|
|
676
|
+
async invokeHook(callback) {
|
|
677
|
+
if (!callback)
|
|
678
|
+
return;
|
|
679
|
+
const result = callback();
|
|
680
|
+
if (result instanceof Promise) {
|
|
681
|
+
await result;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
createRequest(instance, method, url, body, options) {
|
|
685
|
+
const request$ = instance.client.request(method, url, {
|
|
686
|
+
...options,
|
|
687
|
+
body,
|
|
688
|
+
observe: 'response',
|
|
689
|
+
}).pipe(takeUntil(instance.destroy$()), catchError((error) => {
|
|
690
|
+
// Convert to a non-observable error to handle in the promise
|
|
691
|
+
return throwError(() => error);
|
|
692
|
+
}));
|
|
693
|
+
return request$;
|
|
694
|
+
}
|
|
695
|
+
defaultRetryFunction(error) {
|
|
696
|
+
// Don't retry for other errors (like 400, 401, 403, etc.)
|
|
697
|
+
if (!this.isConnectionError(error))
|
|
698
|
+
throw error;
|
|
699
|
+
return true;
|
|
700
|
+
}
|
|
701
|
+
isConnectionError(error) {
|
|
702
|
+
const isNetworkError = error.status === 0;
|
|
703
|
+
const isServerError = error.status >= 1000 && error.status < 600;
|
|
704
|
+
return isNetworkError || isServerError;
|
|
705
|
+
}
|
|
706
|
+
async onConnectionError(options, error) {
|
|
707
|
+
if (!options.connectionError)
|
|
708
|
+
return;
|
|
709
|
+
let styleElement;
|
|
710
|
+
if (this.isConnectionError(error)) {
|
|
711
|
+
styleElement = this.screenBlocker(options, error, true);
|
|
712
|
+
await this.invokeHook(options.connectionError.callback?.bind(this, error));
|
|
713
|
+
return styleElement;
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
this.screenBlocker(options, error, false);
|
|
717
|
+
styleElement?.remove();
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
screenBlocker(optons, error, add = true) {
|
|
721
|
+
if (!optons.connectionError?.blockScreen)
|
|
722
|
+
return;
|
|
723
|
+
const message = optons.connectionError?.message
|
|
724
|
+
|| 'Connection error occurred. Please wait';
|
|
725
|
+
const errorMessage = error?.error?.message || 'An error occurred';
|
|
726
|
+
const suggestinMessage = optons.connectionError?.suggestionMessage
|
|
727
|
+
|| 'Please check your internet connection or the server status.';
|
|
728
|
+
const zIndex = optons.connectionError?.blockScreenZIndex || 10000;
|
|
729
|
+
const body = document.body;
|
|
730
|
+
const blcokerHtml = `
|
|
731
|
+
<div class="lze-blocker">
|
|
732
|
+
${LOCALIZE_API_ASSETS.network.noConnection}
|
|
733
|
+
<div class="lze-blocker__message">
|
|
734
|
+
${message}
|
|
735
|
+
<span class="lze-blocker__dotting">
|
|
736
|
+
<span class="lze-blocker__dot"></span>
|
|
737
|
+
<span class="lze-blocker__dot"></span>
|
|
738
|
+
<span class="lze-blocker__dot"></span>
|
|
739
|
+
</span>
|
|
740
|
+
</div>
|
|
741
|
+
<div class="lze-blocker__error">${errorMessage}</div>
|
|
742
|
+
<div class="lze-blocker__error_suggestion">${suggestinMessage}</div>
|
|
743
|
+
</div>
|
|
744
|
+
`;
|
|
745
|
+
const style = `
|
|
746
|
+
div.lze-blocker {
|
|
747
|
+
position: fixed;
|
|
748
|
+
top: 0;
|
|
749
|
+
left: 0;
|
|
750
|
+
width: 100%;
|
|
751
|
+
height: 100%;
|
|
752
|
+
background: rgba(0, 0, 0, 0.85) !important;
|
|
753
|
+
z-index: ${zIndex};
|
|
754
|
+
display: flex;
|
|
755
|
+
align-items: center;
|
|
756
|
+
justify-content: center;
|
|
757
|
+
flex-direction: column;
|
|
758
|
+
color: #fff !important;
|
|
759
|
+
font-family: Arial, sans-serif;
|
|
760
|
+
text-align: center;
|
|
761
|
+
padding: 20px;
|
|
762
|
+
box-sizing: border-box;
|
|
763
|
+
overflow: hidden;
|
|
764
|
+
user-select: none;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
svg#lze-no-connection {
|
|
768
|
+
width: 75px;
|
|
769
|
+
height: 75px;
|
|
770
|
+
margin-bottom: 20px;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
div.lze-blocker__message {
|
|
774
|
+
color: #fff !important;
|
|
775
|
+
font-size: 18px !important;
|
|
776
|
+
margin-bottom: 10px;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.lze-blocker__dotting {
|
|
780
|
+
display: inline-block;
|
|
781
|
+
vertical-align: middle;
|
|
782
|
+
}
|
|
783
|
+
span.lze-blocker__dot {
|
|
784
|
+
display: inline-block;
|
|
785
|
+
width: 7px;
|
|
786
|
+
height: 7px;
|
|
787
|
+
background-color: #ffffff !important;
|
|
788
|
+
border-radius: 50%;
|
|
789
|
+
margin-left: 3px;
|
|
790
|
+
opacity: 0.3;
|
|
791
|
+
animation: dotting 1s infinite;
|
|
792
|
+
}
|
|
793
|
+
.lze-blocker__dot:nth-child(1) {
|
|
794
|
+
animation-delay: 0s;
|
|
795
|
+
opacity: 1;
|
|
796
|
+
}
|
|
797
|
+
.lze-blocker__dot:nth-child(2) {
|
|
798
|
+
animation-delay: 0.2s;
|
|
799
|
+
}
|
|
800
|
+
.lze-blocker__dot:nth-child(3) {
|
|
801
|
+
animation-delay: 0.4s;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
@keyframes dotting {
|
|
805
|
+
0%, 80%, 100% { opacity: 0.3; }
|
|
806
|
+
40% { opacity: 1; }
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
div.lze-blocker__error {
|
|
810
|
+
color: #f00;
|
|
811
|
+
font-size: 14px !important;
|
|
812
|
+
margin-bottom: 10px;
|
|
813
|
+
text-shadow: 0 0 1px #ff5f5f !important;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
div.lze-blocker__error_suggestion {
|
|
817
|
+
color: #ccc !important;
|
|
818
|
+
font-size: 14px !important;
|
|
819
|
+
margin-top: 10px;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
@keyframes spin {
|
|
823
|
+
0% { transform: rotate(0deg); }
|
|
824
|
+
100% { transform: rotate(360deg); }
|
|
825
|
+
}
|
|
826
|
+
`;
|
|
827
|
+
const styleElement = document.createElement('style');
|
|
828
|
+
if (add) {
|
|
829
|
+
if (!document.querySelector('.lze-blocker')) {
|
|
830
|
+
styleElement.innerHTML = style;
|
|
831
|
+
document.head.appendChild(styleElement);
|
|
832
|
+
body.insertAdjacentHTML('beforeend', blcokerHtml);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
this.removeBlocker(styleElement);
|
|
837
|
+
}
|
|
838
|
+
return styleElement;
|
|
839
|
+
}
|
|
840
|
+
removeBlocker(styleElement) {
|
|
841
|
+
const blocker = document.querySelector('.lze-blocker');
|
|
842
|
+
blocker?.remove();
|
|
843
|
+
styleElement?.remove();
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const ApiHelper = new LocalizeApiHelper();
|
|
847
|
+
|
|
848
|
+
const SCHEMES = LocalizeToken.httpHeaders;
|
|
849
|
+
class LocalizeApiService {
|
|
850
|
+
httpClient;
|
|
851
|
+
localizeTokenService;
|
|
852
|
+
destroy$ = new Subject();
|
|
853
|
+
configSubject = new BehaviorSubject({});
|
|
854
|
+
isRequestingSubject = new BehaviorSubject(false);
|
|
855
|
+
isResolvingStartupSubject = new BehaviorSubject(false);
|
|
856
|
+
get isResolvingStartup() { return this.isResolvingStartupSubject.value; }
|
|
857
|
+
get needTenant() { return this.localizeTokenService.config.tenantToken !== undefined; }
|
|
858
|
+
get isRequesting() { return this.isRequestingSubject.value; }
|
|
859
|
+
get isRevokingToken() { return this.localizeTokenService.isRevokingToken; }
|
|
860
|
+
set isRevokingToken(value) { this.localizeTokenService.isRevokingToken = value; }
|
|
861
|
+
get accessToken() { return this.localizeTokenService.accessToken; }
|
|
862
|
+
set accessToken(value) { this.localizeTokenService.accessToken = value; }
|
|
863
|
+
get refreshToken() { return this.localizeTokenService.refreshToken; }
|
|
864
|
+
get tenantToken() { return this.localizeTokenService.tenantToken; }
|
|
865
|
+
defaultConfig = {
|
|
866
|
+
waitEachRequest: { milliseconds: 0 },
|
|
867
|
+
enableRequestCancellation: true,
|
|
868
|
+
retryOptions: {
|
|
869
|
+
maxRetries: 1000,
|
|
870
|
+
delay: 1000,
|
|
871
|
+
retryFunction: ApiHelper.defaultRetryFunction.bind(this),
|
|
872
|
+
},
|
|
873
|
+
};
|
|
874
|
+
get config() {
|
|
875
|
+
this.validateConfig();
|
|
876
|
+
return this.configSubject.value;
|
|
877
|
+
}
|
|
878
|
+
apiOptions = {
|
|
879
|
+
method: EMethod.GET,
|
|
880
|
+
requestBody: null,
|
|
881
|
+
};
|
|
882
|
+
constructor(httpClient, localizeTokenService) {
|
|
883
|
+
this.httpClient = httpClient;
|
|
884
|
+
this.localizeTokenService = localizeTokenService;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Initialize the API service.
|
|
888
|
+
* @param apiConfigs - The API configurations.
|
|
889
|
+
*/
|
|
890
|
+
init(apiConfigs) {
|
|
891
|
+
console.log('LocalizeApiService is initialized.');
|
|
892
|
+
this.configSubject.next({ ...this.defaultConfig, ...apiConfigs });
|
|
893
|
+
}
|
|
894
|
+
cancelPendingRequests() {
|
|
895
|
+
this.config.enableRequestCancellation
|
|
896
|
+
&& this.destroy$.next();
|
|
897
|
+
}
|
|
898
|
+
ngOnDestroy() {
|
|
899
|
+
this.destroy$.next();
|
|
900
|
+
this.destroy$.complete();
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* A higher-order function that returns a curried function for making API requests.
|
|
904
|
+
*
|
|
905
|
+
* @param baseUrl - The base URL of the API.
|
|
906
|
+
* @returns A curried function that can be used to make API requests.
|
|
907
|
+
*/
|
|
908
|
+
func = (baseUrl) => (path, method = EMethod.GET, reqBody = null, reqHeaders) => this.request(baseUrl, path, method, reqBody, reqHeaders);
|
|
909
|
+
async request(baseUrl, path, method = EMethod.GET, reqBody = null, reqHeaders) {
|
|
910
|
+
await waitUntil(() => !this.isResolvingStartup, 500);
|
|
911
|
+
await ApiHelper.invokeHook(this.config.onPrepareRequest);
|
|
912
|
+
const apiOptions = this.buildApiOptions(baseUrl, path, method, reqBody, reqHeaders);
|
|
913
|
+
try {
|
|
914
|
+
await this.toWaitForPreviousRequest();
|
|
915
|
+
return await ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
return await this.handleOnRequestError(error, apiOptions);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
async handleOnRequestError(error, options) {
|
|
922
|
+
if (error.status !== 401)
|
|
923
|
+
throw error;
|
|
924
|
+
await waitUntil(() => !this.isResolvingStartup, 50);
|
|
925
|
+
return await ApiHelper.performRetry({
|
|
926
|
+
maxRetries: () => 1000,
|
|
927
|
+
delay: 10,
|
|
928
|
+
retryUnless: (error) => error.status === 401 || ApiHelper.isConnectionError(error),
|
|
929
|
+
callback: async () => {
|
|
930
|
+
// Only handle 401 Unauthorized errors
|
|
931
|
+
await this.revokeToken();
|
|
932
|
+
// Retry the request with the new access token
|
|
933
|
+
return await this.performRequest(options);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
async performRequest(options) {
|
|
938
|
+
// Build the request options
|
|
939
|
+
const buildOptions = { headers: this.buildHeaderOptions(options) };
|
|
940
|
+
// Create the request observable
|
|
941
|
+
const request$ = ApiHelper.createRequest({
|
|
942
|
+
client: this.httpClient,
|
|
943
|
+
destroy$: () => this.destroy$
|
|
944
|
+
}, options.method, options.requestUrl, options.requestBody, buildOptions);
|
|
945
|
+
// Set the isRequesting state to true before making the request
|
|
946
|
+
this.isRequestingSubject.next(true);
|
|
947
|
+
const response = await new Promise((resolve, reject) => request$.subscribe({ next: (res) => resolve(res.body), error: reject }));
|
|
948
|
+
// Reset the isRequesting state after the request completes
|
|
949
|
+
this.isRequestingSubject.next(false);
|
|
950
|
+
return response;
|
|
951
|
+
}
|
|
952
|
+
async revokeToken() {
|
|
953
|
+
try {
|
|
954
|
+
if (await this.interceptRevokeToken())
|
|
955
|
+
return;
|
|
956
|
+
this.isRevokingToken = true;
|
|
957
|
+
const apiOptions = {
|
|
958
|
+
...this.buildApiOptions(this.localizeTokenService.config.refreshToken?.requestUrl || ''),
|
|
959
|
+
refreshToken: true,
|
|
960
|
+
};
|
|
961
|
+
// const revokeToken = await this.performRequest(apiOptions);
|
|
962
|
+
const revokeToken = await ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
|
|
963
|
+
await this.handleOnTokenRevoked(revokeToken);
|
|
964
|
+
}
|
|
965
|
+
catch (error) {
|
|
966
|
+
// Handle the error, log it
|
|
967
|
+
await ApiHelper.invokeHook(this.config.onAutoLogout);
|
|
968
|
+
}
|
|
969
|
+
finally {
|
|
970
|
+
// Reset the revoking token state
|
|
971
|
+
this.isRevokingToken = false;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
/** default http request options */
|
|
975
|
+
buildHeaderOptions(options) {
|
|
976
|
+
const headers = {
|
|
977
|
+
...(options.refreshToken && { [SCHEMES.X_REFRESH_TOKEN]: `${this.refreshToken}` }),
|
|
978
|
+
...(!options.isFormData && { [SCHEMES.CONTENT_TYPE]: 'application/json' }),
|
|
979
|
+
[SCHEMES.AUTHORIZATION]: `Bearer ${this.accessToken}`,
|
|
980
|
+
...(this.needTenant && { [SCHEMES.X_TENANT]: `${this.tenantToken}` })
|
|
981
|
+
};
|
|
982
|
+
return new HttpHeaders({ ...headers, ...options.headers });
|
|
983
|
+
}
|
|
984
|
+
buildApiOptions(baseUrl, path = '', method = EMethod.GET, requestBody = null, headers) {
|
|
985
|
+
const requestUrl = ApiHelper.buildUrl(baseUrl, path);
|
|
986
|
+
const isFormData = requestBody && requestBody instanceof FormData;
|
|
987
|
+
return {
|
|
988
|
+
...this.apiOptions,
|
|
989
|
+
...{ headers, method, requestUrl, requestBody, isFormData }
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
async toWaitForPreviousRequest() {
|
|
993
|
+
if (this.isRevokingToken) {
|
|
994
|
+
// console.warn('A token refresh is in progress. Request is waiting.');
|
|
995
|
+
await waitUntil(() => !this.isRevokingToken);
|
|
996
|
+
// console.info('Token refresh complete. Resuming request.');
|
|
997
|
+
}
|
|
998
|
+
// to wait for each request in 50ms, even if the request is not completed
|
|
999
|
+
const waitMilliseconds = this.config.waitEachRequest?.milliseconds;
|
|
1000
|
+
if (waitMilliseconds && this.isRequesting) {
|
|
1001
|
+
// console.warn(`Request throttling: Another request is in progress. Waiting for ${waitMilliseconds}ms.`);
|
|
1002
|
+
await waitFor(waitMilliseconds, this.isRequesting);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async handleOnTokenRevoked(response) {
|
|
1006
|
+
if (response?.status) {
|
|
1007
|
+
// If the response is successful, update the access token
|
|
1008
|
+
this.accessToken = response.message;
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
// If the response indicates an error, invoke the onRevokeUnauthorized hook
|
|
1012
|
+
console.warn('Token revocation failed, refresh token is expired.', response.message);
|
|
1013
|
+
await ApiHelper.invokeHook(this.config.onRevokeUnauthorized);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
async interceptRevokeToken() {
|
|
1017
|
+
if (this.isRevokingToken) {
|
|
1018
|
+
console.warn('Token is already being revoked. Waiting for the current operation to complete...');
|
|
1019
|
+
await waitUntil(() => !this.isRevokingToken);
|
|
1020
|
+
return true;
|
|
1021
|
+
}
|
|
1022
|
+
if (!this.refreshToken) {
|
|
1023
|
+
// await ApiHelper.invokeHook(this.apiConfigs.onAutoLogout);
|
|
1024
|
+
throw new Error('Refresh token is missing. Please login again.');
|
|
1025
|
+
}
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
validateConfig() {
|
|
1029
|
+
if (this.localizeTokenService.config.tenantToken
|
|
1030
|
+
&& !this.localizeTokenService.config.tenantToken?.name?.trim().length) {
|
|
1031
|
+
throw Error('Tenant token is required but tenantTokenName is not configured');
|
|
1032
|
+
}
|
|
1033
|
+
if (!this.localizeTokenService.config.refreshToken?.requestUrl?.trim().length) {
|
|
1034
|
+
throw Error('Revoke token URL is not configured - token refresh will not work');
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, deps: [{ token: i4.HttpClient }, { token: LocalizeTokenService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1038
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, providedIn: 'root' });
|
|
1039
|
+
}
|
|
1040
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiService, decorators: [{
|
|
1041
|
+
type: Injectable,
|
|
1042
|
+
args: [{
|
|
1043
|
+
providedIn: 'root'
|
|
1044
|
+
}]
|
|
1045
|
+
}], ctorParameters: () => [{ type: i4.HttpClient }, { type: LocalizeTokenService }] });
|
|
1046
|
+
|
|
1047
|
+
class LocalizeTokenModule {
|
|
1048
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1049
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule });
|
|
1050
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, providers: [
|
|
1051
|
+
LocalizeTokenService,
|
|
1052
|
+
LocalizeApiService
|
|
1053
|
+
] });
|
|
1054
|
+
}
|
|
1055
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeTokenModule, decorators: [{
|
|
1056
|
+
type: NgModule,
|
|
1057
|
+
args: [{
|
|
1058
|
+
providers: [
|
|
1059
|
+
LocalizeTokenService,
|
|
1060
|
+
LocalizeApiService
|
|
1061
|
+
]
|
|
1062
|
+
}]
|
|
1063
|
+
}] });
|
|
1064
|
+
|
|
1065
|
+
class LocalizeApiTokenService {
|
|
1066
|
+
api;
|
|
1067
|
+
token;
|
|
1068
|
+
loginDialog;
|
|
1069
|
+
constructor(tokenService, apiService, loginDialogService) {
|
|
1070
|
+
this.api = apiService;
|
|
1071
|
+
this.token = tokenService;
|
|
1072
|
+
this.loginDialog = loginDialogService;
|
|
1073
|
+
}
|
|
1074
|
+
initialize(tokenConfig, apiConfig) {
|
|
1075
|
+
// Initialize the LocalizeTokenService with the provided token configuration
|
|
1076
|
+
this.token.init(tokenConfig);
|
|
1077
|
+
// Initialize the LocalizeApiService with the provided API configuration
|
|
1078
|
+
this.api.init(apiConfig);
|
|
1079
|
+
console.log('LocalizeApiTokenService initialized with token and API configurations.');
|
|
1080
|
+
}
|
|
1081
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenService, deps: [{ token: LocalizeTokenService }, { token: LocalizeApiService }, { token: LocalizeLogindlgService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1082
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenService, providedIn: 'root' });
|
|
1083
|
+
}
|
|
1084
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenService, decorators: [{
|
|
1085
|
+
type: Injectable,
|
|
1086
|
+
args: [{
|
|
1087
|
+
providedIn: 'root'
|
|
1088
|
+
}]
|
|
1089
|
+
}], ctorParameters: () => [{ type: LocalizeTokenService }, { type: LocalizeApiService }, { type: LocalizeLogindlgService }] });
|
|
1090
|
+
|
|
1091
|
+
class LocalizeApiTokenModule {
|
|
1092
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1093
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenModule, imports: [CommonModule,
|
|
1094
|
+
LocalizeTokenModule,
|
|
1095
|
+
LocalizeLogindlgModule] });
|
|
1096
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenModule, providers: [
|
|
1097
|
+
LocalizeApiTokenService
|
|
1098
|
+
], imports: [CommonModule,
|
|
1099
|
+
LocalizeTokenModule,
|
|
1100
|
+
LocalizeLogindlgModule] });
|
|
1101
|
+
}
|
|
1102
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LocalizeApiTokenModule, decorators: [{
|
|
1103
|
+
type: NgModule,
|
|
1104
|
+
args: [{
|
|
1105
|
+
declarations: [],
|
|
1106
|
+
imports: [
|
|
1107
|
+
CommonModule,
|
|
1108
|
+
LocalizeTokenModule,
|
|
1109
|
+
LocalizeLogindlgModule
|
|
1110
|
+
],
|
|
1111
|
+
providers: [
|
|
1112
|
+
LocalizeApiTokenService
|
|
1113
|
+
]
|
|
1114
|
+
}]
|
|
1115
|
+
}] });
|
|
1116
|
+
|
|
1117
|
+
//#region login dialog
|
|
1118
|
+
|
|
695
1119
|
/**
|
|
696
1120
|
* Generated bundle index. Do not edit.
|
|
697
1121
|
*/
|
|
698
1122
|
|
|
699
|
-
export { EMethod, LocalizeApiService, LocalizeLogindlgComponent, LocalizeLogindlgModule, LocalizeLogindlgService, LocalizeToken, LocalizeTokenModule, LocalizeTokenService, LocalizeTokenStorage, extractMainDomain, waitFor, waitUntil };
|
|
1123
|
+
export { ApiHelper, EMethod, LOCALIZE_API_ASSETS, LocalizeApiService, LocalizeApiTokenModule, LocalizeApiTokenService, LocalizeLogindlgComponent, LocalizeLogindlgModule, LocalizeLogindlgService, LocalizeToken, LocalizeTokenModule, LocalizeTokenService, LocalizeTokenStorage, extractMainDomain, waitFor, waitUntil };
|
|
700
1124
|
//# sourceMappingURL=sambath999-localize-token.mjs.map
|