@arsedizioni/ars-utils 21.2.209 → 21.2.221
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/arsedizioni-ars-utils-clipper.common.mjs +179 -159
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs +2939 -2939
- package/fesm2022/arsedizioni-ars-utils-clipper.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.mjs +101 -101
- package/fesm2022/arsedizioni-ars-utils-core.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +280 -252
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-help.mjs +115 -102
- package/fesm2022/arsedizioni-ars-utils-help.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs +43 -36
- package/fesm2022/arsedizioni-ars-utils-support.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-support.ui.mjs +68 -77
- package/fesm2022/arsedizioni-ars-utils-support.ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-tinymce.mjs +41 -26
- package/fesm2022/arsedizioni-ars-utils-tinymce.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.application.mjs +1461 -1390
- package/fesm2022/arsedizioni-ars-utils-ui.application.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.mjs +1349 -1204
- package/fesm2022/arsedizioni-ars-utils-ui.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs +29 -25
- package/fesm2022/arsedizioni-ars-utils-ui.oauth.mjs.map +1 -1
- package/package.json +1 -1
- package/types/arsedizioni-ars-utils-clipper.common.d.ts +88 -62
- package/types/arsedizioni-ars-utils-clipper.ui.d.ts +196 -196
- package/types/arsedizioni-ars-utils-core.d.ts +16 -16
- package/types/arsedizioni-ars-utils-evolution.common.d.ts +131 -70
- package/types/arsedizioni-ars-utils-help.d.ts +76 -66
- package/types/arsedizioni-ars-utils-support.common.d.ts +29 -19
- package/types/arsedizioni-ars-utils-support.ui.d.ts +29 -25
- package/types/arsedizioni-ars-utils-tinymce.d.ts +25 -10
- package/types/arsedizioni-ars-utils-ui.application.d.ts +597 -467
- package/types/arsedizioni-ars-utils-ui.d.ts +474 -337
- package/types/arsedizioni-ars-utils-ui.oauth.d.ts +25 -18
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, signal, Injectable, NgModule } from '@angular/core';
|
|
3
|
+
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
|
|
3
4
|
import { BroadcastService, SystemUtils } from '@arsedizioni/ars-utils/core';
|
|
4
5
|
import { EMPTY, throwError, of, catchError as catchError$1 } from 'rxjs';
|
|
5
|
-
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
6
6
|
import { DialogService } from '@arsedizioni/ars-utils/ui';
|
|
7
7
|
import { catchError, finalize, map } from 'rxjs/operators';
|
|
8
8
|
|
|
@@ -481,121 +481,140 @@ var ERPPlace;
|
|
|
481
481
|
class EvolutionComplianceContextInfo {
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
/**
|
|
485
|
+
* Core service for the Evolution compliance module.
|
|
486
|
+
* Manages authentication (login / logout / MFA), session persistence,
|
|
487
|
+
* and HTTP access to all Evolution API endpoints.
|
|
488
|
+
*/
|
|
484
489
|
class EvolutionService {
|
|
485
490
|
constructor() {
|
|
486
491
|
this.httpClient = inject(HttpClient);
|
|
487
492
|
this.broadcastService = inject(BroadcastService);
|
|
488
493
|
this.dialogService = inject(DialogService);
|
|
489
|
-
this._serviceUri = undefined;
|
|
490
494
|
this._flags = EvolutionServiceFlags.None;
|
|
495
|
+
/** `true` when the user has an active (non-temporary) session. */
|
|
491
496
|
this.loggedIn = signal(false, ...(ngDevMode ? [{ debugName: "loggedIn" }] : /* istanbul ignore next */ []));
|
|
497
|
+
/** `true` while a login request is in flight. */
|
|
492
498
|
this.loggingIn = signal(false, ...(ngDevMode ? [{ debugName: "loggingIn" }] : /* istanbul ignore next */ []));
|
|
493
499
|
}
|
|
500
|
+
/** Base URI of the Evolution back-end service. */
|
|
494
501
|
get serviceUri() {
|
|
495
502
|
return this._serviceUri;
|
|
496
503
|
}
|
|
504
|
+
/** Feature flags controlling service behaviour (notifications, embedded mode, etc.). */
|
|
497
505
|
get flags() {
|
|
498
506
|
return this._flags;
|
|
499
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Returns the current login info, hydrating it from `localStorage` on first access
|
|
510
|
+
* when no in-memory value is available.
|
|
511
|
+
*/
|
|
500
512
|
get loginInfo() {
|
|
501
513
|
if (!this._loginInfo) {
|
|
502
|
-
const
|
|
503
|
-
if (
|
|
514
|
+
const raw = localStorage.getItem('evolution_context');
|
|
515
|
+
if (raw) {
|
|
504
516
|
try {
|
|
505
|
-
this._loginInfo = JSON.parse(
|
|
517
|
+
this._loginInfo = JSON.parse(raw);
|
|
506
518
|
}
|
|
507
|
-
catch { }
|
|
519
|
+
catch { /* invalid JSON — ignore and leave undefined */ }
|
|
508
520
|
}
|
|
509
521
|
}
|
|
510
522
|
return this._loginInfo;
|
|
511
523
|
}
|
|
512
524
|
ngOnDestroy() {
|
|
513
|
-
|
|
514
|
-
this.broadcastServiceSubscription.unsubscribe();
|
|
515
|
-
}
|
|
525
|
+
this.broadcastServiceSubscription?.unsubscribe();
|
|
516
526
|
}
|
|
517
527
|
/**
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
* @param
|
|
528
|
+
* Initialises the service with the back-end URI and optional feature flags.
|
|
529
|
+
* Must be called once during application bootstrap before any other method.
|
|
530
|
+
* @param serviceUri - Base URL of the Evolution service (e.g. `'https://api.example.com/evolution'`).
|
|
531
|
+
* @param flags - Bitmask of `EvolutionServiceFlags` (default: `None`).
|
|
521
532
|
*/
|
|
522
533
|
initialize(serviceUri, flags = EvolutionServiceFlags.None) {
|
|
523
|
-
// Create unique client
|
|
534
|
+
// Create a unique per-tab client ID if not already set
|
|
524
535
|
if (!sessionStorage.getItem('evolution_client_id')) {
|
|
525
|
-
sessionStorage.setItem('evolution_client_id', (flags
|
|
536
|
+
sessionStorage.setItem('evolution_client_id', (flags & EvolutionServiceFlags.Embedded) > 0
|
|
526
537
|
? 'embedded'
|
|
527
538
|
: SystemUtils.generateUUID());
|
|
528
539
|
}
|
|
529
|
-
// Initialize
|
|
530
540
|
this._serviceUri = serviceUri;
|
|
531
541
|
this._flags = flags;
|
|
532
|
-
//
|
|
542
|
+
// Subscribe to broadcast messages (only once)
|
|
533
543
|
if (!this.broadcastServiceSubscription) {
|
|
534
|
-
this.broadcastServiceSubscription = this.broadcastService
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (!r.success) {
|
|
539
|
-
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
540
|
-
this.dialogService.error("Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso.", undefined, "Errore di Evolution");
|
|
541
|
-
}
|
|
542
|
-
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_FAILED);
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
546
|
-
this.dialogService.toast('Connesso a Evolution', 1500, 'power');
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
},
|
|
550
|
-
error: () => { console.error("Evolution non disponibile."); } // Avoid unwanted errors on client
|
|
551
|
-
});
|
|
552
|
-
}
|
|
553
|
-
else if (message.id === EvolutionMessages.LOGOUT) {
|
|
554
|
-
if (this.loggedIn()) {
|
|
555
|
-
this.logout().subscribe(r => {
|
|
556
|
-
if (!r.success) {
|
|
557
|
-
if (r.message) {
|
|
558
|
-
this.dialogService.error("<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Evolution accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>", null, "Errore di Evolution");
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
else {
|
|
562
|
-
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
563
|
-
this.dialogService.toast('Disconnesso da Evolution', 1500, 'power_off');
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
this.clear();
|
|
570
|
-
}
|
|
571
|
-
}
|
|
544
|
+
this.broadcastServiceSubscription = this.broadcastService
|
|
545
|
+
.getMessage()
|
|
546
|
+
.subscribe((message) => {
|
|
547
|
+
this.handleBroadcastMessage(message);
|
|
572
548
|
});
|
|
573
549
|
}
|
|
574
|
-
//
|
|
550
|
+
// If a session is already active (e.g. after an F5 page refresh), notify consumers
|
|
575
551
|
if (this.loggedIn()) {
|
|
576
|
-
// Auto login
|
|
577
552
|
this.loggingIn.set(false);
|
|
578
|
-
// Notify
|
|
579
553
|
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_COMPLETED);
|
|
580
554
|
}
|
|
581
555
|
}
|
|
582
556
|
/**
|
|
583
|
-
|
|
584
|
-
|
|
557
|
+
* Dispatches an incoming broadcast message to the appropriate handler.
|
|
558
|
+
* @param message - The message received from the broadcast channel.
|
|
559
|
+
*/
|
|
560
|
+
handleBroadcastMessage(message) {
|
|
561
|
+
if (message.id === EvolutionMessages.LOGIN_CHANGED) {
|
|
562
|
+
const data = message.data;
|
|
563
|
+
this.login(undefined, undefined, true, data?.['oauth'], data?.['oauthAccessToken']).subscribe({
|
|
564
|
+
next: r => {
|
|
565
|
+
if (!r.success) {
|
|
566
|
+
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
567
|
+
this.dialogService.error("Le credenziali di accesso sono cambiate o non sono più valide. Esegui un nuovo accesso.", undefined, "Errore di Evolution");
|
|
568
|
+
}
|
|
569
|
+
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_FAILED);
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
573
|
+
this.dialogService.toast('Connesso a Evolution', 1500, 'power');
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
error: () => { console.error('Evolution non disponibile.'); }
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
else if (message.id === EvolutionMessages.LOGOUT) {
|
|
581
|
+
if (this.loggedIn()) {
|
|
582
|
+
this.logout().subscribe(r => {
|
|
583
|
+
if (!r.success) {
|
|
584
|
+
if (r.message) {
|
|
585
|
+
this.dialogService.error("<p>" + r.message + "</p><br><br><hr><p class='small'><i>Per eliminare la configurazione di Evolution accedere a:<br><b>menu > personalizza > collegamenti</b></i></p>", undefined, "Errore di Evolution");
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
if ((this.flags & EvolutionServiceFlags.DisplayConnectionStateMessages) > 0) {
|
|
590
|
+
this.dialogService.toast('Disconnesso da Evolution', 1500, 'power_off');
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
this.clear();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Sends a one-shot ping to the back end to verify connectivity.
|
|
602
|
+
*/
|
|
585
603
|
ping() {
|
|
586
|
-
this.httpClient
|
|
587
|
-
.
|
|
604
|
+
this.httpClient
|
|
605
|
+
.get(this._serviceUri + '/ping?nocache=' + SystemUtils.generateUUID())
|
|
606
|
+
.pipe(catchError(() => EMPTY))
|
|
588
607
|
.subscribe();
|
|
589
608
|
}
|
|
590
609
|
/**
|
|
591
|
-
|
|
592
|
-
|
|
610
|
+
* Persists the current login info to `localStorage`.
|
|
611
|
+
*/
|
|
593
612
|
storeContext() {
|
|
594
613
|
localStorage.setItem('evolution_context', JSON.stringify(this._loginInfo));
|
|
595
614
|
}
|
|
596
615
|
/**
|
|
597
|
-
*
|
|
598
|
-
* @param result
|
|
616
|
+
* Merges a login result into the stored login info and persists it.
|
|
617
|
+
* @param result - The `EvolutionLoginResult` returned by the login endpoint.
|
|
599
618
|
*/
|
|
600
619
|
updateContext(result) {
|
|
601
620
|
if (!this._loginInfo) {
|
|
@@ -605,24 +624,24 @@ class EvolutionService {
|
|
|
605
624
|
this.storeContext();
|
|
606
625
|
}
|
|
607
626
|
/**
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
627
|
+
* Performs an automatic login using the credentials already stored in the session.
|
|
628
|
+
* Shows a busy indicator and handles success/failure dialogs.
|
|
629
|
+
* @param onSuccess - Optional callback invoked after a successful login.
|
|
630
|
+
* @returns `true` (always) — the result is handled via the subscription callbacks.
|
|
631
|
+
*/
|
|
611
632
|
autoLogin(onSuccess) {
|
|
612
|
-
this.login(
|
|
633
|
+
this.login(undefined, undefined, true)
|
|
613
634
|
.pipe(finalize(() => this.dialogService.clearBusy()))
|
|
614
635
|
.subscribe({
|
|
615
636
|
next: r => {
|
|
616
637
|
if (!r.success) {
|
|
617
|
-
this.dialogService.error(r.message,
|
|
638
|
+
this.dialogService.error(r.message, undefined, "Errore in Evolution");
|
|
618
639
|
}
|
|
619
640
|
else {
|
|
620
|
-
if (!r.value
|
|
641
|
+
if (!r.value?.requiresMfa) {
|
|
621
642
|
this.dialogService.toast('Connesso ad Evolution', 1500, 'power');
|
|
622
643
|
}
|
|
623
|
-
|
|
624
|
-
onSuccess();
|
|
625
|
-
}
|
|
644
|
+
onSuccess?.();
|
|
626
645
|
}
|
|
627
646
|
},
|
|
628
647
|
error: () => { this.dialogService.error("Evolution non disponibile."); }
|
|
@@ -630,16 +649,15 @@ class EvolutionService {
|
|
|
630
649
|
return true;
|
|
631
650
|
}
|
|
632
651
|
/**
|
|
633
|
-
*
|
|
634
|
-
* @param onSuccess
|
|
652
|
+
* Performs an automatic logout, notifying the user when the session ends.
|
|
653
|
+
* @param onSuccess - Optional callback invoked after the logout completes.
|
|
635
654
|
*/
|
|
636
655
|
autoLogout(onSuccess) {
|
|
637
|
-
this.logout()
|
|
638
|
-
.subscribe({
|
|
656
|
+
this.logout().subscribe({
|
|
639
657
|
next: r => {
|
|
640
658
|
if (!r.success) {
|
|
641
659
|
if (r.message) {
|
|
642
|
-
this.dialogService.error(r.message,
|
|
660
|
+
this.dialogService.error(r.message, undefined, "Errore in Evolution");
|
|
643
661
|
}
|
|
644
662
|
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_CHANGED);
|
|
645
663
|
}
|
|
@@ -650,48 +668,43 @@ class EvolutionService {
|
|
|
650
668
|
error: () => { },
|
|
651
669
|
complete: () => {
|
|
652
670
|
this.dialogService.clearBusy();
|
|
653
|
-
|
|
654
|
-
onSuccess();
|
|
655
|
-
}
|
|
671
|
+
onSuccess?.();
|
|
656
672
|
}
|
|
657
673
|
});
|
|
658
674
|
}
|
|
659
675
|
/**
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
* @
|
|
663
|
-
* @param
|
|
664
|
-
* @param
|
|
665
|
-
* @param
|
|
676
|
+
* Authenticates the user against the Evolution back end.
|
|
677
|
+
* Supports both credential-based and OAuth2 login flows.
|
|
678
|
+
* @param email - User e-mail (credential login only; omit for OAuth2).
|
|
679
|
+
* @param password - User password (credential login only; omit for OAuth2).
|
|
680
|
+
* @param remember - Whether to persist the session across browser restarts.
|
|
681
|
+
* @param oauth - OAuth2 provider type, when using federated login.
|
|
682
|
+
* @param oauthAccessToken - Bearer token from the OAuth2 provider.
|
|
683
|
+
* @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
|
|
666
684
|
*/
|
|
667
|
-
login(email, password, remember, oauth, oauthAccessToken = sessionStorage.getItem(
|
|
685
|
+
login(email, password, remember, oauth, oauthAccessToken = sessionStorage.getItem('evolution_oauth_token') ?? undefined) {
|
|
668
686
|
return this.httpClient
|
|
669
687
|
.post(this._serviceUri + '/login2', {
|
|
670
688
|
user: oauth ? null : email,
|
|
671
689
|
password: oauth ? null : password,
|
|
672
|
-
remember
|
|
673
|
-
oauth
|
|
690
|
+
remember,
|
|
691
|
+
oauth
|
|
674
692
|
}, {
|
|
675
|
-
headers:
|
|
676
|
-
? new HttpHeaders()
|
|
693
|
+
headers: oauth && oauthAccessToken
|
|
694
|
+
? new HttpHeaders().set('Authorization', oauthAccessToken)
|
|
677
695
|
: new HttpHeaders()
|
|
678
|
-
.set("Authorization", oauthAccessToken ?? '')
|
|
679
696
|
})
|
|
680
|
-
.pipe(catchError(err => {
|
|
681
|
-
return throwError(() => err);
|
|
682
|
-
}), map((r) => {
|
|
697
|
+
.pipe(catchError(err => throwError(() => err)), map((r) => {
|
|
683
698
|
if (r.success) {
|
|
684
699
|
if (!this._loginInfo) {
|
|
685
700
|
this._loginInfo = { context: undefined };
|
|
686
701
|
}
|
|
687
702
|
this._loginInfo.oauth = oauth;
|
|
688
703
|
this._loginInfo.remember = remember;
|
|
689
|
-
if (!oauth && r.value
|
|
690
|
-
// Notify login is pending
|
|
704
|
+
if (!oauth && r.value?.requiresMfa) {
|
|
691
705
|
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_PENDING, {});
|
|
692
706
|
}
|
|
693
707
|
else {
|
|
694
|
-
// Complete login
|
|
695
708
|
this.completeLogin(r.value);
|
|
696
709
|
}
|
|
697
710
|
}
|
|
@@ -699,289 +712,304 @@ class EvolutionService {
|
|
|
699
712
|
}));
|
|
700
713
|
}
|
|
701
714
|
/**
|
|
702
|
-
*
|
|
703
|
-
* @param result
|
|
715
|
+
* Finalises a successful login by updating the stored context and notifying consumers.
|
|
716
|
+
* @param result - The login result payload from the server.
|
|
704
717
|
*/
|
|
705
718
|
completeLogin(result) {
|
|
706
|
-
// Update context info
|
|
707
719
|
this.updateContext(result);
|
|
708
720
|
this.loggedIn.set(!result.context?.isTemporary);
|
|
709
721
|
this.loggingIn.set(false);
|
|
710
|
-
// Keep alive
|
|
711
|
-
// Notify
|
|
712
722
|
this.broadcastService.sendMessage(EvolutionMessages.LOGIN_COMPLETED);
|
|
713
723
|
}
|
|
714
724
|
/**
|
|
715
|
-
*
|
|
716
|
-
* @param code
|
|
725
|
+
* Confirms a multi-factor authentication challenge and completes the login.
|
|
726
|
+
* @param code - The one-time MFA code entered by the user.
|
|
727
|
+
* @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
|
|
717
728
|
*/
|
|
718
729
|
confirmIdentity(code) {
|
|
719
730
|
return this.httpClient
|
|
720
731
|
.post(this._serviceUri + '/login/confirm/' + code, {})
|
|
721
|
-
.pipe(catchError((err) => {
|
|
722
|
-
return throwError(() => err);
|
|
723
|
-
}), map((r) => {
|
|
732
|
+
.pipe(catchError(err => throwError(() => err)), map((r) => {
|
|
724
733
|
if (r.success) {
|
|
725
|
-
// Complete login
|
|
726
734
|
this.completeLogin(r.value);
|
|
727
735
|
}
|
|
728
736
|
return r;
|
|
729
737
|
}));
|
|
730
738
|
}
|
|
731
739
|
/**
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
740
|
+
* Logs the current user out of the back end and clears local session data.
|
|
741
|
+
* @param forget - When `true`, instructs the server to discard all stored credentials.
|
|
742
|
+
* @returns An observable that emits `ApiResult<unknown>`.
|
|
743
|
+
*/
|
|
735
744
|
logout(forget = false) {
|
|
736
|
-
return this.httpClient
|
|
745
|
+
return this.httpClient
|
|
746
|
+
.post(this._serviceUri + '/logout/?forget=' + forget, {})
|
|
737
747
|
.pipe(finalize(() => {
|
|
738
748
|
this.clear();
|
|
739
|
-
// Clean up
|
|
740
749
|
localStorage.removeItem('evolution_context');
|
|
741
|
-
}), catchError((
|
|
742
|
-
return of([]);
|
|
743
|
-
}));
|
|
750
|
+
}), catchError(() => of({ success: false, value: undefined, message: undefined })));
|
|
744
751
|
}
|
|
745
752
|
/**
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
753
|
+
* Switches the active session to a different user account while retaining credentials.
|
|
754
|
+
* @param id - The user ID to switch to.
|
|
755
|
+
* @returns An observable that emits the `ApiResult<EvolutionLoginResult>`.
|
|
756
|
+
*/
|
|
749
757
|
loginSwitch(id) {
|
|
750
758
|
return this.httpClient
|
|
751
|
-
.post(this._serviceUri + '/login/switch', {
|
|
752
|
-
|
|
753
|
-
})
|
|
754
|
-
.pipe(catchError((err) => {
|
|
755
|
-
return throwError(() => err);
|
|
756
|
-
}), map((r) => {
|
|
759
|
+
.post(this._serviceUri + '/login/switch', { userId: id })
|
|
760
|
+
.pipe(catchError(err => throwError(() => err)), map((r) => {
|
|
757
761
|
if (r.success) {
|
|
758
|
-
// Update login
|
|
759
762
|
this.completeLogin(r.value);
|
|
760
763
|
}
|
|
761
764
|
return r;
|
|
762
765
|
}));
|
|
763
766
|
}
|
|
764
767
|
/**
|
|
765
|
-
*
|
|
768
|
+
* Resets the in-memory login state and broadcasts a logout-completed event.
|
|
769
|
+
* Does **not** touch `sessionStorage` or `localStorage`; call `clear()` for a full cleanup.
|
|
766
770
|
*/
|
|
767
771
|
reset() {
|
|
768
|
-
// Clear login info
|
|
769
772
|
this._loginInfo = undefined;
|
|
770
|
-
// Logged out
|
|
771
773
|
this.loggedIn.set(false);
|
|
772
|
-
// Notify
|
|
773
774
|
this.broadcastService.sendMessage(EvolutionMessages.LOGOUT_COMPLETED);
|
|
774
775
|
}
|
|
775
776
|
/**
|
|
776
|
-
*
|
|
777
|
-
* @param clearOAuthToken
|
|
777
|
+
* Removes Evolution session data from `sessionStorage` and calls `reset()`.
|
|
778
|
+
* @param clearOAuthToken - When `true`, also removes the stored OAuth2 access token.
|
|
778
779
|
*/
|
|
779
780
|
clear(clearOAuthToken = false) {
|
|
780
|
-
// Clear local storage
|
|
781
781
|
sessionStorage.removeItem('evolution_auth');
|
|
782
782
|
sessionStorage.removeItem('evolution_refresh');
|
|
783
783
|
sessionStorage.removeItem('evolution_oauth');
|
|
784
784
|
if (clearOAuthToken) {
|
|
785
785
|
sessionStorage.removeItem('evolution_oauth_token');
|
|
786
786
|
}
|
|
787
|
-
// Reset login
|
|
788
787
|
this.reset();
|
|
789
788
|
}
|
|
790
789
|
/**
|
|
791
|
-
*
|
|
792
|
-
* @param folders
|
|
790
|
+
* Converts a flat list of `INode` items into a hierarchical tree structure.
|
|
791
|
+
* @param folders - The root-level nodes to convert.
|
|
792
|
+
* @returns An array of `INode` objects with nested `children`.
|
|
793
793
|
*/
|
|
794
794
|
toNodes(folders) {
|
|
795
|
-
return this._toNodes(folders,
|
|
795
|
+
return this._toNodes(folders, undefined);
|
|
796
796
|
}
|
|
797
797
|
/**
|
|
798
|
-
*
|
|
799
|
-
* @param folders
|
|
798
|
+
* Recursive helper for `toNodes`.
|
|
799
|
+
* @param folders - The nodes to process at the current depth level.
|
|
800
|
+
* @param parent - The parent node, or `undefined` at the root level.
|
|
801
|
+
* @returns An array of `INode` objects with nested `children`.
|
|
800
802
|
*/
|
|
801
803
|
_toNodes(folders, parent) {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
804
|
+
const nodes = [];
|
|
805
|
+
for (const n of folders) {
|
|
806
|
+
const node = {
|
|
805
807
|
id: n.id,
|
|
806
808
|
name: n.name,
|
|
807
809
|
count: n.count,
|
|
808
|
-
parent
|
|
809
|
-
children:
|
|
810
|
+
parent,
|
|
811
|
+
children: undefined,
|
|
810
812
|
bag: n,
|
|
811
813
|
};
|
|
812
|
-
node.children =
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
: [];
|
|
814
|
+
node.children = n.children && n.children.length > 0
|
|
815
|
+
? this._toNodes(n.children, node)
|
|
816
|
+
: [];
|
|
816
817
|
nodes.push(node);
|
|
817
|
-
}
|
|
818
|
+
}
|
|
818
819
|
return nodes;
|
|
819
820
|
}
|
|
820
821
|
/**
|
|
821
|
-
*
|
|
822
|
+
* Retrieves the taxonomy tree from the back end.
|
|
823
|
+
* @returns An observable that emits `ApiResult<FolderTree>`.
|
|
822
824
|
*/
|
|
823
825
|
getTaxonomy() {
|
|
824
826
|
return this.httpClient.get(this._serviceUri + '/taxonomy');
|
|
825
827
|
}
|
|
826
828
|
/**
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
829
|
+
* Retrieves the compliance groups for a register.
|
|
830
|
+
* @param group - Group index to retrieve (default: `1`).
|
|
831
|
+
* @param register - Optional register ID to scope the query.
|
|
832
|
+
* @returns An observable that emits `ApiResult<string[]>`.
|
|
833
|
+
*/
|
|
831
834
|
getGroups(group = 1, register) {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
: '/compliance/groups/?group=' + group));
|
|
839
|
-
}
|
|
840
|
-
////
|
|
841
|
-
// CONTEXT
|
|
842
|
-
////
|
|
835
|
+
const path = register
|
|
836
|
+
? `/compliance/groups/?group=${group}®ister=${register}`
|
|
837
|
+
: `/compliance/groups/?group=${group}`;
|
|
838
|
+
return this.httpClient.get(this._serviceUri + path);
|
|
839
|
+
}
|
|
840
|
+
// ── Context ────────────────────────────────────────────────────────────────
|
|
843
841
|
/**
|
|
844
|
-
*
|
|
842
|
+
* Sends a context-change request to the back end.
|
|
843
|
+
* @param params - The context model describing the desired switch.
|
|
844
|
+
* @returns An observable that emits `ApiResult<EvolutionChangeContextResultModel>`.
|
|
845
845
|
*/
|
|
846
846
|
changeContext(params) {
|
|
847
847
|
return this.httpClient.post(this._serviceUri + '/compliance/context', params);
|
|
848
848
|
}
|
|
849
|
-
|
|
850
|
-
// REGISTERS
|
|
851
|
-
////
|
|
849
|
+
// ── Registers ──────────────────────────────────────────────────────────────
|
|
852
850
|
/**
|
|
853
|
-
*
|
|
854
|
-
* @param id
|
|
851
|
+
* Retrieves a single compliance register by ID.
|
|
852
|
+
* @param id - The register ID.
|
|
853
|
+
* @returns An observable that emits `ApiResult<EvolutionComplianceRegister>`.
|
|
855
854
|
*/
|
|
856
855
|
getRegister(id) {
|
|
857
|
-
return this.httpClient.get(this._serviceUri +
|
|
858
|
-
'/compliance/registers/' + id);
|
|
856
|
+
return this.httpClient.get(this._serviceUri + '/compliance/registers/' + id);
|
|
859
857
|
}
|
|
860
858
|
/**
|
|
861
|
-
*
|
|
862
|
-
* @param params parameters
|
|
859
|
+
* Collects register profiles matching the given query parameters.
|
|
860
|
+
* @param params - Query parameters defining the filter criteria.
|
|
861
|
+
* @returns An observable that emits `ApiResult<EvolutionComplianceRegisterProfile[]>`.
|
|
863
862
|
*/
|
|
864
863
|
collectRegisterProfiles(params) {
|
|
865
|
-
return this.httpClient.post(this._serviceUri +
|
|
866
|
-
'/compliance/registers/profiles/collect', params);
|
|
864
|
+
return this.httpClient.post(this._serviceUri + '/compliance/registers/profiles/collect', params);
|
|
867
865
|
}
|
|
868
|
-
|
|
869
|
-
// LAWS
|
|
870
|
-
////
|
|
866
|
+
// ── Laws ───────────────────────────────────────────────────────────────────
|
|
871
867
|
/**
|
|
872
|
-
*
|
|
873
|
-
* @param params
|
|
868
|
+
* Adds one or more compliance laws.
|
|
869
|
+
* @param params - The laws to add.
|
|
870
|
+
* @returns An observable that emits `ApiResult<EvolutionComplianceLaw[]>`.
|
|
874
871
|
*/
|
|
875
872
|
addLaws(params) {
|
|
876
873
|
return this.httpClient.post(this._serviceUri + '/compliance/laws/add', params);
|
|
877
874
|
}
|
|
878
|
-
|
|
879
|
-
// ACTIVITIES
|
|
880
|
-
////
|
|
875
|
+
// ── Activities ─────────────────────────────────────────────────────────────
|
|
881
876
|
/**
|
|
882
|
-
*
|
|
883
|
-
* @param params
|
|
877
|
+
* Adds one or more compliance activities.
|
|
878
|
+
* @param params - The activities to add.
|
|
879
|
+
* @returns An observable that emits `ApiResult<EvolutionComplianceActivity>`.
|
|
884
880
|
*/
|
|
885
881
|
addActivities(params) {
|
|
886
882
|
return this.httpClient.post(this._serviceUri + '/compliance/activities/add', params);
|
|
887
883
|
}
|
|
888
884
|
/**
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
885
|
+
* Exports compliance laws in the format expected by the server.
|
|
886
|
+
* @param params - Export parameters (model shape is server-defined).
|
|
887
|
+
* @returns An observable that emits the binary blob response.
|
|
888
|
+
*/
|
|
889
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
892
890
|
exportLaws(params) {
|
|
893
891
|
return this.httpClient.post(this._serviceUri + '/compliance/laws/export', params, { responseType: 'blob' });
|
|
894
892
|
}
|
|
895
|
-
|
|
896
|
-
// LINKS
|
|
897
|
-
///
|
|
893
|
+
// ── Links ──────────────────────────────────────────────────────────────────
|
|
898
894
|
/**
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
895
|
+
* Persists a user link on the server.
|
|
896
|
+
* @param item - The user link to save.
|
|
897
|
+
* @returns An observable that emits `ApiResult<boolean>`.
|
|
898
|
+
*/
|
|
902
899
|
saveLink(item) {
|
|
903
900
|
return this.httpClient.post(this._serviceUri + '/account/links/save', item);
|
|
904
901
|
}
|
|
905
902
|
/**
|
|
906
|
-
*
|
|
907
|
-
* @param item
|
|
903
|
+
* Deletes a user link from the server.
|
|
904
|
+
* @param item - The user link to delete.
|
|
905
|
+
* @returns An observable that emits `ApiResult<boolean>`.
|
|
908
906
|
*/
|
|
909
907
|
deleteLink(item) {
|
|
910
908
|
return this.httpClient.post(this._serviceUri + '/account/links/delete', item);
|
|
911
909
|
}
|
|
912
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
913
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
910
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
911
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, providedIn: 'root' }); }
|
|
914
912
|
}
|
|
915
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
913
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionService, decorators: [{
|
|
916
914
|
type: Injectable,
|
|
917
915
|
args: [{
|
|
918
916
|
providedIn: 'root',
|
|
919
917
|
}]
|
|
920
918
|
}] });
|
|
921
919
|
|
|
920
|
+
/** Minimum milliseconds between consecutive error broadcasts (debounce guard). */
|
|
921
|
+
const ERROR_DEBOUNCE_MS = 5000;
|
|
922
|
+
/**
|
|
923
|
+
* HTTP interceptor that attaches Evolution authentication headers to every request
|
|
924
|
+
* targeting the Evolution service, and broadcasts user-friendly error messages
|
|
925
|
+
* when the server returns an error response.
|
|
926
|
+
*/
|
|
922
927
|
class EvolutionAuthInterceptor {
|
|
923
928
|
constructor() {
|
|
924
929
|
this.evolutionService = inject(EvolutionService);
|
|
925
930
|
this.broadcastService = inject(BroadcastService);
|
|
926
931
|
this.lastErrorTime = -1;
|
|
927
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* Intercepts every outgoing HTTP request.
|
|
935
|
+
* When the request targets the Evolution service URI, attaches credentials and
|
|
936
|
+
* a client-ID header, then pipes the response through an error handler.
|
|
937
|
+
* @param request - The outgoing HTTP request.
|
|
938
|
+
* @param next - The next handler in the interceptor chain.
|
|
939
|
+
* @returns An observable of the HTTP event stream.
|
|
940
|
+
*/
|
|
928
941
|
intercept(request, next) {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
setHeaders: {
|
|
933
|
-
'ngsw-bypass': 'ngsw-bypass',
|
|
934
|
-
'X-Client-Id': sessionStorage.getItem('evolution_client_id') ?? ''
|
|
935
|
-
}
|
|
936
|
-
});
|
|
937
|
-
return next.handle(request)
|
|
938
|
-
.pipe(catchError$1(error => {
|
|
939
|
-
if (error.url.startsWith(this.evolutionService.serviceUri)) {
|
|
940
|
-
const errorStatus = parseInt(error.status ?? "0");
|
|
941
|
-
if ((errorStatus > 0 && errorStatus < 500) || (this.evolutionService.flags & EvolutionServiceFlags.NotifySystemErrors) > 0) {
|
|
942
|
-
const errorTime = new Date().getTime();
|
|
943
|
-
if (errorTime - this.lastErrorTime > 5000) {
|
|
944
|
-
this.lastErrorTime = errorTime;
|
|
945
|
-
let message = "";
|
|
946
|
-
switch (errorStatus) {
|
|
947
|
-
case 0:
|
|
948
|
-
message = "In questo momento Evolution non è disponibile. Riprova tra qualche minuto.";
|
|
949
|
-
break;
|
|
950
|
-
case 403:
|
|
951
|
-
message = "Non hai i permessi necessari per eseguire l'operazione richiesta.";
|
|
952
|
-
break;
|
|
953
|
-
default:
|
|
954
|
-
message = (error.error?.message ?? error.message ?? "Impossibile eseguire l'operazione richiesta.").replaceAll("\r\n", "</p><p>");
|
|
955
|
-
break;
|
|
956
|
-
}
|
|
957
|
-
this.broadcastService.sendMessage(EvolutionMessages.ERROR, {
|
|
958
|
-
invalidateSession: errorStatus === 405 || errorStatus === 410,
|
|
959
|
-
message: message,
|
|
960
|
-
title: "Errore in Clipper",
|
|
961
|
-
errorStatus: errorStatus,
|
|
962
|
-
service: this.evolutionService.serviceUri
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
return throwError(() => error);
|
|
968
|
-
}));
|
|
942
|
+
const serviceUri = this.evolutionService.serviceUri ?? '';
|
|
943
|
+
if (!serviceUri || !request.url.startsWith(serviceUri)) {
|
|
944
|
+
return next.handle(request);
|
|
969
945
|
}
|
|
970
|
-
|
|
946
|
+
const authenticatedRequest = request.clone({
|
|
947
|
+
withCredentials: true,
|
|
948
|
+
setHeaders: {
|
|
949
|
+
'ngsw-bypass': 'ngsw-bypass',
|
|
950
|
+
'X-Client-Id': sessionStorage.getItem('evolution_client_id') ?? ''
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
return next.handle(authenticatedRequest).pipe(catchError$1((error) => {
|
|
954
|
+
this.handleError(error);
|
|
955
|
+
return throwError(() => error);
|
|
956
|
+
}));
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Processes an HTTP error, broadcasting a user-friendly message when appropriate.
|
|
960
|
+
* Errors are debounced: only one message is sent per `ERROR_DEBOUNCE_MS` window.
|
|
961
|
+
* @param error - The raw error value thrown by the HTTP layer.
|
|
962
|
+
*/
|
|
963
|
+
handleError(error) {
|
|
964
|
+
if (!(error instanceof HttpErrorResponse))
|
|
965
|
+
return;
|
|
966
|
+
const serviceUri = this.evolutionService.serviceUri ?? '';
|
|
967
|
+
if (!serviceUri || !error.url?.startsWith(serviceUri))
|
|
968
|
+
return;
|
|
969
|
+
const errorStatus = error.status;
|
|
970
|
+
const shouldNotify = (errorStatus > 0 && errorStatus < 500) ||
|
|
971
|
+
(this.evolutionService.flags & EvolutionServiceFlags.NotifySystemErrors) > 0;
|
|
972
|
+
if (!shouldNotify)
|
|
973
|
+
return;
|
|
974
|
+
const now = Date.now();
|
|
975
|
+
if (now - this.lastErrorTime <= ERROR_DEBOUNCE_MS)
|
|
976
|
+
return;
|
|
977
|
+
this.lastErrorTime = now;
|
|
978
|
+
let message;
|
|
979
|
+
switch (errorStatus) {
|
|
980
|
+
case 0:
|
|
981
|
+
message = "In questo momento Evolution non è disponibile. Riprova tra qualche minuto.";
|
|
982
|
+
break;
|
|
983
|
+
case 403:
|
|
984
|
+
message = "Non hai i permessi necessari per eseguire l'operazione richiesta.";
|
|
985
|
+
break;
|
|
986
|
+
default:
|
|
987
|
+
message = (error.error?.['message'] ??
|
|
988
|
+
error.message ??
|
|
989
|
+
"Impossibile eseguire l'operazione richiesta.").replaceAll('\r\n', '</p><p>');
|
|
990
|
+
break;
|
|
991
|
+
}
|
|
992
|
+
this.broadcastService.sendMessage(EvolutionMessages.ERROR, {
|
|
993
|
+
invalidateSession: errorStatus === 405 || errorStatus === 410,
|
|
994
|
+
message,
|
|
995
|
+
title: "Errore in Evolution",
|
|
996
|
+
errorStatus,
|
|
997
|
+
service: this.evolutionService.serviceUri
|
|
998
|
+
});
|
|
971
999
|
}
|
|
972
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
973
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1000
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1001
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor }); }
|
|
974
1002
|
}
|
|
975
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1003
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionAuthInterceptor, decorators: [{
|
|
976
1004
|
type: Injectable
|
|
977
1005
|
}] });
|
|
978
1006
|
|
|
979
1007
|
class EvolutionCommonModule {
|
|
980
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
981
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.
|
|
982
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.
|
|
1008
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
1009
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule }); }
|
|
1010
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule }); }
|
|
983
1011
|
}
|
|
984
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1012
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: EvolutionCommonModule, decorators: [{
|
|
985
1013
|
type: NgModule
|
|
986
1014
|
}] });
|
|
987
1015
|
|