mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACS-8433] ACA: User Profile Service (#3957)
This commit is contained in:
parent
f23f5edd08
commit
b5568d43fa
9
.github/workflows/pull-request.yml
vendored
9
.github/workflows/pull-request.yml
vendored
@ -70,20 +70,13 @@ jobs:
|
||||
|
||||
unit-tests:
|
||||
needs: [lint, build]
|
||||
name: "Unit tests: ${{ matrix.unit-tests.name }}"
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
unit-tests:
|
||||
- name: "aca-content"
|
||||
- name: "aca-shared"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
|
@ -1,2 +1 @@
|
||||
<h1 class="aca-sr-only" title="{{pageHeading | async | translate}}">{{ pageHeading | async | translate }}</h1>
|
||||
<router-outlet></router-outlet>
|
||||
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AppService } from '@alfresco/aca-shared';
|
||||
|
||||
@Component({
|
||||
@ -34,10 +34,8 @@ import { AppService } from '@alfresco/aca-shared';
|
||||
})
|
||||
export class AppComponent {
|
||||
onDestroy$: Subject<boolean> = new Subject<boolean>();
|
||||
pageHeading: Observable<string>;
|
||||
|
||||
constructor(private appService: AppService) {
|
||||
this.pageHeading = this.appService.pageHeading$;
|
||||
this.appService.init();
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ module.exports = () => {
|
||||
check: {
|
||||
global: {
|
||||
statements: 75,
|
||||
branches: 67,
|
||||
branches: 65,
|
||||
functions: 71,
|
||||
lines: 74
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AppStore, getUserProfile } from '@alfresco/aca-shared/store';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { UserProfileService } from '@alfresco/aca-shared';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@ -39,6 +38,7 @@ import { Store } from '@ngrx/store';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class UserInfoComponent {
|
||||
private store = inject<Store<AppStore>>(Store<AppStore>);
|
||||
user$ = this.store.select(getUserProfile);
|
||||
private userProfileService = inject(UserProfileService);
|
||||
|
||||
user$ = this.userProfileService.userProfile$;
|
||||
}
|
||||
|
@ -28,9 +28,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { ToolbarMenuItemComponent } from '@alfresco/aca-shared';
|
||||
import { AppStore, getUserProfile } from '@alfresco/aca-shared/store';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ToolbarMenuItemComponent, UserProfileService } from '@alfresco/aca-shared';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
@ -42,8 +40,9 @@ import { Store } from '@ngrx/store';
|
||||
host: { class: 'aca-user-menu' }
|
||||
})
|
||||
export class UserMenuComponent implements OnInit {
|
||||
private store = inject<Store<AppStore>>(Store<AppStore>);
|
||||
user$ = this.store.select(getUserProfile);
|
||||
private userProfileService = inject(UserProfileService);
|
||||
|
||||
user$ = this.userProfileService.userProfile$;
|
||||
|
||||
@Input()
|
||||
actionRef: ContentActionRef;
|
||||
|
@ -22,17 +22,10 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
AppStore,
|
||||
SetSelectedNodesAction,
|
||||
SnackbarErrorAction,
|
||||
SnackbarInfoAction,
|
||||
getAppSelection,
|
||||
getUserProfile
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { AppHookService } from '@alfresco/aca-shared';
|
||||
import { ProfileState, SelectionState } from '@alfresco/adf-extensions';
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { AppStore, SetSelectedNodesAction, SnackbarErrorAction, SnackbarInfoAction, getAppSelection } from '@alfresco/aca-shared/store';
|
||||
import { AppHookService, UserProfileService } from '@alfresco/aca-shared';
|
||||
import { SelectionState } from '@alfresco/adf-extensions';
|
||||
import { Component, inject, ViewEncapsulation } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { LibraryMembershipDirective, LibraryMembershipErrorEvent, LibraryMembershipToggleEvent } from '@alfresco/adf-content-services';
|
||||
@ -64,12 +57,13 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
host: { class: 'app-toggle-join-library' }
|
||||
})
|
||||
export class ToggleJoinLibraryButtonComponent {
|
||||
private userProfileService = inject(UserProfileService);
|
||||
|
||||
selection$: Observable<SelectionState>;
|
||||
profile$: Observable<ProfileState>;
|
||||
profile$ = this.userProfileService.userProfile$;
|
||||
|
||||
constructor(private store: Store<AppStore>, private appHookService: AppHookService) {
|
||||
this.selection$ = this.store.select(getAppSelection);
|
||||
this.profile$ = this.store.select(getUserProfile);
|
||||
}
|
||||
|
||||
onToggleEvent(event: LibraryMembershipToggleEvent) {
|
||||
|
@ -22,10 +22,16 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { getUserProfile } from '@alfresco/aca-shared/store';
|
||||
import { DocumentListPresetRef, DynamicColumnComponent } from '@alfresco/adf-extensions';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ContextActionsDirective, PageComponent, PageLayoutComponent, PaginationDirective, ToolbarComponent } from '@alfresco/aca-shared';
|
||||
import { Component, inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
ContextActionsDirective,
|
||||
PageComponent,
|
||||
PageLayoutComponent,
|
||||
PaginationDirective,
|
||||
ToolbarComponent,
|
||||
UserProfileService
|
||||
} from '@alfresco/aca-shared';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DocumentListModule } from '@alfresco/adf-content-services';
|
||||
@ -52,7 +58,9 @@ import { DocumentListDirective } from '../../directives/document-list.directive'
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class TrashcanComponent extends PageComponent implements OnInit {
|
||||
user$ = this.store.select(getUserProfile);
|
||||
private userProfileService = inject(UserProfileService);
|
||||
|
||||
user$ = this.userProfileService.userProfile$;
|
||||
columns: DocumentListPresetRef[] = [];
|
||||
|
||||
ngOnInit() {
|
||||
|
@ -92,32 +92,7 @@ export function appReducer(state: AppState = INITIAL_APP_STATE, action: Action):
|
||||
}
|
||||
|
||||
function updateUser(state: AppState, action: SetUserProfileAction): AppState {
|
||||
const newState = { ...state };
|
||||
const user = action.payload.person;
|
||||
const groups = [...(action.payload.groups || [])];
|
||||
|
||||
const id = user.id;
|
||||
const firstName = user.firstName || '';
|
||||
const lastName = user.lastName || '';
|
||||
const userName = `${firstName} ${lastName}`;
|
||||
const initials = [firstName[0], lastName[0]].join('');
|
||||
const email = user.email;
|
||||
|
||||
const capabilities = user.capabilities;
|
||||
const isAdmin = capabilities ? capabilities.isAdmin : true;
|
||||
|
||||
newState.user = {
|
||||
firstName,
|
||||
lastName,
|
||||
userName,
|
||||
initials,
|
||||
isAdmin,
|
||||
id,
|
||||
groups,
|
||||
email
|
||||
};
|
||||
|
||||
return newState;
|
||||
return { ...state, user: { ...action.payload } };
|
||||
}
|
||||
|
||||
function updateCurrentFolder(state: AppState, action: SetCurrentFolderAction) {
|
||||
|
@ -26,20 +26,19 @@ import { AppService } from './app.service';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
AuthenticationService,
|
||||
AppConfigService,
|
||||
AlfrescoApiService,
|
||||
PageTitleService,
|
||||
AlfrescoApiServiceMock,
|
||||
TranslationMock,
|
||||
TranslationService,
|
||||
UserPreferencesService
|
||||
UserPreferencesService,
|
||||
NotificationService
|
||||
} from '@alfresco/adf-core';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import {
|
||||
DiscoveryApiService,
|
||||
FileUploadErrorEvent,
|
||||
GroupService,
|
||||
SearchQueryBuilderService,
|
||||
SharedLinksApiService,
|
||||
UploadService
|
||||
@ -53,25 +52,26 @@ import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ContentApiService } from './content-api.service';
|
||||
import { SetRepositoryInfoAction, SetUserProfileAction, SnackbarErrorAction } from '@alfresco/aca-shared/store';
|
||||
import { AppSettingsService } from '@alfresco/aca-shared';
|
||||
import { AppSettingsService, UserProfileService } from '@alfresco/aca-shared';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
|
||||
describe('AppService', () => {
|
||||
let service: AppService;
|
||||
let auth: AuthenticationService;
|
||||
let appConfig: AppConfigService;
|
||||
let searchQueryBuilderService: SearchQueryBuilderService;
|
||||
let uploadService: UploadService;
|
||||
let store: Store;
|
||||
let sharedLinksApiService: SharedLinksApiService;
|
||||
let contentApi: ContentApiService;
|
||||
let groupService: GroupService;
|
||||
let preferencesService: UserPreferencesService;
|
||||
let appSettingsService: AppSettingsService;
|
||||
let userProfileService: UserProfileService;
|
||||
let notificationService: NotificationService;
|
||||
let loadUserProfileSpy: jasmine.Spy;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), MatDialogModule],
|
||||
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), MatDialogModule, MatSnackBarModule],
|
||||
providers: [
|
||||
SearchQueryBuilderService,
|
||||
provideMockStore({}),
|
||||
@ -118,31 +118,18 @@ describe('AppService', () => {
|
||||
});
|
||||
|
||||
appSettingsService = TestBed.inject(AppSettingsService);
|
||||
appConfig = TestBed.inject(AppConfigService);
|
||||
auth = TestBed.inject(AuthenticationService);
|
||||
searchQueryBuilderService = TestBed.inject(SearchQueryBuilderService);
|
||||
uploadService = TestBed.inject(UploadService);
|
||||
store = TestBed.inject(Store);
|
||||
sharedLinksApiService = TestBed.inject(SharedLinksApiService);
|
||||
contentApi = TestBed.inject(ContentApiService);
|
||||
groupService = TestBed.inject(GroupService);
|
||||
spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({} as any));
|
||||
service = TestBed.inject(AppService);
|
||||
preferencesService = TestBed.inject(UserPreferencesService);
|
||||
});
|
||||
|
||||
it('should be ready if [withCredentials] mode is used', (done) => {
|
||||
appConfig.config = {
|
||||
auth: {
|
||||
withCredentials: true
|
||||
}
|
||||
};
|
||||
|
||||
const instance = TestBed.inject(AppService);
|
||||
expect(instance.withCredentials).toBeTruthy();
|
||||
|
||||
instance.ready$.subscribe(() => {
|
||||
done();
|
||||
});
|
||||
userProfileService = TestBed.inject(UserProfileService);
|
||||
loadUserProfileSpy = spyOn(userProfileService, 'loadUserProfile').and.returnValue(Promise.resolve({} as any));
|
||||
notificationService = TestBed.inject(NotificationService);
|
||||
});
|
||||
|
||||
it('should be ready after login', async () => {
|
||||
@ -170,45 +157,46 @@ describe('AppService', () => {
|
||||
});
|
||||
|
||||
it('should raise notification on share link error', () => {
|
||||
const showError = spyOn(notificationService, 'showError').and.stub();
|
||||
spyOn(store, 'select').and.returnValue(of(''));
|
||||
service.init();
|
||||
const dispatch = spyOn(store, 'dispatch');
|
||||
|
||||
sharedLinksApiService.error.next({ message: 'Error Message', statusCode: 1 });
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('Error Message'));
|
||||
expect(showError).toHaveBeenCalledWith('Error Message');
|
||||
});
|
||||
|
||||
it('should raise notification on upload error', async () => {
|
||||
spyOn(store, 'select').and.returnValue(of(''));
|
||||
service.init();
|
||||
const dispatch = spyOn(store, 'dispatch');
|
||||
|
||||
const showError = spyOn(notificationService, 'showError').and.stub();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.403');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 404 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.404'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.404');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 409 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.CONFLICT'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.CONFLICT');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 500 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.500'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.500');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 504 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.504'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.504');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
|
||||
dispatch.calls.reset();
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.403');
|
||||
showError.calls.reset();
|
||||
|
||||
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, {}));
|
||||
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.GENERIC'));
|
||||
expect(showError).toHaveBeenCalledWith('APP.MESSAGES.UPLOAD.ERROR.GENERIC');
|
||||
});
|
||||
|
||||
it('should load custom css', () => {
|
||||
@ -225,34 +213,19 @@ describe('AppService', () => {
|
||||
});
|
||||
|
||||
it('should load repository status on login', () => {
|
||||
const repository: any = {};
|
||||
spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({ entry: { repository } }));
|
||||
spyOn(store, 'select').and.returnValue(of(''));
|
||||
service.init();
|
||||
|
||||
const dispatch = spyOn(store, 'dispatch');
|
||||
auth.onLogin.next(true);
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(new SetRepositoryInfoAction(repository));
|
||||
expect(contentApi.getRepositoryInformation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should load user profile on login', async () => {
|
||||
const person: any = { id: 'person' };
|
||||
|
||||
const group: any = { entry: {} };
|
||||
const groups: any[] = [group];
|
||||
|
||||
spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({} as any));
|
||||
spyOn(groupService, 'listAllGroupMembershipsForPerson').and.returnValue(Promise.resolve(groups));
|
||||
spyOn(contentApi, 'getPerson').and.returnValue(of({ entry: person }));
|
||||
|
||||
loadUserProfileSpy.and.returnValue(Promise.resolve(person));
|
||||
spyOn(store, 'select').and.returnValue(of(''));
|
||||
service.init();
|
||||
|
||||
const dispatch = spyOn(store, 'dispatch');
|
||||
auth.onLogin.next(true);
|
||||
|
||||
await expect(groupService.listAllGroupMembershipsForPerson).toHaveBeenCalled();
|
||||
await expect(dispatch).toHaveBeenCalledWith(new SetUserProfileAction({ person, groups: [group.entry] }));
|
||||
expect(loadUserProfileSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -22,39 +22,51 @@
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Injectable, OnDestroy } from '@angular/core';
|
||||
import { AuthenticationService, AppConfigService, AlfrescoApiService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { inject, Injectable, OnDestroy } from '@angular/core';
|
||||
import {
|
||||
AuthenticationService,
|
||||
AppConfigService,
|
||||
AlfrescoApiService,
|
||||
PageTitleService,
|
||||
UserPreferencesService,
|
||||
NotificationService
|
||||
} from '@alfresco/adf-core';
|
||||
import { Observable, BehaviorSubject, Subject } from 'rxjs';
|
||||
import { GroupService, SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
|
||||
import { SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
|
||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||
import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router';
|
||||
import { filter, map, tap } from 'rxjs/operators';
|
||||
import { filter, map } from 'rxjs/operators';
|
||||
import {
|
||||
AppStore,
|
||||
CloseModalDialogsAction,
|
||||
SetCurrentUrlAction,
|
||||
SetRepositoryInfoAction,
|
||||
SetUserProfileAction,
|
||||
SnackbarErrorAction,
|
||||
ResetSelectionAction
|
||||
} from '@alfresco/aca-shared/store';
|
||||
import { ContentApiService } from './content-api.service';
|
||||
import { RouterExtensionService } from './router.extension.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { DiscoveryEntry, GroupEntry, Group } from '@alfresco/js-api';
|
||||
import { DiscoveryEntry } from '@alfresco/js-api';
|
||||
import { AcaMobileAppSwitcherService } from './aca-mobile-app-switcher.service';
|
||||
import { ShellAppService } from '@alfresco/adf-core/shell';
|
||||
import { AppSettingsService } from './app-settings.service';
|
||||
import { UserProfileService } from './user-profile.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
// After moving shell to ADF to core, AppService will implement ShellAppService
|
||||
export class AppService implements ShellAppService, OnDestroy {
|
||||
private notificationService = inject(NotificationService);
|
||||
private ready: BehaviorSubject<boolean>;
|
||||
|
||||
ready$: Observable<boolean>;
|
||||
pageHeading$: Observable<string>;
|
||||
|
||||
private pageHeading = new BehaviorSubject('');
|
||||
/** @deprecated page title is updated automatically */
|
||||
pageHeading$ = this.pageHeading.asObservable();
|
||||
|
||||
appNavNarMode$: Subject<'collapsed' | 'expanded'> = new BehaviorSubject('expanded');
|
||||
toggleAppNavBar$ = new Subject();
|
||||
|
||||
@ -84,11 +96,11 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
private routerExtensionService: RouterExtensionService,
|
||||
private contentApi: ContentApiService,
|
||||
private sharedLinksApiService: SharedLinksApiService,
|
||||
private groupService: GroupService,
|
||||
private overlayContainer: OverlayContainer,
|
||||
searchQueryBuilderService: SearchQueryBuilderService,
|
||||
private acaMobileAppSwitcherService: AcaMobileAppSwitcherService,
|
||||
private appSettingsService: AppSettingsService
|
||||
private appSettingsService: AppSettingsService,
|
||||
private userProfileService: UserProfileService
|
||||
) {
|
||||
this.ready = new BehaviorSubject(this.authenticationService.isLoggedIn() || this.withCredentials);
|
||||
this.ready$ = this.ready.asObservable();
|
||||
@ -104,11 +116,15 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
acaMobileAppSwitcherService.closeDialog();
|
||||
});
|
||||
|
||||
this.pageHeading$ = this.router.events.pipe(
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter((event) => event instanceof ActivationEnd && event.snapshot.children.length === 0),
|
||||
map((event: ActivationEnd) => event.snapshot?.data?.title ?? ''),
|
||||
tap((title) => this.pageTitle.setTitle(title))
|
||||
);
|
||||
map((event: ActivationEnd) => event.snapshot?.data?.title ?? '')
|
||||
)
|
||||
.subscribe((title) => {
|
||||
this.pageHeading.next(title);
|
||||
this.pageTitle.setTitle(title);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@ -153,7 +169,7 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
|
||||
this.sharedLinksApiService.error.subscribe((err: { message: string }) => {
|
||||
if (err?.message) {
|
||||
this.store.dispatch(new SnackbarErrorAction(err.message));
|
||||
this.notificationService.showError(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
@ -184,17 +200,8 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
}
|
||||
|
||||
private async loadUserProfile() {
|
||||
const groupsEntries: GroupEntry[] = await this.groupService.listAllGroupMembershipsForPerson('-me-', { maxItems: 250 });
|
||||
|
||||
const groups: Group[] = [];
|
||||
|
||||
if (groupsEntries) {
|
||||
groups.push(...groupsEntries.map((obj) => obj.entry));
|
||||
}
|
||||
|
||||
this.contentApi.getPerson('-me-').subscribe((person) => {
|
||||
this.store.dispatch(new SetUserProfileAction({ person: person.entry, groups }));
|
||||
});
|
||||
const profile = await this.userProfileService.loadUserProfile();
|
||||
this.store.dispatch(new SetUserProfileAction(profile));
|
||||
}
|
||||
|
||||
onFileUploadedError(error: FileUploadErrorEvent) {
|
||||
@ -220,7 +227,7 @@ export class AppService implements ShellAppService, OnDestroy {
|
||||
message = 'APP.MESSAGES.UPLOAD.ERROR.504';
|
||||
}
|
||||
|
||||
this.store.dispatch(new SnackbarErrorAction(message));
|
||||
this.notificationService.showError(message);
|
||||
}
|
||||
|
||||
private loadCustomCss(): void {
|
||||
|
81
projects/aca-shared/src/lib/services/user-profile.service.ts
Normal file
81
projects/aca-shared/src/lib/services/user-profile.service.ts
Normal file
@ -0,0 +1,81 @@
|
||||
/*!
|
||||
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { ProfileState } from '@alfresco/adf-extensions';
|
||||
import { GroupService } from '@alfresco/adf-content-services';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { PeopleApi } from '@alfresco/js-api';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class UserProfileService {
|
||||
private api = inject(AlfrescoApiService);
|
||||
private groupService = inject(GroupService);
|
||||
|
||||
private get peopleApi(): PeopleApi {
|
||||
return new PeopleApi(this.api.getInstance());
|
||||
}
|
||||
|
||||
private userProfile = new BehaviorSubject<ProfileState>(null);
|
||||
userProfile$ = this.userProfile.asObservable();
|
||||
|
||||
/**
|
||||
* Load user profile.
|
||||
*/
|
||||
async loadUserProfile(): Promise<ProfileState> {
|
||||
const groupsEntries = await this.groupService.listAllGroupMembershipsForPerson('-me-', { maxItems: 250 });
|
||||
|
||||
const groups = [];
|
||||
if (groupsEntries) {
|
||||
groups.push(...groupsEntries.map((obj) => obj.entry));
|
||||
}
|
||||
|
||||
const { entry: user } = await this.peopleApi.getPerson('-me-');
|
||||
|
||||
const id = user.id;
|
||||
const firstName = user.firstName || '';
|
||||
const lastName = user.lastName || '';
|
||||
const userName = `${firstName} ${lastName}`;
|
||||
const initials = [firstName[0], lastName[0]].join('');
|
||||
const email = user.email;
|
||||
|
||||
const capabilities = user.capabilities;
|
||||
const isAdmin = capabilities ? capabilities.isAdmin : true;
|
||||
|
||||
const profile: ProfileState = {
|
||||
firstName,
|
||||
lastName,
|
||||
userName,
|
||||
initials,
|
||||
isAdmin,
|
||||
id,
|
||||
groups,
|
||||
email
|
||||
};
|
||||
|
||||
this.userProfile.next(profile);
|
||||
return profile;
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ export * from './lib/services/router.extension.service';
|
||||
export * from './lib/services/app-hook.service';
|
||||
export * from './lib/services/aca-file-auto-download.service';
|
||||
export * from './lib/services/app-settings.service';
|
||||
export * from './lib/services/user-profile.service';
|
||||
|
||||
export * from './lib/utils/node.utils';
|
||||
export * from './lib/testing/lib-testing-module';
|
||||
|
@ -23,8 +23,9 @@
|
||||
*/
|
||||
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Node, Person, Group, RepositoryInfo, VersionEntry } from '@alfresco/js-api';
|
||||
import { Node, RepositoryInfo, VersionEntry } from '@alfresco/js-api';
|
||||
import { AppActionTypes } from './app-action-types';
|
||||
import { ProfileState } from '@alfresco/adf-extensions';
|
||||
|
||||
export class SetCurrentFolderAction implements Action {
|
||||
readonly type = AppActionTypes.SetCurrentFolder;
|
||||
@ -47,7 +48,7 @@ export class SetCurrentUrlAction implements Action {
|
||||
export class SetUserProfileAction implements Action {
|
||||
readonly type = AppActionTypes.SetUserProfile;
|
||||
|
||||
constructor(public payload: { person: Person; groups: Group[] }) {}
|
||||
constructor(public payload: ProfileState) {}
|
||||
}
|
||||
|
||||
export class ToggleInfoDrawerAction implements Action {
|
||||
|
@ -28,6 +28,7 @@ import { createSelector } from '@ngrx/store';
|
||||
const HXI_CONNECTOR = 'alfresco-hxinsight-connector-prediction-applier-extension';
|
||||
export const selectApp = (state: AppStore) => state.app;
|
||||
|
||||
/** @deprecated use `UserProfileService` instead */
|
||||
export const getUserProfile = createSelector(selectApp, (state) => state.user);
|
||||
export const getCurrentFolder = createSelector(selectApp, (state) => state.navigation.currentFolder);
|
||||
export const getCurrentVersion = createSelector(selectApp, (state) => state.currentNodeVersion);
|
||||
|
Loading…
x
Reference in New Issue
Block a user