mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #1808 from atmire/PR-1548-fix-group-page-lists
Fix group page lists in PR #1548
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
combineLatest as observableCombineLatest,
|
||||
ObservedValueOf,
|
||||
} from 'rxjs';
|
||||
import { map, mergeMap, switchMap, take } from 'rxjs/operators';
|
||||
import { defaultIfEmpty, map, mergeMap, switchMap, take } from 'rxjs/operators';
|
||||
import {buildPaginatedList, PaginatedList} from '../../../../core/data/paginated-list.model';
|
||||
import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { EPersonDataService } from '../../../../core/eperson/eperson-data.service';
|
||||
@@ -144,7 +144,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}),
|
||||
switchMap((epersonListRD: RemoteData<PaginatedList<EPerson>>) => {
|
||||
const dtos$ = observableCombineLatest(...epersonListRD.payload.page.map((member: EPerson) => {
|
||||
const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => {
|
||||
const dto$: Observable<EpersonDtoModel> = observableCombineLatest(
|
||||
this.isMemberOfGroup(member), (isMember: ObservedValueOf<Observable<boolean>>) => {
|
||||
const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
|
||||
@@ -153,8 +153,8 @@ export class MembersListComponent implements OnInit, OnDestroy {
|
||||
return epersonDtoModel;
|
||||
});
|
||||
return dto$;
|
||||
}));
|
||||
return dtos$.pipe(map((dtos: EpersonDtoModel[]) => {
|
||||
})]);
|
||||
return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => {
|
||||
return buildPaginatedList(epersonListRD.payload.pageInfo, dtos);
|
||||
}));
|
||||
}))
|
||||
@@ -174,7 +174,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
|
||||
return this.ePersonDataService.findListByHref(group._links.epersons.href, {
|
||||
currentPage: 1,
|
||||
elementsPerPage: 9999
|
||||
}, false)
|
||||
})
|
||||
.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
@@ -274,7 +274,7 @@ export class MembersListComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}),
|
||||
switchMap((epersonListRD: RemoteData<PaginatedList<EPerson>>) => {
|
||||
const dtos$ = observableCombineLatest(...epersonListRD.payload.page.map((member: EPerson) => {
|
||||
const dtos$ = observableCombineLatest([...epersonListRD.payload.page.map((member: EPerson) => {
|
||||
const dto$: Observable<EpersonDtoModel> = observableCombineLatest(
|
||||
this.isMemberOfGroup(member), (isMember: ObservedValueOf<Observable<boolean>>) => {
|
||||
const epersonDtoModel: EpersonDtoModel = new EpersonDtoModel();
|
||||
@@ -283,8 +283,8 @@ export class MembersListComponent implements OnInit, OnDestroy {
|
||||
return epersonDtoModel;
|
||||
});
|
||||
return dto$;
|
||||
}));
|
||||
return dtos$.pipe(map((dtos: EpersonDtoModel[]) => {
|
||||
})]);
|
||||
return dtos$.pipe(defaultIfEmpty([]), map((dtos: EpersonDtoModel[]) => {
|
||||
return buildPaginatedList(epersonListRD.payload.pageInfo, dtos);
|
||||
}));
|
||||
}))
|
||||
|
@@ -18,6 +18,7 @@ import { take } from 'rxjs/operators';
|
||||
import { HALLink } from '../../shared/hal-link.model';
|
||||
import { RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { cold } from 'jasmine-marbles';
|
||||
|
||||
describe('RemoteDataBuildService', () => {
|
||||
let service: RemoteDataBuildService;
|
||||
@@ -646,4 +647,120 @@ describe('RemoteDataBuildService', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildFromHref', () => {
|
||||
beforeEach(() => {
|
||||
(objectCache.getRequestUUIDBySelfLink as jasmine.Spy).and.returnValue(cold('a', { a: 'request/uuid' }));
|
||||
});
|
||||
|
||||
describe('when both getRequestFromRequestHref and getRequestFromRequestUUID emit nothing', () => {
|
||||
beforeEach(() => {
|
||||
(requestService.getByHref as jasmine.Spy).and.returnValue(cold('a', { a: undefined }));
|
||||
(requestService.getByUUID as jasmine.Spy).and.returnValue(cold('a', { a: undefined }));
|
||||
});
|
||||
|
||||
it('should not emit anything', () => {
|
||||
expect(service.buildFromHref(cold('a', { a: 'rest/api/endpoint' }))).toBeObservable(cold(''));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when one of getRequestFromRequestHref or getRequestFromRequestUUID emits nothing', () => {
|
||||
let requestEntry: RequestEntry;
|
||||
|
||||
beforeEach(() => {
|
||||
requestEntry = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.Success,
|
||||
request: {},
|
||||
});
|
||||
(requestService.getByHref as jasmine.Spy).and.returnValue(cold('a', { a: undefined }));
|
||||
(requestService.getByUUID as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry }));
|
||||
spyOn((service as any), 'buildPayload').and.returnValue(cold('a', { a: {} }));
|
||||
});
|
||||
|
||||
it('should create remote-data with the existing request-entry', () => {
|
||||
expect(service.buildFromHref(cold('a', { a: 'rest/api/endpoint' }))).toBeObservable(cold('a', {
|
||||
a: new RemoteData(undefined, undefined, undefined, RequestEntryState.Success, undefined, {}, undefined),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when one of getRequestFromRequestHref or getRequestFromRequestUUID is stale', () => {
|
||||
let requestEntry1: RequestEntry;
|
||||
let requestEntry2: RequestEntry;
|
||||
|
||||
beforeEach(() => {
|
||||
requestEntry1 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.Success,
|
||||
request: {},
|
||||
});
|
||||
requestEntry2 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.SuccessStale,
|
||||
request: {},
|
||||
});
|
||||
(requestService.getByHref as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry1 }));
|
||||
(requestService.getByUUID as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry2 }));
|
||||
spyOn((service as any), 'buildPayload').and.returnValue(cold('a', { a: {} }));
|
||||
});
|
||||
|
||||
it('should create remote-data with the non-stale request-entry', () => {
|
||||
expect(service.buildFromHref(cold('a', { a: 'rest/api/endpoint' }))).toBeObservable(cold('a', {
|
||||
a: new RemoteData(undefined, undefined, undefined, RequestEntryState.Success, undefined, {}, undefined),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when both getRequestFromRequestHref and getRequestFromRequestUUID are stale', () => {
|
||||
let requestEntry1: RequestEntry;
|
||||
let requestEntry2: RequestEntry;
|
||||
|
||||
beforeEach(() => {
|
||||
requestEntry1 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.SuccessStale,
|
||||
request: {},
|
||||
lastUpdated: 20,
|
||||
});
|
||||
requestEntry2 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.SuccessStale,
|
||||
request: {},
|
||||
lastUpdated: 10,
|
||||
});
|
||||
(requestService.getByHref as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry1 }));
|
||||
(requestService.getByUUID as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry2 }));
|
||||
spyOn((service as any), 'buildPayload').and.returnValue(cold('a', { a: {} }));
|
||||
});
|
||||
|
||||
it('should create remote-data with the most up-to-date request-entry', () => {
|
||||
expect(service.buildFromHref(cold('a', { a: 'rest/api/endpoint' }))).toBeObservable(cold('a', {
|
||||
a: new RemoteData(undefined, undefined, 20, RequestEntryState.SuccessStale, undefined, {}, undefined),
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when both getRequestFromRequestHref and getRequestFromRequestUUID are not stale', () => {
|
||||
let requestEntry1: RequestEntry;
|
||||
let requestEntry2: RequestEntry;
|
||||
|
||||
beforeEach(() => {
|
||||
requestEntry1 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.Success,
|
||||
request: {},
|
||||
lastUpdated: 25,
|
||||
});
|
||||
requestEntry2 = Object.assign(new RequestEntry(), {
|
||||
state: RequestEntryState.Success,
|
||||
request: {},
|
||||
lastUpdated: 5,
|
||||
});
|
||||
(requestService.getByHref as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry1 }));
|
||||
(requestService.getByUUID as jasmine.Spy).and.returnValue(cold('a', { a: requestEntry2 }));
|
||||
spyOn((service as any), 'buildPayload').and.returnValue(cold('a', { a: {} }));
|
||||
});
|
||||
|
||||
it('should create remote-data with the most up-to-date request-entry', () => {
|
||||
expect(service.buildFromHref(cold('a', { a: 'rest/api/endpoint' }))).toBeObservable(cold('a', {
|
||||
a: new RemoteData(undefined, undefined, 25, RequestEntryState.Success, undefined, {}, undefined),
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,9 +3,8 @@ import {
|
||||
combineLatest as observableCombineLatest,
|
||||
Observable,
|
||||
of as observableOf,
|
||||
race as observableRace
|
||||
} from 'rxjs';
|
||||
import { map, switchMap, filter, distinctUntilKeyChanged } from 'rxjs/operators';
|
||||
import { map, switchMap, filter, distinctUntilKeyChanged, startWith } from 'rxjs/operators';
|
||||
import { hasValue, isEmpty, isNotEmpty, hasNoValue, isUndefined } from '../../../shared/empty.util';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
|
||||
import { FollowLinkConfig, followLink } from '../../../shared/utils/follow-link-config.model';
|
||||
@@ -21,7 +20,7 @@ import { HALResource } from '../../shared/hal-resource.model';
|
||||
import { PAGINATED_LIST } from '../../data/paginated-list.resource-type';
|
||||
import { getUrlWithoutEmbedParams } from '../../index/index.selectors';
|
||||
import { getResourceTypeValueFor } from '../object-cache.reducer';
|
||||
import { hasSucceeded, RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { hasSucceeded, isStale, RequestEntryState } from '../../data/request-entry-state.model';
|
||||
import { getRequestFromRequestHref, getRequestFromRequestUUID } from '../../shared/request.operators';
|
||||
import { RequestEntry } from '../../data/request-entry.model';
|
||||
import { ResponseState } from '../../data/response-state.model';
|
||||
@@ -207,10 +206,27 @@ export class RemoteDataBuildService {
|
||||
this.objectCache.getRequestUUIDBySelfLink(href)),
|
||||
);
|
||||
|
||||
const requestEntry$ = observableRace(
|
||||
href$.pipe(getRequestFromRequestHref(this.requestService)),
|
||||
requestUUID$.pipe(getRequestFromRequestUUID(this.requestService)),
|
||||
).pipe(
|
||||
const requestEntry$ = observableCombineLatest([
|
||||
href$.pipe(getRequestFromRequestHref(this.requestService), startWith(undefined)),
|
||||
requestUUID$.pipe(getRequestFromRequestUUID(this.requestService), startWith(undefined)),
|
||||
]).pipe(
|
||||
filter(([r1, r2]) => hasValue(r1) || hasValue(r2)),
|
||||
map(([r1, r2]) => {
|
||||
// If one of the two requests has no value, return the other (both is impossible due to the filter above)
|
||||
if (hasNoValue(r2)) {
|
||||
return r1;
|
||||
} else if (hasNoValue(r1)) {
|
||||
return r2;
|
||||
}
|
||||
|
||||
if ((isStale(r1.state) && isStale(r2.state)) || (!isStale(r1.state) && !isStale(r2.state))) {
|
||||
// Neither or both are stale, pick the most recent request
|
||||
return r1.lastUpdated >= r2.lastUpdated ? r1 : r2;
|
||||
} else {
|
||||
// One of the two is stale, return the not stale request
|
||||
return isStale(r2.state) ? r1 : r2;
|
||||
}
|
||||
}),
|
||||
distinctUntilKeyChanged('lastUpdated')
|
||||
);
|
||||
|
||||
|
@@ -26,6 +26,10 @@ import { EPersonMock, EPersonMock2 } from '../../shared/testing/eperson.mock';
|
||||
import { createPaginatedList, createRequestEntry$ } from '../../shared/testing/utils.test';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from '../data/find-list-options.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { getMockLinkService } from '../../shared/mocks/link-service.mock';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { ObjectCacheEntry } from '../cache/object-cache.reducer';
|
||||
|
||||
describe('GroupDataService', () => {
|
||||
let service: GroupDataService;
|
||||
@@ -38,7 +42,7 @@ describe('GroupDataService', () => {
|
||||
let groups$;
|
||||
let halService;
|
||||
let rdbService;
|
||||
|
||||
let objectCache: ObjectCacheService;
|
||||
function init() {
|
||||
restEndpointURL = 'https://dspace.4science.it/dspace-spring-rest/api/eperson';
|
||||
groupsEndpoint = `${restEndpointURL}/groups`;
|
||||
@@ -46,6 +50,7 @@ describe('GroupDataService', () => {
|
||||
groups$ = createSuccessfulRemoteDataObject$(createPaginatedList(groups));
|
||||
rdbService = getMockRemoteDataBuildServiceHrefMap(undefined, { 'https://dspace.4science.it/dspace-spring-rest/api/eperson/groups': groups$ });
|
||||
halService = new HALEndpointServiceStub(restEndpointURL);
|
||||
objectCache = new ObjectCacheService(store, getMockLinkService());
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -67,7 +72,7 @@ describe('GroupDataService', () => {
|
||||
return new GroupDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
null,
|
||||
objectCache,
|
||||
halService,
|
||||
new DummyChangeAnalyzer() as any,
|
||||
null,
|
||||
@@ -108,6 +113,10 @@ describe('GroupDataService', () => {
|
||||
|
||||
describe('addSubGroupToGroup', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(objectCache, 'getByHref').and.returnValue(observableOf({
|
||||
requestUUIDs: ['request1', 'request2']
|
||||
} as ObjectCacheEntry));
|
||||
spyOn((service as any).deleteData, 'invalidateByHref');
|
||||
service.addSubGroupToGroup(GroupMock, GroupMock2).subscribe();
|
||||
});
|
||||
it('should send PostRequest to eperson/groups/group-id/subgroups endpoint with new subgroup link in body', () => {
|
||||
@@ -118,20 +127,40 @@ describe('GroupDataService', () => {
|
||||
const expected = new PostRequest(requestService.generateRequestId(), GroupMock.self + '/' + service.subgroupsEndpoint, GroupMock2.self, options);
|
||||
expect(requestService.send).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
it('should invalidate the previous requests of the parent group', () => {
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(GroupMock._links.self.href);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledTimes(2);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request1');
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteSubGroupFromGroup', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(objectCache, 'getByHref').and.returnValue(observableOf({
|
||||
requestUUIDs: ['request1', 'request2']
|
||||
} as ObjectCacheEntry));
|
||||
spyOn((service as any).deleteData, 'invalidateByHref');
|
||||
service.deleteSubGroupFromGroup(GroupMock, GroupMock2).subscribe();
|
||||
});
|
||||
it('should send DeleteRequest to eperson/groups/group-id/subgroups/group-id endpoint', () => {
|
||||
const expected = new DeleteRequest(requestService.generateRequestId(), GroupMock.self + '/' + service.subgroupsEndpoint + '/' + GroupMock2.id);
|
||||
expect(requestService.send).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
it('should invalidate the previous requests of the parent group\'', () => {
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(GroupMock._links.self.href);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledTimes(2);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request1');
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('addMemberToGroup', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(objectCache, 'getByHref').and.returnValue(observableOf({
|
||||
requestUUIDs: ['request1', 'request2']
|
||||
} as ObjectCacheEntry));
|
||||
spyOn((service as any).deleteData, 'invalidateByHref');
|
||||
service.addMemberToGroup(GroupMock, EPersonMock2).subscribe();
|
||||
});
|
||||
it('should send PostRequest to eperson/groups/group-id/epersons endpoint with new eperson member in body', () => {
|
||||
@@ -142,20 +171,38 @@ describe('GroupDataService', () => {
|
||||
const expected = new PostRequest(requestService.generateRequestId(), GroupMock.self + '/' + service.ePersonsEndpoint, EPersonMock2.self, options);
|
||||
expect(requestService.send).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
it('should invalidate the previous requests of the EPerson and the group', () => {
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(EPersonMock2._links.self.href);
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(GroupMock._links.self.href);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledTimes(4);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request1');
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteMemberFromGroup', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(objectCache, 'getByHref').and.returnValue(observableOf({
|
||||
requestUUIDs: ['request1', 'request2']
|
||||
} as ObjectCacheEntry));
|
||||
spyOn((service as any).deleteData, 'invalidateByHref');
|
||||
service.deleteMemberFromGroup(GroupMock, EPersonMock).subscribe();
|
||||
});
|
||||
it('should send DeleteRequest to eperson/groups/group-id/epersons/eperson-id endpoint', () => {
|
||||
const expected = new DeleteRequest(requestService.generateRequestId(), GroupMock.self + '/' + service.ePersonsEndpoint + '/' + EPersonMock.id);
|
||||
expect(requestService.send).toHaveBeenCalledWith(expected);
|
||||
});
|
||||
it('should invalidate the previous requests of the EPerson and the group', () => {
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(EPersonMock._links.self.href);
|
||||
expect(objectCache.getByHref).toHaveBeenCalledWith(GroupMock._links.self.href);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledTimes(4);
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request1');
|
||||
expect(requestService.setStaleByUUID).toHaveBeenCalledWith('request2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('editGroup', () => {
|
||||
it('should dispatch a EDIT_GROUP action with the groupp to start editing', () => {
|
||||
it('should dispatch a EDIT_GROUP action with the group to start editing', () => {
|
||||
service.editGroup(GroupMock);
|
||||
expect(store.dispatch).toHaveBeenCalledWith(new GroupRegistryEditGroupAction(GroupMock));
|
||||
});
|
||||
|
@@ -2,8 +2,8 @@ import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { createSelector, select, Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, take } from 'rxjs/operators';
|
||||
import { Observable, AsyncSubject, zip as observableZip } from 'rxjs';
|
||||
import { filter, map, take, switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
GroupRegistryCancelGroupAction,
|
||||
GroupRegistryEditGroupAction
|
||||
@@ -124,7 +124,8 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds given subgroup as a subgroup to the given active group
|
||||
* Adds given subgroup as a subgroup to the given active group and waits until the {@link activeGroup} and
|
||||
* the {@link subgroup} are invalidated.
|
||||
* @param activeGroup Group we want to add subgroup to
|
||||
* @param subgroup Group we want to add as subgroup to activeGroup
|
||||
*/
|
||||
@@ -137,11 +138,46 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
const postRequest = new PostRequest(requestId, activeGroup.self + '/' + this.subgroupsEndpoint, subgroup.self, options);
|
||||
this.requestService.send(postRequest);
|
||||
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
const response$ = this.rdbService.buildFromRequestUUID(requestId);
|
||||
|
||||
const invalidated$ = new AsyncSubject<boolean>();
|
||||
response$.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
switchMap((rd: RemoteData<Group>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return observableZip(
|
||||
this.invalidateByHref(activeGroup._links.self.href),
|
||||
this.requestService.setStaleByHrefSubstring(activeGroup._links.subgroups.href).pipe(take(1)),
|
||||
).pipe(
|
||||
map((arr: boolean[]) => arr.every((b: boolean) => b === true))
|
||||
);
|
||||
} else {
|
||||
return [true];
|
||||
}
|
||||
})
|
||||
).subscribe(() => {
|
||||
invalidated$.next(true);
|
||||
invalidated$.complete();
|
||||
});
|
||||
|
||||
return response$.pipe(
|
||||
switchMap((rd: RemoteData<Group>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return invalidated$.pipe(
|
||||
filter((invalidated: boolean) => invalidated),
|
||||
map(() => rd)
|
||||
);
|
||||
} else {
|
||||
return [rd];
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given subgroup from the subgroups of the given active group
|
||||
* Deletes a given subgroup from the subgroups of the given active group and waits until the {@link activeGroup} and
|
||||
* the {@link subgroup} are invalidated.
|
||||
* are invalidated.
|
||||
* @param activeGroup Group we want to delete subgroup from
|
||||
* @param subgroup Subgroup we want to delete from activeGroup
|
||||
*/
|
||||
@@ -150,11 +186,45 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
const deleteRequest = new DeleteRequest(requestId, activeGroup.self + '/' + this.subgroupsEndpoint + '/' + subgroup.id);
|
||||
this.requestService.send(deleteRequest);
|
||||
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
const response$ = this.rdbService.buildFromRequestUUID(requestId);
|
||||
|
||||
const invalidated$ = new AsyncSubject<boolean>();
|
||||
response$.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
switchMap((rd: RemoteData<NoContent>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return observableZip(
|
||||
this.invalidateByHref(activeGroup._links.self.href),
|
||||
this.requestService.setStaleByHrefSubstring(activeGroup._links.subgroups.href).pipe(take(1)),
|
||||
).pipe(
|
||||
map((arr: boolean[]) => arr.every((b: boolean) => b === true))
|
||||
);
|
||||
} else {
|
||||
return [true];
|
||||
}
|
||||
})
|
||||
).subscribe(() => {
|
||||
invalidated$.next(true);
|
||||
invalidated$.complete();
|
||||
});
|
||||
|
||||
return response$.pipe(
|
||||
switchMap((rd: RemoteData<NoContent>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return invalidated$.pipe(
|
||||
filter((invalidated: boolean) => invalidated),
|
||||
map(() => rd)
|
||||
);
|
||||
} else {
|
||||
return [rd];
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds given ePerson as member to given group
|
||||
* Adds given ePerson as member to a given group and invalidates the ePerson and waits until the {@link ePerson} and
|
||||
* the {@link activeGroup} are invalidated.
|
||||
* @param activeGroup Group we want to add member to
|
||||
* @param ePerson EPerson we want to add as member to given activeGroup
|
||||
*/
|
||||
@@ -167,11 +237,47 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
const postRequest = new PostRequest(requestId, activeGroup.self + '/' + this.ePersonsEndpoint, ePerson.self, options);
|
||||
this.requestService.send(postRequest);
|
||||
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
const response$ = this.rdbService.buildFromRequestUUID(requestId);
|
||||
|
||||
const invalidated$ = new AsyncSubject<boolean>();
|
||||
response$.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
switchMap((rd: RemoteData<NoContent>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return observableZip(
|
||||
this.invalidateByHref(ePerson._links.self.href),
|
||||
this.invalidateByHref(activeGroup._links.self.href),
|
||||
this.requestService.setStaleByHrefSubstring(ePerson._links.groups.href).pipe(take(1)),
|
||||
this.requestService.setStaleByHrefSubstring(activeGroup._links.epersons.href).pipe(take(1)),
|
||||
).pipe(
|
||||
map((arr: boolean[]) => arr.every((b: boolean) => b === true))
|
||||
);
|
||||
} else {
|
||||
return [true];
|
||||
}
|
||||
})
|
||||
).subscribe(() => {
|
||||
invalidated$.next(true);
|
||||
invalidated$.complete();
|
||||
});
|
||||
|
||||
return response$.pipe(
|
||||
switchMap((rd: RemoteData<Group>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return invalidated$.pipe(
|
||||
filter((invalidated: boolean) => invalidated),
|
||||
map(() => rd)
|
||||
);
|
||||
} else {
|
||||
return [rd];
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a given ePerson from the members of the given active group
|
||||
* Deletes a given ePerson from the members of the given active group and waits until the {@link ePerson} and the
|
||||
* {@link activeGroup} are invalidated.
|
||||
* @param activeGroup Group we want to delete member from
|
||||
* @param ePerson EPerson we want to delete from members of given activeGroup
|
||||
*/
|
||||
@@ -180,7 +286,42 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
const deleteRequest = new DeleteRequest(requestId, activeGroup.self + '/' + this.ePersonsEndpoint + '/' + ePerson.id);
|
||||
this.requestService.send(deleteRequest);
|
||||
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
const response$ = this.rdbService.buildFromRequestUUID(requestId);
|
||||
|
||||
const invalidated$ = new AsyncSubject<boolean>();
|
||||
response$.pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
switchMap((rd: RemoteData<NoContent>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return observableZip(
|
||||
this.invalidateByHref(ePerson._links.self.href),
|
||||
this.invalidateByHref(activeGroup._links.self.href),
|
||||
this.requestService.setStaleByHrefSubstring(ePerson._links.groups.href).pipe(take(1)),
|
||||
this.requestService.setStaleByHrefSubstring(activeGroup._links.epersons.href).pipe(take(1)),
|
||||
).pipe(
|
||||
map((arr: boolean[]) => arr.every((b: boolean) => b === true))
|
||||
);
|
||||
} else {
|
||||
return [true];
|
||||
}
|
||||
})
|
||||
).subscribe(() => {
|
||||
invalidated$.next(true);
|
||||
invalidated$.complete();
|
||||
});
|
||||
|
||||
return response$.pipe(
|
||||
switchMap((rd: RemoteData<NoContent>) => {
|
||||
if (rd.hasSucceeded) {
|
||||
return invalidated$.pipe(
|
||||
filter((invalidated: boolean) => invalidated),
|
||||
map(() => rd)
|
||||
);
|
||||
} else {
|
||||
return [rd];
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +417,7 @@ export class GroupDataService extends IdentifiableDataService<Group> implements
|
||||
* @param role The name of the role for which to create a group
|
||||
* @param link The REST endpoint to create the group
|
||||
*/
|
||||
createComcolGroup(dso: Community|Collection, role: string, link: string): Observable<RemoteData<Group>> {
|
||||
createComcolGroup(dso: Community | Collection, role: string, link: string): Observable<RemoteData<Group>> {
|
||||
|
||||
const requestId = this.requestService.generateRequestId();
|
||||
const group = Object.assign(new Group(), {
|
||||
|
@@ -11,7 +11,8 @@ export function getMockObjectCacheService(): ObjectCacheService {
|
||||
'getRequestHrefByUUID',
|
||||
'getList',
|
||||
'hasByUUID',
|
||||
'hasByHref'
|
||||
'hasByHref',
|
||||
'getRequestUUIDBySelfLink',
|
||||
]);
|
||||
|
||||
}
|
||||
|
9
src/app/shared/testing/data-service.stub.ts
Normal file
9
src/app/shared/testing/data-service.stub.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
|
||||
export class DataServiceStub {
|
||||
|
||||
invalidateByHref(_href: string): Observable<boolean> {
|
||||
return observableOf(true);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user