diff --git a/src/app/core/cache/models/search-param.model.ts b/src/app/core/cache/models/search-param.model.ts new file mode 100644 index 0000000000..77d5cb744a --- /dev/null +++ b/src/app/core/cache/models/search-param.model.ts @@ -0,0 +1,6 @@ + +export class SearchParam { + constructor(public fieldName: string, public fieldValue: any) { + + } +} diff --git a/src/app/core/data/data.service.ts b/src/app/core/data/data.service.ts index ba447c32de..6287ce36d7 100644 --- a/src/app/core/data/data.service.ts +++ b/src/app/core/data/data.service.ts @@ -12,6 +12,7 @@ import { FindAllOptions, FindAllRequest, FindByIDRequest, GetRequest } from './r import { RequestService } from './request.service'; import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; import { NormalizedObject } from '../cache/models/normalized-object.model'; +import { SearchParam } from '../cache/models/search-param.model'; export abstract class DataService { protected abstract responseCache: ResponseCacheService; @@ -58,10 +59,16 @@ export abstract class DataService let result: Observable; const args = []; + result = Observable.of(`${endpoint}/search/${searchByLink}`); + + if (hasValue(options.searchParams)) { + options.searchParams.forEach((param: SearchParam) => { + args.push(`${param.fieldName}=${param.fieldValue}`); + }) + } + if (hasValue(options.scopeID)) { - result = Observable.of(`${endpoint}/${searchByLink}?uuid=${options.scopeID}`); - } else { - result = Observable.of(endpoint); + args.push(`uuid=${options.scopeID}`); } if (hasValue(options.currentPage) && typeof options.currentPage === 'number') { @@ -123,38 +130,17 @@ export abstract class DataService return this.rdbService.buildSingle(href); } - // TODO remove when search will be completed - public searchBySubmitter(options: FindAllOptions = {}): Observable>> { - return this.searchBy('submitter', options); - } - - // TODO remove when search will be completed - searchByUser(options: FindAllOptions = {}): Observable>> { - return this.searchBy('user', options); - } - - // TODO remove when search will be completed - protected searchBy(searchBy: string, options: FindAllOptions = {}): Observable>> { - let url = null; - switch (searchBy) { - case 'user': { - url = 'search/findByUser'; - break; - } - case 'submitter': { - url = 'search/findBySubmitter'; - break; - } - } + protected searchBy(searchMethod: string, options: FindAllOptions = {}): Observable>> { const hrefObs = this.halService.getEndpoint(this.linkPath).filter((href: string) => isNotEmpty(href)) - .flatMap((endpoint: string) => this.getSearchByHref(endpoint, url, options)); + .flatMap((endpoint: string) => this.getSearchByHref(endpoint, searchMethod, options)); hrefObs .filter((href: string) => hasValue(href)) .take(1) .subscribe((href: string) => { + console.log(href); const request = new FindAllRequest(this.requestService.generateRequestId(), href, options); - this.requestService.configure(request, this.forceBypassCache); + this.requestService.configure(request, true); }); return this.rdbService.buildList(hrefObs) as Observable>>; diff --git a/src/app/core/data/request.models.ts b/src/app/core/data/request.models.ts index 56d2109646..7cc4a059e8 100644 --- a/src/app/core/data/request.models.ts +++ b/src/app/core/data/request.models.ts @@ -1,7 +1,5 @@ import { SortOptions } from '../cache/models/sort-options.model'; import { GenericConstructor } from '../shared/generic-constructor'; -import { GlobalConfig } from '../../../config/global-config.interface'; -import { RESTURLCombiner } from '../url-combiner/rest-url-combiner'; import { BrowseEntriesResponseParsingService } from './browse-entries-response-parsing.service'; import { DSOResponseParsingService } from './dso-response-parsing.service'; import { ResponseParsingService } from './parsing.service'; @@ -10,10 +8,9 @@ import { BrowseResponseParsingService } from './browse-response-parsing.service' import { ConfigResponseParsingService } from './config-response-parsing.service'; import { AuthResponseParsingService } from '../auth/auth-response-parsing.service'; import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service'; -import { HttpHeaders } from '@angular/common/http'; import { SubmissionResponseParsingService } from '../submission/submission-response-parsing.service'; -import { EpersonResponseParsingService } from '../eperson/eperson-response-parsing.service'; import { IntegrationResponseParsingService } from '../integration/integration-response-parsing.service'; +import { SearchParam } from '../cache/models/search-param.model'; /* tslint:disable:max-classes-per-file */ @@ -143,6 +140,7 @@ export class FindAllOptions { elementsPerPage?: number; currentPage?: number; sort?: SortOptions; + searchParams?: SearchParam[]; } export class FindAllRequest extends GetRequest { @@ -299,7 +297,7 @@ export class EpersonRequest extends GetRequest { } getResponseParser(): GenericConstructor { - return EpersonResponseParsingService; + return DSOResponseParsingService; } } diff --git a/src/app/core/eperson/eperson-data.ts b/src/app/core/eperson/eperson-data.ts deleted file mode 100644 index a0d69a726f..0000000000 --- a/src/app/core/eperson/eperson-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PageInfo } from '../shared/page-info.model'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; - -/** - * A class to represent the data retrieved by a Eperson service - */ -export class EpersonData { - constructor( - public pageInfo: PageInfo, - public payload: NormalizedObject[] - ) { } -} diff --git a/src/app/core/eperson/eperson-object-factory.ts b/src/app/core/eperson/eperson-object-factory.ts deleted file mode 100644 index e2d27d7164..0000000000 --- a/src/app/core/eperson/eperson-object-factory.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { EpersonType } from './eperson-type'; -import { GenericConstructor } from '../shared/generic-constructor'; -import { NormalizedEpersonModel } from './models/NormalizedEperson.model'; -import { NormalizedGroupModel } from './models/NormalizedGroup.model'; -import { NormalizedObject } from '../cache/models/normalized-object.model'; - -export class EpersonObjectFactory { - public static getConstructor(type): GenericConstructor { - switch (type) { - case EpersonType.EpersonsModel: { - return NormalizedEpersonModel - } - case EpersonType.GroupsModel: { - return NormalizedGroupModel - } - default: { - return undefined; - } - } - } -} diff --git a/src/app/core/eperson/eperson-response-parsing.service.ts b/src/app/core/eperson/eperson-response-parsing.service.ts index 6972149798..b4bc9e4676 100644 --- a/src/app/core/eperson/eperson-response-parsing.service.ts +++ b/src/app/core/eperson/eperson-response-parsing.service.ts @@ -1,26 +1,22 @@ import { Inject, Injectable } from '@angular/core'; + import { RestRequest } from '../data/request.models'; import { ResponseParsingService } from '../data/parsing.service'; import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model'; -import { - EpersonSuccessResponse, ErrorResponse, - RestResponse -} from '../cache/response-cache.models'; +import { EpersonSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models'; import { isNotEmpty } from '../../shared/empty.util'; -import { EpersonObjectFactory } from './eperson-object-factory'; -import { EpersonType } from './eperson-type'; - import { BaseResponseParsingService } from '../data/base-response-parsing.service'; import { GLOBAL_CONFIG } from '../../../config'; import { GlobalConfig } from '../../../config/global-config.interface'; import { ObjectCacheService } from '../cache/object-cache.service'; -import { DSpaceObject } from '../shared/dspace-object.model'; import { NormalizedObject } from '../cache/models/normalized-object.model'; +import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory'; +import { ResourceType } from '../shared/resource-type'; @Injectable() export class EpersonResponseParsingService extends BaseResponseParsingService implements ResponseParsingService { - protected objectFactory = EpersonObjectFactory; + protected objectFactory = NormalizedObjectFactory; protected toCache = false; constructor( @@ -32,7 +28,7 @@ export class EpersonResponseParsingService extends BaseResponseParsingService im parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse { if (isNotEmpty(data.payload) && isNotEmpty(data.payload._links)) { - const epersonDefinition = this.process(data.payload, request.href); + const epersonDefinition = this.process(data.payload, request.href); return new EpersonSuccessResponse(epersonDefinition[Object.keys(epersonDefinition)[0]], data.statusCode, this.processPageInfo(data.payload)); } else { return new ErrorResponse( diff --git a/src/app/core/eperson/eperson-type.ts b/src/app/core/eperson/eperson-type.ts deleted file mode 100644 index ca0bbf04bd..0000000000 --- a/src/app/core/eperson/eperson-type.ts +++ /dev/null @@ -1,5 +0,0 @@ - -export enum EpersonType { - EpersonsModel = 'eperson', - GroupsModel = 'group', -} diff --git a/src/app/core/eperson/eperson.service.ts b/src/app/core/eperson/eperson.service.ts index bcd9448f5e..ea278d5aa5 100644 --- a/src/app/core/eperson/eperson.service.ts +++ b/src/app/core/eperson/eperson.service.ts @@ -1,14 +1,12 @@ import { Observable } from 'rxjs/Observable'; import { RequestService } from '../data/request.service'; import { ResponseCacheService } from '../cache/response-cache.service'; -import { EpersonSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models'; -import { EpersonRequest, GetRequest } from '../data/request.models'; -import { ResponseCacheEntry } from '../cache/response-cache.reducer'; -import { isNotEmpty } from '../../shared/empty.util'; +import { EpersonRequest } from '../data/request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { EpersonData } from './eperson-data'; +import { NormalizedObject } from '../cache/models/normalized-object.model'; +import { DataService } from '../data/data.service'; -export abstract class EpersonService { +export abstract class EpersonService extends DataService { protected request: EpersonRequest; protected abstract responseCache: ResponseCacheService; protected abstract requestService: RequestService; @@ -16,38 +14,7 @@ export abstract class EpersonService { protected abstract browseEndpoint: string; protected abstract halService: HALEndpointService; - protected getEperson(request: GetRequest): Observable { - const [successResponse, errorResponse] = this.responseCache.get(request.href) - .map((entry: ResponseCacheEntry) => entry.response) - .partition((response: RestResponse) => response.isSuccessful); - return Observable.merge( - errorResponse.flatMap((response: ErrorResponse) => - Observable.throw(new Error(`Couldn't retrieve the EPerson`))), - successResponse - .filter((response: EpersonSuccessResponse) => isNotEmpty(response)) - .map((response: EpersonSuccessResponse) => new EpersonData(response.pageInfo, response.epersonDefinition)) - .distinctUntilChanged()); - } - - public getDataByHref(href: string): Observable { - const request = new EpersonRequest(this.requestService.generateRequestId(), href); - this.requestService.configure(request); - - return this.getEperson(request); - } - - public getDataByUuid(uuid: string): Observable { - return this.halService.getEndpoint(this.linkPath) - .map((endpoint: string) => this.getDataByIDHref(endpoint, uuid)) - .filter((href: string) => isNotEmpty(href)) - .distinctUntilChanged() - .map((endpointURL: string) => new EpersonRequest(this.requestService.generateRequestId(), endpointURL)) - .do((request: GetRequest) => this.requestService.configure(request)) - .flatMap((request: GetRequest) => this.getEperson(request)) - .distinctUntilChanged(); - } - - protected getDataByIDHref(endpoint, resourceID): string { - return `${endpoint}/${resourceID}`; + public getScopedEndpoint(scopeID: string): Observable { + return this.halService.getEndpoint(this.linkPath); } } diff --git a/src/app/core/eperson/group-eperson.service.ts b/src/app/core/eperson/group-eperson.service.ts index 1f990ef5a0..59a3953ce7 100644 --- a/src/app/core/eperson/group-eperson.service.ts +++ b/src/app/core/eperson/group-eperson.service.ts @@ -1,55 +1,49 @@ import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { filter, map, take } from 'rxjs/operators'; + import { EpersonService } from './eperson.service'; import { ResponseCacheService } from '../cache/response-cache.service'; import { RequestService } from '../data/request.service'; -import { isNotEmpty } from '../../shared/empty.util'; -import { EpersonRequest, GetRequest } from '../data/request.models'; -import { EpersonData } from './eperson-data'; -import { EpersonSuccessResponse, ErrorResponse, RestResponse } from '../cache/response-cache.models'; -import { Observable } from 'rxjs/Observable'; -import { ResponseCacheEntry } from '../cache/response-cache.reducer'; +import { FindAllOptions } from '../data/request.models'; import { HALEndpointService } from '../shared/hal-endpoint.service'; -import { BrowseService } from '../browse/browse.service'; +import { NormalizedGroupModel } from './models/NormalizedGroup.model'; +import { Group } from './models/group.model'; +import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service'; +import { Store } from '@ngrx/store'; +import { CoreState } from '../core.reducers'; +import { ObjectCacheService } from '../cache/object-cache.service'; +import { SearchParam } from '../cache/models/search-param.model'; +import { RemoteData } from '../data/remote-data'; +import { PaginatedList } from '../data/paginated-list'; @Injectable() -export class GroupEpersonService extends EpersonService { +export class GroupEpersonService extends EpersonService { protected linkPath = 'groups'; protected browseEndpoint = ''; + protected forceBypassCache = false; constructor( protected responseCache: ResponseCacheService, protected requestService: RequestService, - protected bs: BrowseService, - protected halService: HALEndpointService) { + protected rdbService: RemoteDataBuildService, + protected store: Store, + protected objectCache: ObjectCacheService, + protected halService: HALEndpointService + ) { super(); } - protected getSearchHref(endpoint, groupName): string { - return `${endpoint}/search/isMemberOf?groupName=${groupName}`; - } + isMemberOf(groupName: string): Observable { + const searchHref = 'isMemberOf'; + const options = new FindAllOptions(); + options.searchParams = [new SearchParam('groupName', groupName)]; - isMemberOf(groupName: string) { - return this.halService.getEndpoint(this.linkPath) - .map((endpoint: string) => this.getSearchHref(endpoint, groupName)) - .filter((href: string) => isNotEmpty(href)) - .distinctUntilChanged() - .map((endpointURL: string) => new EpersonRequest(this.requestService.generateRequestId(), endpointURL)) - .do((request: GetRequest) => this.requestService.configure(request)) - .flatMap((request: GetRequest) => this.getSearch(request)) - .distinctUntilChanged(); - } - - protected getSearch(request: GetRequest): Observable { - const [successResponse, errorResponse] = this.responseCache.get(request.href) - .map((entry: ResponseCacheEntry) => entry.response) - .partition((response: RestResponse) => response.isSuccessful); - return Observable.merge( - errorResponse.flatMap((response: ErrorResponse) => - Observable.of(new EpersonData(undefined, undefined))), - successResponse - .filter((response: EpersonSuccessResponse) => isNotEmpty(response)) - .map((response: EpersonSuccessResponse) => new EpersonData(response.pageInfo, response.epersonDefinition)) - .distinctUntilChanged()); + return this.searchBy(searchHref, options).pipe( + filter((groups: RemoteData>) => !groups.isResponsePending), + take(1), + map((groups: RemoteData>) => groups.payload.totalElements > 0) + ); } } diff --git a/src/app/submission/sections/upload/accessConditions/accessConditions.component.ts b/src/app/submission/sections/upload/accessConditions/accessConditions.component.ts index c89886d69d..d05da19b0e 100644 --- a/src/app/submission/sections/upload/accessConditions/accessConditions.component.ts +++ b/src/app/submission/sections/upload/accessConditions/accessConditions.component.ts @@ -2,8 +2,8 @@ import { Component, Input, OnInit } from '@angular/core'; import { GroupEpersonService } from '../../../../core/eperson/group-eperson.service'; import { ResourcePolicy } from '../../../../core/shared/resource-policy.model'; import { isEmpty } from '../../../../shared/empty.util'; -import { EpersonData } from '../../../../core/eperson/eperson-data'; import { Group } from '../../../../core/eperson/models/group.model'; +import { RemoteData } from '../../../../core/data/remote-data'; @Component({ selector: 'ds-access-conditions', @@ -20,9 +20,11 @@ export class AccessConditionsComponent implements OnInit { ngOnInit() { this.accessConditions.forEach((accessCondition: ResourcePolicy) => { if (isEmpty(accessCondition.name)) { - this.groupService.getDataByUuid(accessCondition.groupUUID) - .subscribe((data: EpersonData) => { - const group = data.payload[0] as any; + this.groupService.findById(accessCondition.groupUUID) + .filter((rd: RemoteData) => !rd.isResponsePending && rd.hasSucceeded) + .take(1) + .subscribe((rd: RemoteData) => { + const group: Group = rd.payload; const accessConditionEntry = Object.assign({}, accessCondition); accessConditionEntry.name = group.name; this.accessConditionsList.push(accessConditionEntry); diff --git a/src/app/submission/sections/upload/section-upload.component.ts b/src/app/submission/sections/upload/section-upload.component.ts index c3b64ac70d..edf76fe676 100644 --- a/src/app/submission/sections/upload/section-upload.component.ts +++ b/src/app/submission/sections/upload/section-upload.component.ts @@ -10,7 +10,6 @@ import { GroupEpersonService } from '../../../core/eperson/group-eperson.service import { SubmissionUploadsConfigService } from '../../../core/config/submission-uploads-config.service'; import { SubmissionUploadsModel } from '../../../core/shared/config/config-submission-uploads.model'; import { Observable } from 'rxjs/Observable'; -import { EpersonData } from '../../../core/eperson/eperson-data'; import { SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model'; import { SectionsType } from '../sections-type'; import { renderSectionFor } from '../sections-decorator'; @@ -18,6 +17,8 @@ import { SectionDataObject } from '../models/section-data.model'; import { submissionObjectFromIdSelector } from '../../selectors'; import { SubmissionObjectEntry } from '../../objects/submission-objects.reducer'; import { AlertType } from '../../../shared/alerts/aletrs-type'; +import { RemoteData } from '../../../core/data/remote-data'; +import { Group } from '../../../core/eperson/models/group.model'; export const POLICY_DEFAULT_NO_LIST = 1; // Banner1 export const POLICY_DEFAULT_WITH_LIST = 2; // Banner2 @@ -113,16 +114,19 @@ export class UploadSectionComponent extends SectionModelComponent implements OnI // Retrieve Groups for accessConditionPolicies this.availableAccessConditionOptions.forEach((accessCondition) => { if (accessCondition.hasEndDate === true || accessCondition.hasStartDate === true) { - groupsObs.push(this.groupService.getDataByUuid(accessCondition.groupUUID) + groupsObs.push( + this.groupService.findById(accessCondition.groupUUID) + .filter((rd: RemoteData) => !rd.isResponsePending && rd.hasSucceeded) + .take(1) ); } }); let obsCounter = 1; - Observable.merge(groupsObs) + Observable.forkJoin(groupsObs) .flatMap((group) => group) .take(groupsObs.length) - .subscribe((data: EpersonData) => { - const group = data.payload[0] as any; + .subscribe((rd: RemoteData) => { + const group: Group = rd.payload; if (isUndefined(this.availableGroups.get(group.uuid))) { if (Array.isArray(group.groups)) { const groupArrayData = []; @@ -156,7 +160,7 @@ export class UploadSectionComponent extends SectionModelComponent implements OnI this.fileNames = []; this.changeDetectorRef.detectChanges(); if (isNotUndefined(fileList) && fileList.length > 0) { - fileList.forEach((file, index) => { + fileList.forEach((file) => { this.fileList.push(file); this.fileIndexes.push(file.uuid); const fileName = file.metadata['dc.title'][0].display || file.uuid;