[CST-5738] Add method to retrieve embedded special groups

This commit is contained in:
Giuseppe Digilio
2022-04-29 12:49:07 +02:00
parent 1e651c2d47
commit 0f80b6533b
7 changed files with 70 additions and 40 deletions

View File

@@ -18,7 +18,6 @@ import { RestRequest } from '../data/rest-request.model';
*/ */
export abstract class AuthRequestService { export abstract class AuthRequestService {
protected linkName = 'authn'; protected linkName = 'authn';
protected browseEndpoint = '';
protected shortlivedtokensEndpoint = 'shortlivedtokens'; protected shortlivedtokensEndpoint = 'shortlivedtokens';
constructor(protected halService: HALEndpointService, constructor(protected halService: HALEndpointService,
@@ -33,8 +32,13 @@ export abstract class AuthRequestService {
); );
} }
protected getEndpointByMethod(endpoint: string, method: string): string { protected getEndpointByMethod(endpoint: string, method: string, embed = false): string {
return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`; let url = isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`;
if (embed) {
url += '?embed=specialGroups';
}
return url;
} }
public postToEndpoint(method: string, body?: any, options?: HttpOptions): Observable<RemoteData<AuthStatus>> { public postToEndpoint(method: string, body?: any, options?: HttpOptions): Observable<RemoteData<AuthStatus>> {
@@ -48,7 +52,7 @@ export abstract class AuthRequestService {
distinctUntilChanged()); distinctUntilChanged());
} }
public getRequest(method: string, options?: HttpOptions): Observable<RemoteData<AuthStatus>> { public getRequest(method: string, options?: HttpOptions, embed = false): Observable<RemoteData<AuthStatus>> {
return this.halService.getEndpoint(this.linkName).pipe( return this.halService.getEndpoint(this.linkName).pipe(
filter((href: string) => isNotEmpty(href)), filter((href: string) => isNotEmpty(href)),
map((endpointURL) => this.getEndpointByMethod(endpointURL, method)), map((endpointURL) => this.getEndpointByMethod(endpointURL, method)),

View File

@@ -32,6 +32,8 @@ import { TranslateService } from '@ngx-translate/core';
import { getMockTranslateService } from '../../shared/mocks/translate.service.mock'; import { getMockTranslateService } from '../../shared/mocks/translate.service.mock';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub'; import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { SetUserAsIdleAction, UnsetUserAsIdleAction } from './auth.actions'; import { SetUserAsIdleAction, UnsetUserAsIdleAction } from './auth.actions';
import { SpecialGroupDataMock, SpecialGroupDataMock$ } from '../../shared/testing/special-group.mock';
import { cold } from 'jasmine-marbles';
describe('AuthService test', () => { describe('AuthService test', () => {
@@ -56,6 +58,13 @@ describe('AuthService test', () => {
let linkService; let linkService;
let hardRedirectService; let hardRedirectService;
const AuthStatusWithSpecialGroups = Object.assign(new AuthStatus(), {
uuid: 'test',
authenticated: true,
okay: true,
specialGroups: SpecialGroupDataMock$
});
function init() { function init() {
mockStore = jasmine.createSpyObj('store', { mockStore = jasmine.createSpyObj('store', {
dispatch: {}, dispatch: {},
@@ -511,6 +520,19 @@ describe('AuthService test', () => {
expect((authService as any).navigateToRedirectUrl).toHaveBeenCalled(); expect((authService as any).navigateToRedirectUrl).toHaveBeenCalled();
}); });
}); });
describe('getSpecialGroupsFromAuthStatus', () => {
beforeEach(() => {
spyOn(authRequest, 'getRequest').and.returnValue(createSuccessfulRemoteDataObject$(AuthStatusWithSpecialGroups));
});
it('should call navigateToRedirectUrl with no url', () => {
const expectRes = cold('(a|)', {
a: SpecialGroupDataMock
});
expect(authService.getSpecialGroupsFromAuthStatus()).toBeObservable(expectRes);
});
});
}); });
describe('when user is not logged in', () => { describe('when user is not logged in', () => {

View File

@@ -44,13 +44,17 @@ import {
import { NativeWindowRef, NativeWindowService } from '../services/window.service'; import { NativeWindowRef, NativeWindowService } from '../services/window.service';
import { RouteService } from '../services/route.service'; import { RouteService } from '../services/route.service';
import { EPersonDataService } from '../eperson/eperson-data.service'; import { EPersonDataService } from '../eperson/eperson-data.service';
import { getAllSucceededRemoteDataPayload } from '../shared/operators'; import { getAllSucceededRemoteDataPayload, getFirstCompletedRemoteData } from '../shared/operators';
import { AuthMethod } from './models/auth.method'; import { AuthMethod } from './models/auth.method';
import { HardRedirectService } from '../services/hard-redirect.service'; import { HardRedirectService } from '../services/hard-redirect.service';
import { RemoteData } from '../data/remote-data'; import { RemoteData } from '../data/remote-data';
import { environment } from '../../../environments/environment'; import { environment } from '../../../environments/environment';
import { NotificationsService } from '../../shared/notifications/notifications.service'; import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { buildPaginatedList, PaginatedList } from '../data/paginated-list.model';
import { Group } from '../eperson/models/group.model';
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import { PageInfo } from '../shared/page-info.model';
export const LOGIN_ROUTE = '/login'; export const LOGIN_ROUTE = '/login';
export const LOGOUT_ROUTE = '/logout'; export const LOGOUT_ROUTE = '/logout';
@@ -211,6 +215,22 @@ export class AuthService {
this.store.dispatch(new CheckAuthenticationTokenAction()); this.store.dispatch(new CheckAuthenticationTokenAction());
} }
/**
* Return the special groups list embedded in the AuthStatus model
*/
public getSpecialGroupsFromAuthStatus(): Observable<RemoteData<PaginatedList<Group>>> {
return this.authRequestService.getRequest('status', null, true).pipe(
getFirstCompletedRemoteData(),
switchMap((status: RemoteData<AuthStatus>) => {
if (status.hasSucceeded) {
return status.payload.specialGroups;
} else {
return createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(),[]));
}
})
);
}
/** /**
* Checks if token is present into storage and is not expired * Checks if token is present into storage and is not expired
*/ */

View File

@@ -15,7 +15,7 @@ import { AUTH_STATUS } from './auth-status.resource-type';
import { AuthTokenInfo } from './auth-token-info.model'; import { AuthTokenInfo } from './auth-token-info.model';
import { AuthMethod } from './auth.method'; import { AuthMethod } from './auth.method';
import { CacheableObject } from '../../cache/cacheable-object.model'; import { CacheableObject } from '../../cache/cacheable-object.model';
import { PaginatedList } from '../../data/paginated-list.model';
/** /**
* Object that represents the authenticated status of a user * Object that represents the authenticated status of a user
@@ -78,8 +78,8 @@ export class AuthStatus implements CacheableObject {
* The SpecialGroup of this auth status * The SpecialGroup of this auth status
* Will be undefined unless the SpecialGroup {@link HALLink} has been resolved. * Will be undefined unless the SpecialGroup {@link HALLink} has been resolved.
*/ */
@link(GROUP) @link(GROUP, true)
specialGroups?: Observable<RemoteData<Group>>; specialGroups?: Observable<RemoteData<PaginatedList<Group>>>;
/** /**
* True if the token is valid, false if there was no token or the token wasn't valid * True if the token is valid, false if there was no token or the token wasn't valid

View File

@@ -13,14 +13,14 @@ import { NotificationsService } from '../shared/notifications/notifications.serv
import { authReducer } from '../core/auth/auth.reducer'; import { authReducer } from '../core/auth/auth.reducer';
import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils'; import { createSuccessfulRemoteDataObject$ } from '../shared/remote-data.utils';
import { createPaginatedList } from '../shared/testing/utils.test'; import { createPaginatedList } from '../shared/testing/utils.test';
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs'; import { BehaviorSubject, of as observableOf } from 'rxjs';
import { AuthService } from '../core/auth/auth.service'; import { AuthService } from '../core/auth/auth.service';
import { RestResponse } from '../core/cache/response.models'; import { RestResponse } from '../core/cache/response.models';
import { provideMockStore } from '@ngrx/store/testing'; import { provideMockStore } from '@ngrx/store/testing';
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { SpecialGroupData } from '../shared/testing/special-group.mock'; import { SpecialGroupDataMock$ } from '../shared/testing/special-group.mock';
describe('ProfilePageComponent', () => { describe('ProfilePageComponent', () => {
let component: ProfilePageComponent; let component: ProfilePageComponent;
@@ -55,7 +55,8 @@ describe('ProfilePageComponent', () => {
}; };
authService = jasmine.createSpyObj('authService', { authService = jasmine.createSpyObj('authService', {
getAuthenticatedUserFromStore: observableOf(user) getAuthenticatedUserFromStore: observableOf(user),
getSpecialGroupsFromAuthStatus: SpecialGroupDataMock$
}); });
epersonService = jasmine.createSpyObj('epersonService', { epersonService = jasmine.createSpyObj('epersonService', {
findById: createSuccessfulRemoteDataObject$(user), findById: createSuccessfulRemoteDataObject$(user),
@@ -239,8 +240,6 @@ describe('ProfilePageComponent', () => {
describe('check for specialGroups', () => { describe('check for specialGroups', () => {
it('should contains specialGroups list', () => { it('should contains specialGroups list', () => {
component.specialGroupsRD$ = SpecialGroupData;
fixture.detectChanges();
const specialGroupsEle = fixture.debugElement.query(By.css('#specialGroups')); const specialGroupsEle = fixture.debugElement.query(By.css('#specialGroups'));
expect(specialGroupsEle).toBeTruthy(); expect(specialGroupsEle).toBeTruthy();
}); });

View File

@@ -9,19 +9,13 @@ import { RemoteData } from '../core/data/remote-data';
import { PaginatedList } from '../core/data/paginated-list.model'; import { PaginatedList } from '../core/data/paginated-list.model';
import { filter, switchMap, tap } from 'rxjs/operators'; import { filter, switchMap, tap } from 'rxjs/operators';
import { EPersonDataService } from '../core/eperson/eperson-data.service'; import { EPersonDataService } from '../core/eperson/eperson-data.service';
import { import { getAllSucceededRemoteData, getFirstCompletedRemoteData, getRemoteDataPayload } from '../core/shared/operators';
getAllSucceededRemoteData,
getRemoteDataPayload,
getFirstCompletedRemoteData
} from '../core/shared/operators';
import { hasValue, isNotEmpty } from '../shared/empty.util'; import { hasValue, isNotEmpty } from '../shared/empty.util';
import { followLink } from '../shared/utils/follow-link-config.model'; import { followLink } from '../shared/utils/follow-link-config.model';
import { AuthService } from '../core/auth/auth.service'; import { AuthService } from '../core/auth/auth.service';
import { Operation } from 'fast-json-patch'; import { Operation } from 'fast-json-patch';
import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service'; import { AuthorizationDataService } from '../core/data/feature-authorization/authorization-data.service';
import { FeatureID } from '../core/data/feature-authorization/feature-id'; import { FeatureID } from '../core/data/feature-authorization/feature-id';
import { SpecialGroupData } from '../shared/testing/special-group.mock';
@Component({ @Component({
selector: 'ds-profile-page', selector: 'ds-profile-page',
@@ -95,7 +89,7 @@ export class ProfilePageComponent implements OnInit {
); );
this.groupsRD$ = this.user$.pipe(switchMap((user: EPerson) => user.groups)); this.groupsRD$ = this.user$.pipe(switchMap((user: EPerson) => user.groups));
this.canChangePassword$ = this.user$.pipe(switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href))); this.canChangePassword$ = this.user$.pipe(switchMap((user: EPerson) => this.authorizationService.isAuthorized(FeatureID.CanChangePassword, user._links.self.href)));
this.specialGroupsRD$ = SpecialGroupData; this.specialGroupsRD$ = this.authService.getSpecialGroupsFromAuthStatus();
} }
/** /**

View File

@@ -1,12 +1,11 @@
import { EPersonMock } from './eperson.mock'; import { Observable } from 'rxjs';
import { of } from 'rxjs';
import { RemoteData } from '../../core/data/remote-data';
import { environment } from '../../../environments/environment';
import { RequestEntryState } from '../../core/data/request.reducer';
import { PageInfo } from '../../core/shared/page-info.model';
import { buildPaginatedList } from '../../core/data/paginated-list.model';
import { Group } from '../../core/eperson/models/group.model';
import { EPersonMock } from './eperson.mock';
import { PageInfo } from '../../core/shared/page-info.model';
import { buildPaginatedList, PaginatedList } from '../../core/data/paginated-list.model';
import { Group } from '../../core/eperson/models/group.model';
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../remote-data.utils';
import { RemoteData } from '../../core/data/remote-data';
export const SpecialGroupMock2: Group = Object.assign(new Group(), { export const SpecialGroupMock2: Group = Object.assign(new Group(), {
handle: null, handle: null,
@@ -49,16 +48,8 @@ export const SpecialGroupMock: Group = Object.assign(new Group(), {
type: 'specialGroups', type: 'specialGroups',
}); });
export const SpecialGroupData = of(new RemoteData( export const SpecialGroupDataMock: RemoteData<PaginatedList<Group>> = createSuccessfulRemoteDataObject(buildPaginatedList(new PageInfo(), [SpecialGroupMock2,SpecialGroupMock]));
new Date().getTime(), export const SpecialGroupDataMock$: Observable<RemoteData<PaginatedList<Group>>> = createSuccessfulRemoteDataObject$(buildPaginatedList(new PageInfo(), [SpecialGroupMock2,SpecialGroupMock]));
environment.cache.msToLive.default,
new Date().getTime(),
RequestEntryState.Success,
undefined,
buildPaginatedList(new PageInfo(), [SpecialGroupMock2,SpecialGroupMock]),
200
));