mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-18 07:23:03 +00:00
93803: Refactor existing data services
This commit is contained in:
@@ -76,6 +76,6 @@ describe('AccessStatusDataService', () => {
|
||||
});
|
||||
halService = new HALEndpointServiceStub(url);
|
||||
notificationsService = new NotificationsServiceStub();
|
||||
service = new AccessStatusDataService(null, halService, null, notificationsService, objectCache, rdbService, requestService, null);
|
||||
service = new AccessStatusDataService(requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
});
|
||||
|
@@ -1,38 +1,27 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { AccessStatusObject } from 'src/app/shared/object-list/access-status-badge/access-status.model';
|
||||
import { ACCESS_STATUS } from 'src/app/shared/object-list/access-status-badge/access-status.resource-type';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
|
||||
@Injectable()
|
||||
@dataService(ACCESS_STATUS)
|
||||
export class AccessStatusDataService extends DataService<AccessStatusObject> {
|
||||
|
||||
protected linkPath = 'accessStatus';
|
||||
export class AccessStatusDataService extends BaseDataService<AccessStatusObject> {
|
||||
|
||||
constructor(
|
||||
protected comparator: DefaultChangeAnalyzer<AccessStatusObject>,
|
||||
protected halService: HALEndpointService,
|
||||
protected http: HttpClient,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected requestService: RequestService,
|
||||
protected store: Store<CoreState>,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
) {
|
||||
super();
|
||||
super('accessStatus', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -47,7 +47,7 @@ describe('BitstreamDataService', () => {
|
||||
});
|
||||
rdbService = getMockRemoteDataBuildService();
|
||||
|
||||
service = new BitstreamDataService(requestService, rdbService, null, objectCache, halService, null, null, null, null, bitstreamFormatService);
|
||||
service = new BitstreamDataService(requestService, rdbService, objectCache, halService, null, bitstreamFormatService, null, null);
|
||||
});
|
||||
|
||||
describe('when updating the bitstream\'s format', () => {
|
||||
|
@@ -1,10 +1,8 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
@@ -15,8 +13,6 @@ import { Bundle } from '../shared/bundle.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { BundleDataService } from './bundle-data.service';
|
||||
import { DataService } from './data.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { buildPaginatedList, PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PutRequest } from './request.models';
|
||||
@@ -28,36 +24,43 @@ import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.util
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
import { PatchData, PatchDataImpl } from './base/patch-data';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
/**
|
||||
* A service to retrieve {@link Bitstream}s from the REST API
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
@dataService(BITSTREAM)
|
||||
export class BitstreamDataService extends DataService<Bitstream> {
|
||||
|
||||
/**
|
||||
* The HAL path to the bitstream endpoint
|
||||
*/
|
||||
protected linkPath = 'bitstreams';
|
||||
export class BitstreamDataService extends IdentifiableDataService<Bitstream> implements SearchData<Bitstream>, PatchData<Bitstream>, DeleteData<Bitstream> {
|
||||
private searchData: SearchDataImpl<Bitstream>;
|
||||
private patchData: PatchDataImpl<Bitstream>;
|
||||
private deleteData: DeleteDataImpl<Bitstream>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Bitstream>,
|
||||
protected bundleService: BundleDataService,
|
||||
protected bitstreamFormatService: BitstreamFormatDataService
|
||||
protected bitstreamFormatService: BitstreamFormatDataService,
|
||||
protected comparator: DSOChangeAnalyzer<Bitstream>,
|
||||
protected notificationsService: NotificationsService,
|
||||
) {
|
||||
super();
|
||||
super('bitstreams', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.patchData = new PatchDataImpl<Bitstream>(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,8 +183,89 @@ export class BitstreamDataService extends DataService<Bitstream> {
|
||||
hrefObs,
|
||||
useCachedVersionIfAvailable,
|
||||
reRequestOnStale,
|
||||
...linksToFollow
|
||||
...linksToFollow,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HREF for a specific object's search method with given options object
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @return {Observable<string>}
|
||||
* Return an observable that emits created HREF
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
public getSearchByHref(searchMethod: string, options?: FindListOptions, ...linksToFollow: FollowLinkConfig<Bitstream>[]): Observable<string> {
|
||||
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
public searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Bitstream>[]): Observable<RemoteData<PaginatedList<Bitstream>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
* @param method The RestRequestMethod for which de server sync buffer should be committed
|
||||
*/
|
||||
public commitUpdates(method?: RestRequestMethod): void {
|
||||
this.patchData.commitUpdates(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a patch request for a specified object
|
||||
* @param {T} object The object to send a patch request for
|
||||
* @param {Operation[]} operations The patch operations to be performed
|
||||
*/
|
||||
public patch(object: Bitstream, operations: []): Observable<RemoteData<Bitstream>> {
|
||||
return this.patchData.patch(object, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
* @param {DSpaceObject} object The given object
|
||||
*/
|
||||
public update(object: Bitstream): Observable<RemoteData<Bitstream>> {
|
||||
return this.patchData.update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
}
|
||||
|
@@ -50,8 +50,6 @@ describe('BitstreamFormatDataService', () => {
|
||||
} as HALEndpointService;
|
||||
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
|
||||
let rd;
|
||||
let rdbService: RemoteDataBuildService;
|
||||
@@ -65,12 +63,10 @@ describe('BitstreamFormatDataService', () => {
|
||||
return new BitstreamFormatDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator
|
||||
store,
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,8 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { createSelector, select, Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map, tap } from 'rxjs/operators';
|
||||
import {
|
||||
BitstreamFormatsRegistryDeselectAction,
|
||||
BitstreamFormatsRegistryDeselectAllAction,
|
||||
BitstreamFormatsRegistrySelectAction
|
||||
} from '../../admin/admin-registries/bitstream-formats/bitstream-format.actions';
|
||||
import { BitstreamFormatsRegistryDeselectAction, BitstreamFormatsRegistryDeselectAllAction, BitstreamFormatsRegistrySelectAction } from '../../admin/admin-registries/bitstream-formats/bitstream-format.actions';
|
||||
import { BitstreamFormatRegistryState } from '../../admin/admin-registries/bitstream-formats/bitstream-format.reducers';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
@@ -18,40 +13,52 @@ import { BitstreamFormat } from '../shared/bitstream-format.model';
|
||||
import { BITSTREAM_FORMAT } from '../shared/bitstream-format.resource-type';
|
||||
import { Bitstream } from '../shared/bitstream.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PostRequest, PutRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
import { FindAllData, FindAllDataImpl } from './base/find-all-data';
|
||||
import { FollowLinkConfig } from 'src/app/shared/utils/follow-link-config.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
|
||||
const bitstreamFormatsStateSelector = createSelector(
|
||||
coreSelector,
|
||||
(state: CoreState) => state.bitstreamFormats
|
||||
(state: CoreState) => state.bitstreamFormats,
|
||||
);
|
||||
const selectedBitstreamFormatSelector = createSelector(
|
||||
bitstreamFormatsStateSelector,
|
||||
(bitstreamFormatRegistryState: BitstreamFormatRegistryState) => bitstreamFormatRegistryState.selectedBitstreamFormats,
|
||||
);
|
||||
const selectedBitstreamFormatSelector = createSelector(bitstreamFormatsStateSelector,
|
||||
(bitstreamFormatRegistryState: BitstreamFormatRegistryState) => bitstreamFormatRegistryState.selectedBitstreamFormats);
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the bitstreamformats endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(BITSTREAM_FORMAT)
|
||||
export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
|
||||
export class BitstreamFormatDataService extends IdentifiableDataService<BitstreamFormat> implements FindAllData<BitstreamFormat>, DeleteData<BitstreamFormat> {
|
||||
|
||||
protected linkPath = 'bitstreamformats';
|
||||
|
||||
private findAllData: FindAllDataImpl<BitstreamFormat>;
|
||||
private deleteData: DeleteDataImpl<BitstreamFormat>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<BitstreamFormat>) {
|
||||
super();
|
||||
protected store: Store<CoreState>,
|
||||
) {
|
||||
super('bitstreamformats', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +67,7 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
|
||||
*/
|
||||
public getUpdateEndpoint(formatId: string): Observable<string> {
|
||||
return this.getBrowseEndpoint().pipe(
|
||||
map((endpoint: string) => this.getIDHref(endpoint, formatId))
|
||||
map((endpoint: string) => this.getIDHref(endpoint, formatId)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -147,4 +154,47 @@ export class BitstreamFormatDataService extends DataService<BitstreamFormat> {
|
||||
findByBitstream(bitstream: Bitstream): Observable<RemoteData<BitstreamFormat>> {
|
||||
return this.findByHref(bitstream._links.format.href);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<BitstreamFormat>[]): Observable<RemoteData<PaginatedList<BitstreamFormat>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
}
|
||||
|
@@ -64,9 +64,6 @@ describe('BundleDataService', () => {
|
||||
store,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator,
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,7 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, switchMap, take } from 'rxjs/operators';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
@@ -13,8 +10,6 @@ import { Bundle } from '../shared/bundle.model';
|
||||
import { BUNDLE } from '../shared/bundle.resource-type';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { GetRequest } from './request.models';
|
||||
@@ -22,30 +17,35 @@ import { RequestService } from './request.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { Bitstream } from '../shared/bitstream.model';
|
||||
import { RequestEntryState } from './request-entry-state.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { PatchData, PatchDataImpl } from './base/patch-data';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
|
||||
/**
|
||||
* A service to retrieve {@link Bundle}s from the REST API
|
||||
*/
|
||||
@Injectable(
|
||||
{providedIn: 'root'}
|
||||
{ providedIn: 'root' },
|
||||
)
|
||||
@dataService(BUNDLE)
|
||||
export class BundleDataService extends DataService<Bundle> {
|
||||
protected linkPath = 'bundles';
|
||||
protected bitstreamsEndpoint = 'bitstreams';
|
||||
export class BundleDataService extends IdentifiableDataService<Bundle> implements PatchData<Bundle> {
|
||||
private bitstreamsEndpoint = 'bitstreams';
|
||||
|
||||
private patchData: PatchDataImpl<Bundle>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Bundle>) {
|
||||
super();
|
||||
protected comparator: DSOChangeAnalyzer<Bundle>,
|
||||
) {
|
||||
super('bundles', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.patchData = new PatchDataImpl<Bundle>(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +133,7 @@ export class BundleDataService extends DataService<Bundle> {
|
||||
const hrefObs = this.getBitstreamsEndpoint(bundleId, searchOptions);
|
||||
|
||||
hrefObs.pipe(
|
||||
take(1)
|
||||
take(1),
|
||||
).subscribe((href) => {
|
||||
const request = new GetRequest(this.requestService.generateRequestId(), href);
|
||||
this.requestService.send(request, true);
|
||||
@@ -141,4 +141,30 @@ export class BundleDataService extends DataService<Bundle> {
|
||||
|
||||
return this.rdbService.buildList<Bitstream>(hrefObs, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
* @param method The RestRequestMethod for which de server sync buffer should be committed
|
||||
*/
|
||||
public commitUpdates(method?: RestRequestMethod): void {
|
||||
this.patchData.commitUpdates(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a patch request for a specified object
|
||||
* @param {T} object The object to send a patch request for
|
||||
* @param {Operation[]} operations The patch operations to be performed
|
||||
*/
|
||||
public patch(object: Bundle, operations: Operation[]): Observable<RemoteData<Bundle>> {
|
||||
return this.patchData.patch(object, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
* @param {DSpaceObject} object The given object
|
||||
*/
|
||||
public update(object: Bundle): Observable<RemoteData<Bundle>> {
|
||||
return this.patchData.update(object);
|
||||
}
|
||||
}
|
||||
|
@@ -201,7 +201,7 @@ describe('CollectionDataService', () => {
|
||||
notificationsService = new NotificationsServiceStub();
|
||||
translate = getMockTranslateService();
|
||||
|
||||
service = new CollectionDataService(requestService, rdbService, null, null, objectCache, halService, notificationsService, null, null, null, translate);
|
||||
service = new CollectionDataService(requestService, rdbService, objectCache, halService, null, notificationsService, null, null, translate);
|
||||
}
|
||||
|
||||
});
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||
@@ -33,30 +32,27 @@ import {
|
||||
import { RequestService } from './request.service';
|
||||
import { BitstreamDataService } from './bitstream-data.service';
|
||||
import { RestRequest } from './rest-request.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { Community } from '../shared/community.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(COLLECTION)
|
||||
export class CollectionDataService extends ComColDataService<Collection> {
|
||||
protected linkPath = 'collections';
|
||||
protected errorTitle = 'collection.source.update.notifications.error.title';
|
||||
protected contentSourceError = 'collection.source.update.notifications.error.content';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected cds: CommunityDataService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected comparator: DSOChangeAnalyzer<Community>,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected bitstreamDataService: BitstreamDataService,
|
||||
protected comparator: DSOChangeAnalyzer<Collection>,
|
||||
protected translate: TranslateService
|
||||
protected communityDataService: CommunityDataService,
|
||||
protected translate: TranslateService,
|
||||
) {
|
||||
super();
|
||||
super('collections', requestService, rdbService, objectCache, halService, comparator, notificationsService, bitstreamDataService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,10 +285,10 @@ export class CollectionDataService extends ComColDataService<Collection> {
|
||||
|
||||
|
||||
protected getScopeCommunityHref(options: FindListOptions) {
|
||||
return this.cds.getEndpoint().pipe(
|
||||
map((endpoint: string) => this.cds.getIDHref(endpoint, options.scopeID)),
|
||||
return this.communityDataService.getEndpoint().pipe(
|
||||
map((endpoint: string) => this.communityDataService.getIDHref(endpoint, options.scopeID)),
|
||||
filter((href: string) => isNotEmpty(href)),
|
||||
take(1)
|
||||
take(1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ class TestService extends ComColDataService<any> {
|
||||
protected comparator: DSOChangeAnalyzer<Community>,
|
||||
protected linkPath: string
|
||||
) {
|
||||
super();
|
||||
super('something', requestService, rdbService, objectCache, halService, comparator, notificationsService, bitstreamDataService);
|
||||
}
|
||||
|
||||
protected getFindByParentHref(parentUUID: string): Observable<string> {
|
||||
|
@@ -4,7 +4,6 @@ import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { Community } from '../shared/community.model';
|
||||
import { HALLink } from '../shared/hal-link.model';
|
||||
import { DataService } from './data.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
@@ -17,11 +16,44 @@ import { createFailedRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { PatchData, PatchDataImpl } from './base/patch-data';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
import { FindAllData, FindAllDataImpl } from './base/find-all-data';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { CreateData, CreateDataImpl } from './base/create-data';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
|
||||
export abstract class ComColDataService<T extends Community | Collection> extends DataService<T> {
|
||||
protected abstract objectCache: ObjectCacheService;
|
||||
protected abstract halService: HALEndpointService;
|
||||
protected abstract bitstreamDataService: BitstreamDataService;
|
||||
export abstract class ComColDataService<T extends Community | Collection> extends IdentifiableDataService<T> implements CreateData<T>, FindAllData<T>, SearchData<T>, PatchData<T>, DeleteData<T> {
|
||||
private createData: CreateData<T>;
|
||||
private findAllData: FindAllData<T>;
|
||||
private searchData: SearchData<T>;
|
||||
private patchData: PatchData<T>;
|
||||
private deleteData: DeleteData<T>;
|
||||
|
||||
protected constructor(
|
||||
protected linkPath: string,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected comparator: DSOChangeAnalyzer<T>,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected bitstreamDataService: BitstreamDataService,
|
||||
) {
|
||||
super(linkPath, requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.searchData = new SearchDataImpl<T>(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.patchData = new PatchDataImpl<T>(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scoped endpoint URL by fetching the object with
|
||||
@@ -129,4 +161,128 @@ export abstract class ComColDataService<T extends Community | Collection> extend
|
||||
const parentCommunity = dso._links.parentCommunity;
|
||||
return isNotEmpty(parentCommunity) ? parentCommunity.href : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new object on the server, and store the response in the object cache
|
||||
*
|
||||
* @param object The object to create
|
||||
* @param params Array with additional params to combine with query string
|
||||
*/
|
||||
create(object: T, ...params: RequestParam[]): Observable<RemoteData<T>> {
|
||||
return this.createData.create(object, ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HREF with given options object
|
||||
*
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param linkPath The link path for the object
|
||||
* @return {Observable<string>}
|
||||
* Return an observable that emits created HREF
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
public getFindAllHref(options?: FindListOptions, linkPath?: string, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
||||
return this.findAllData.getFindAllHref(options, linkPath, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HREF for a specific object's search method with given options object
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @return {Observable<string>}
|
||||
* Return an observable that emits created HREF
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
public getSearchByHref(searchMethod: string, options?: FindListOptions, ...linksToFollow: FollowLinkConfig<T>[]): Observable<string> {
|
||||
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
public searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<T>[]): Observable<RemoteData<PaginatedList<T>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
* @param method The RestRequestMethod for which de server sync buffer should be committed
|
||||
*/
|
||||
public commitUpdates(method?: RestRequestMethod): void {
|
||||
this.patchData.commitUpdates(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a patch request for a specified object
|
||||
* @param {T} object The object to send a patch request for
|
||||
* @param {Operation[]} operations The patch operations to be performed
|
||||
*/
|
||||
public patch(object: T, operations: []): Observable<RemoteData<T>> {
|
||||
return this.patchData.patch(object, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
* @param {DSpaceObject} object The given object
|
||||
*/
|
||||
public update(object: T): Observable<RemoteData<T>> {
|
||||
return this.patchData.update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
@@ -19,27 +17,23 @@ import { RequestService } from './request.service';
|
||||
import { BitstreamDataService } from './bitstream-data.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(COMMUNITY)
|
||||
export class CommunityDataService extends ComColDataService<Community> {
|
||||
protected linkPath = 'communities';
|
||||
protected topLinkPath = 'search/top';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected comparator: DSOChangeAnalyzer<Community>,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected bitstreamDataService: BitstreamDataService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Community>
|
||||
) {
|
||||
super();
|
||||
super('communities', requestService, rdbService, objectCache, halService, comparator, notificationsService, bitstreamDataService);
|
||||
}
|
||||
|
||||
getEndpoint() {
|
||||
|
@@ -5,8 +5,6 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { GetRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { ConfigurationDataService } from './configuration-data.service';
|
||||
import { ConfigurationProperty } from '../shared/configuration-property.model';
|
||||
|
||||
@@ -44,18 +42,12 @@ describe('ConfigurationDataService', () => {
|
||||
})
|
||||
});
|
||||
objectCache = {} as ObjectCacheService;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
|
||||
service = new ConfigurationDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator
|
||||
);
|
||||
});
|
||||
|
||||
|
@@ -1,55 +1,30 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RequestService } from './request.service';
|
||||
import { ConfigurationProperty } from '../shared/configuration-property.model';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { CONFIG_PROPERTY } from '../shared/config-property.resource-type';
|
||||
import { CoreState } from '../core-state.model';
|
||||
|
||||
class DataServiceImpl extends DataService<ConfigurationProperty> {
|
||||
protected linkPath = 'properties';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<ConfigurationProperty>) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
@Injectable()
|
||||
@dataService(CONFIG_PROPERTY)
|
||||
/**
|
||||
* Data Service responsible for retrieving Configuration properties
|
||||
*/
|
||||
export class ConfigurationDataService {
|
||||
protected linkPath = 'properties';
|
||||
private dataService: DataServiceImpl;
|
||||
export class ConfigurationDataService extends IdentifiableDataService<ConfigurationProperty> {
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<ConfigurationProperty>) {
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
|
||||
) {
|
||||
super('properties', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,6 +32,6 @@ export class ConfigurationDataService {
|
||||
* @param name
|
||||
*/
|
||||
findByPropertyName(name: string): Observable<RemoteData<ConfigurationProperty>> {
|
||||
return this.dataService.findById(name);
|
||||
return this.findById(name);
|
||||
}
|
||||
}
|
||||
|
@@ -1,22 +1,18 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { cold, getTestScheduler } from 'jasmine-marbles';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DsoRedirectDataService } from './dso-redirect-data.service';
|
||||
import { DsoRedirectService } from './dso-redirect.service';
|
||||
import { GetRequest, IdentifierType } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
|
||||
describe('DsoRedirectDataService', () => {
|
||||
describe('DsoRedirectService', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: DsoRedirectDataService;
|
||||
let service: DsoRedirectService;
|
||||
let halService: HALEndpointService;
|
||||
let requestService: RequestService;
|
||||
let rdbService: RemoteDataBuildService;
|
||||
@@ -29,10 +25,6 @@ describe('DsoRedirectDataService', () => {
|
||||
const requestHandleURL = `https://rest.api/rest/api/pid/find?id=${encodedHandle}`;
|
||||
const requestUUIDURL = `https://rest.api/rest/api/pid/find?id=${dsoUUID}`;
|
||||
const requestUUID = '34cfed7c-f597-49ef-9cbe-ea351f0023c2';
|
||||
const store = {} as Store<CoreState>;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
const objectCache = {} as ObjectCacheService;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -59,20 +51,16 @@ describe('DsoRedirectDataService', () => {
|
||||
a: remoteData
|
||||
})
|
||||
});
|
||||
service = new DsoRedirectDataService(
|
||||
service = new DsoRedirectService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator,
|
||||
router
|
||||
router,
|
||||
);
|
||||
});
|
||||
|
||||
describe('findById', () => {
|
||||
describe('findByIdAndIDType', () => {
|
||||
it('should call HALEndpointService with the path to the pid endpoint', () => {
|
||||
scheduler.schedule(() => service.findByIdAndIDType(dsoHandle, IdentifierType.HANDLE));
|
||||
scheduler.flush();
|
||||
@@ -141,7 +129,7 @@ describe('DsoRedirectDataService', () => {
|
||||
redir.subscribe();
|
||||
scheduler.schedule(() => redir);
|
||||
scheduler.flush();
|
||||
expect(router.navigate).toHaveBeenCalledWith([remoteData.payload.type + 's/' + remoteData.payload.uuid]);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/collections/' + remoteData.payload.uuid]);
|
||||
});
|
||||
|
||||
it('should navigate to communities route', () => {
|
||||
@@ -150,55 +138,58 @@ describe('DsoRedirectDataService', () => {
|
||||
redir.subscribe();
|
||||
scheduler.schedule(() => redir);
|
||||
scheduler.flush();
|
||||
expect(router.navigate).toHaveBeenCalledWith(['communities/' + remoteData.payload.uuid]);
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/communities/' + remoteData.payload.uuid]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIDHref', () => {
|
||||
it('should return endpoint', () => {
|
||||
const result = (service as any).getIDHref(pidLink, dsoUUID);
|
||||
expect(result).toEqual(requestUUIDURL);
|
||||
});
|
||||
describe('DataService', () => { // todo: should only test the id/uuid interpolation thingy
|
||||
describe('getIDHref', () => { // todo: should be able to move this up to IdentifiableDataService?
|
||||
it('should return endpoint', () => {
|
||||
const result = (service as any).dataService.getIDHref(pidLink, dsoUUID);
|
||||
expect(result).toEqual(requestUUIDURL);
|
||||
});
|
||||
|
||||
it('should include single linksToFollow as embed', () => {
|
||||
const expected = `${requestUUIDURL}&embed=bundles`;
|
||||
const result = (service as any).getIDHref(pidLink, dsoUUID, followLink('bundles'));
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should include single linksToFollow as embed', () => {
|
||||
const expected = `${requestUUIDURL}&embed=bundles`;
|
||||
const result = (service as any).dataService.getIDHref(pidLink, dsoUUID, followLink('bundles'));
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should include multiple linksToFollow as embed', () => {
|
||||
const expected = `${requestUUIDURL}&embed=bundles&embed=owningCollection&embed=templateItemOf`;
|
||||
const result = (service as any).getIDHref(pidLink, dsoUUID, followLink('bundles'), followLink('owningCollection'), followLink('templateItemOf'));
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should include multiple linksToFollow as embed', () => {
|
||||
const expected = `${requestUUIDURL}&embed=bundles&embed=owningCollection&embed=templateItemOf`;
|
||||
const result = (service as any).dataService.getIDHref(pidLink, dsoUUID, followLink('bundles'), followLink('owningCollection'), followLink('templateItemOf'));
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should not include linksToFollow with shouldEmbed = false', () => {
|
||||
const expected = `${requestUUIDURL}&embed=templateItemOf`;
|
||||
const result = (service as any).getIDHref(
|
||||
pidLink,
|
||||
dsoUUID,
|
||||
followLink('bundles', { shouldEmbed: false }),
|
||||
followLink('owningCollection', { shouldEmbed: false }),
|
||||
followLink('templateItemOf')
|
||||
);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
it('should not include linksToFollow with shouldEmbed = false', () => {
|
||||
const expected = `${requestUUIDURL}&embed=templateItemOf`;
|
||||
const result = (service as any).dataService.getIDHref(
|
||||
pidLink,
|
||||
dsoUUID,
|
||||
followLink('bundles', { shouldEmbed: false }),
|
||||
followLink('owningCollection', { shouldEmbed: false }),
|
||||
followLink('templateItemOf'),
|
||||
);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should include nested linksToFollow 3lvl', () => {
|
||||
const expected = `${requestUUIDURL}&embed=owningCollection/itemtemplate/relationships`;
|
||||
const result = (service as any).getIDHref(
|
||||
pidLink,
|
||||
dsoUUID,
|
||||
followLink('owningCollection',
|
||||
{},
|
||||
followLink('itemtemplate',
|
||||
it('should include nested linksToFollow 3lvl', () => {
|
||||
const expected = `${requestUUIDURL}&embed=owningCollection/itemtemplate/relationships`;
|
||||
const result = (service as any).dataService.getIDHref(
|
||||
pidLink,
|
||||
dsoUUID,
|
||||
followLink(
|
||||
'owningCollection',
|
||||
{},
|
||||
followLink('relationships')
|
||||
)
|
||||
)
|
||||
);
|
||||
expect(result).toEqual(expected);
|
||||
followLink(
|
||||
'itemtemplate',
|
||||
{},
|
||||
followLink('relationships'),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,95 +0,0 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { IdentifierType } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { getFirstCompletedRemoteData } from '../shared/operators';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { getItemPageRoute } from '../../item-page/item-page-routing-paths';
|
||||
import { CoreState } from '../core-state.model';
|
||||
|
||||
@Injectable()
|
||||
export class DsoRedirectDataService extends DataService<any> {
|
||||
|
||||
// Set the default link path to the identifier lookup endpoint.
|
||||
protected linkPath = 'pid';
|
||||
private uuidEndpoint = 'dso';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<any>,
|
||||
private router: Router) {
|
||||
super();
|
||||
}
|
||||
|
||||
setLinkPath(identifierType: IdentifierType) {
|
||||
// The default 'pid' endpoint for identifiers does not support uuid lookups.
|
||||
// For uuid lookups we need to change the linkPath.
|
||||
if (identifierType === IdentifierType.UUID) {
|
||||
this.linkPath = this.uuidEndpoint;
|
||||
}
|
||||
}
|
||||
|
||||
getIDHref(endpoint, resourceID, ...linksToFollow: FollowLinkConfig<any>[]): string {
|
||||
// Supporting both identifier (pid) and uuid (dso) endpoints
|
||||
return this.buildHrefFromFindOptions( endpoint.replace(/\{\?id\}/, `?id=${resourceID}`)
|
||||
.replace(/\{\?uuid\}/, `?uuid=${resourceID}`),
|
||||
{}, [], ...linksToFollow);
|
||||
}
|
||||
|
||||
findByIdAndIDType(id: string, identifierType = IdentifierType.UUID): Observable<RemoteData<DSpaceObject>> {
|
||||
this.setLinkPath(identifierType);
|
||||
return this.findById(id).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
tap((response) => {
|
||||
if (response.hasSucceeded) {
|
||||
const dso = response.payload;
|
||||
const uuid = dso.uuid;
|
||||
if (hasValue(uuid)) {
|
||||
let newRoute = this.getEndpointFromDSOType(response.payload.type);
|
||||
if (dso.type.startsWith('item')) {
|
||||
newRoute = getItemPageRoute(dso as Item);
|
||||
} else if (hasValue(newRoute)) {
|
||||
newRoute += '/' + uuid;
|
||||
}
|
||||
if (hasValue(newRoute)) {
|
||||
this.router.navigate([newRoute]);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
// Is there an existing method somewhere else that converts dso type to route?
|
||||
getEndpointFromDSOType(dsoType: string): string {
|
||||
// Are there other types to consider?
|
||||
if (dsoType.startsWith('item')) {
|
||||
return 'items';
|
||||
} else if (dsoType.startsWith('community')) {
|
||||
return 'communities';
|
||||
} else if (dsoType.startsWith('collection')) {
|
||||
return 'collections';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
90
src/app/core/data/dso-redirect.service.ts
Normal file
90
src/app/core/data/dso-redirect.service.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { IdentifierType } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { getFirstCompletedRemoteData } from '../shared/operators';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { getDSORoute } from '../../app-routing-paths';
|
||||
|
||||
const ID_ENDPOINT = 'pid';
|
||||
const UUID_ENDPOINT = 'dso';
|
||||
|
||||
class DsoByIdOrUUIDService extends IdentifiableDataService<DSpaceObject> {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
) {
|
||||
super(
|
||||
undefined, requestService, rdbService, objectCache, halService, undefined,
|
||||
// interpolate id/uuid as query parameter
|
||||
(endpoint: string, resourceID: string): string => {
|
||||
return endpoint.replace(/{\?id}/, `?id=${resourceID}`)
|
||||
.replace(/{\?uuid}/, `?uuid=${resourceID}`);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default 'pid' endpoint for identifiers does not support uuid lookups.
|
||||
* For uuid lookups we need to change the linkPath.
|
||||
* @param identifierType
|
||||
*/
|
||||
setLinkPath(identifierType: IdentifierType) {
|
||||
if (identifierType === IdentifierType.UUID) {
|
||||
this.linkPath = UUID_ENDPOINT;
|
||||
} else {
|
||||
this.linkPath = ID_ENDPOINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DsoRedirectService {
|
||||
private dataService: DsoByIdOrUUIDService;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.dataService = new DsoByIdOrUUIDService(requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
findByIdAndIDType(id: string, identifierType = IdentifierType.UUID): Observable<RemoteData<DSpaceObject>> {
|
||||
this.dataService.setLinkPath(identifierType);
|
||||
return this.dataService.findById(id).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
tap((response) => {
|
||||
if (response.hasSucceeded) {
|
||||
const dso = response.payload;
|
||||
if (hasValue(dso.uuid)) {
|
||||
let newRoute = getDSORoute(dso);
|
||||
if (hasValue(newRoute)) {
|
||||
this.router.navigate([newRoute]);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@@ -7,8 +7,6 @@ import { GetRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { DSpaceObjectDataService } from './dspace-object-data.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
describe('DSpaceObjectDataService', () => {
|
||||
let scheduler: TestScheduler;
|
||||
@@ -42,18 +40,12 @@ describe('DSpaceObjectDataService', () => {
|
||||
})
|
||||
});
|
||||
objectCache = {} as ObjectCacheService;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
|
||||
service = new DSpaceObjectDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator
|
||||
);
|
||||
});
|
||||
|
||||
|
@@ -1,106 +1,28 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
import { DSPACE_OBJECT } from '../shared/dspace-object.resource-type';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RequestService } from './request.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
|
||||
class DataServiceImpl extends DataService<DSpaceObject> {
|
||||
protected linkPath = 'dso';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<DSpaceObject>) {
|
||||
super();
|
||||
}
|
||||
|
||||
getIDHref(endpoint, resourceID, ...linksToFollow: FollowLinkConfig<DSpaceObject>[]): string {
|
||||
return this.buildHrefFromFindOptions( endpoint.replace(/\{\?uuid\}/, `?uuid=${resourceID}`),
|
||||
{}, [], ...linksToFollow);
|
||||
}
|
||||
}
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
@Injectable()
|
||||
@dataService(DSPACE_OBJECT)
|
||||
export class DSpaceObjectDataService {
|
||||
protected linkPath = 'dso';
|
||||
private dataService: DataServiceImpl;
|
||||
|
||||
export class DSpaceObjectDataService extends IdentifiableDataService<DSpaceObject> {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<DSpaceObject>) {
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
|
||||
) {
|
||||
super(
|
||||
'dso', requestService, rdbService, objectCache, halService, undefined,
|
||||
// interpolate uuid as query parameter
|
||||
(endpoint: string, resourceID: string): string => {
|
||||
return endpoint.replace(/{\?uuid}/, `?uuid=${resourceID}`);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable of {@link RemoteData} of an object, based on its ID, with a list of {@link FollowLinkConfig},
|
||||
* to automatically resolve {@link HALLink}s of the object
|
||||
* @param id ID of object we want to retrieve
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findById(id: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<DSpaceObject>[]): Observable<RemoteData<DSpaceObject>> {
|
||||
return this.dataService.findById(id, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns an observable of {@link RemoteData} of an object, based on an href, with a list of {@link FollowLinkConfig},
|
||||
* to automatically resolve {@link HALLink}s of the object
|
||||
* @param href The url of object we want to retrieve
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findByHref(href: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<DSpaceObject>[]): Observable<RemoteData<DSpaceObject>> {
|
||||
return this.dataService.findByHref(href, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list of {@link FollowLinkConfig},
|
||||
* to automatically resolve {@link HALLink}s of the object
|
||||
* @param href The url of object we want to retrieve
|
||||
* @param findListOptions Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findAllByHref(href: string, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<DSpaceObject>[]): Observable<RemoteData<PaginatedList<DSpaceObject>>> {
|
||||
return this.dataService.findAllByHref(href, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,13 +1,8 @@
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { DataService } from './data.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, map, switchMap, take } from 'rxjs/operators';
|
||||
@@ -17,27 +12,30 @@ import { PaginatedList } from './paginated-list.model';
|
||||
import { ItemType } from '../shared/item-relationships/item-type.model';
|
||||
import { getFirstSucceededRemoteData, getRemoteDataPayload } from '../shared/operators';
|
||||
import { RelationshipTypeService } from './relationship-type.service';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
import { FindAllData, FindAllDataImpl } from './base/find-all-data';
|
||||
|
||||
/**
|
||||
* Service handling all ItemType requests
|
||||
*/
|
||||
@Injectable()
|
||||
export class EntityTypeService extends DataService<ItemType> {
|
||||
export class EntityTypeService extends BaseDataService<ItemType> implements FindAllData<ItemType>, SearchData<ItemType> {
|
||||
private findAllData: FindAllData<ItemType>;
|
||||
private searchData: SearchDataImpl<ItemType>;
|
||||
|
||||
protected linkPath = 'entitytypes';
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected relationshipTypeService: RelationshipTypeService,
|
||||
) {
|
||||
super('entitytypes', requestService, rdbService, objectCache, halService);
|
||||
|
||||
constructor(protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected relationshipTypeService: RelationshipTypeService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<ItemType>) {
|
||||
super();
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
getBrowseEndpoint(options, linkPath?: string): Observable<string> {
|
||||
@@ -158,7 +156,43 @@ export class EntityTypeService extends DataService<ItemType> {
|
||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||
take(1),
|
||||
switchMap((endPoint: string) =>
|
||||
this.findByHref(endPoint + '/label/' + label))
|
||||
this.findByHref(endPoint + '/label/' + label)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<ItemType>[]): Observable<RemoteData<PaginatedList<ItemType>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<ItemType>[]): Observable<RemoteData<PaginatedList<ItemType>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -13,11 +13,9 @@ import { RegistrationResponseParsingService } from './registration-response-pars
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
|
||||
@Injectable(
|
||||
{
|
||||
providedIn: 'root',
|
||||
}
|
||||
)
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
/**
|
||||
* Service that will register a new email address and request a token
|
||||
*/
|
||||
|
@@ -48,9 +48,9 @@ describe('ExternalSourceService', () => {
|
||||
buildList: createSuccessfulRemoteDataObject$(createPaginatedList(entries))
|
||||
});
|
||||
halService = jasmine.createSpyObj('halService', {
|
||||
getEndpoint: observableOf('external-sources-REST-endpoint')
|
||||
getEndpoint: observableOf('external-sources-REST-endpoint'),
|
||||
});
|
||||
service = new ExternalSourceService(requestService, rdbService, undefined, undefined, halService, undefined, undefined, undefined);
|
||||
service = new ExternalSourceService(requestService, rdbService, undefined, halService);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -1,13 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DataService } from './data.service';
|
||||
import { ExternalSource } from '../shared/external-source.model';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
@@ -15,28 +11,27 @@ import { hasValue, isNotEmptyOperator } from '../../shared/empty.util';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { ExternalSourceEntry } from '../shared/external-source-entry.model';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
|
||||
/**
|
||||
* A service handling all external source requests
|
||||
*/
|
||||
@Injectable()
|
||||
export class ExternalSourceService extends DataService<ExternalSource> {
|
||||
protected linkPath = 'externalsources';
|
||||
export class ExternalSourceService extends IdentifiableDataService<ExternalSource> implements SearchData<ExternalSource> {
|
||||
private searchData: SearchData<ExternalSource>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<ExternalSource>) {
|
||||
super();
|
||||
) {
|
||||
super('externalsources', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,10 +70,28 @@ export class ExternalSourceService extends DataService<ExternalSource> {
|
||||
isNotEmptyOperator(),
|
||||
distinctUntilChanged(),
|
||||
map((endpoint: string) => hasValue(searchOptions) ? searchOptions.toRestUrl(endpoint) : endpoint),
|
||||
take(1)
|
||||
take(1),
|
||||
);
|
||||
|
||||
// TODO create a dedicated ExternalSourceEntryDataService and move this entire method to it. Then the "as any"s won't be necessary
|
||||
return this.findAllByHref(href$, undefined, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow as any) as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
public searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<ExternalSource>[]): Observable<RemoteData<PaginatedList<ExternalSource>>> {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { AuthorizationDataService } from './authorization-data.service';
|
||||
import { SiteDataService } from '../site-data.service';
|
||||
import { AuthService } from '../../auth/auth.service';
|
||||
import { Site } from '../../shared/site.model';
|
||||
import { EPerson } from '../../eperson/models/eperson.model';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
@@ -16,7 +15,6 @@ import { FindListOptions } from '../find-list-options.model';
|
||||
describe('AuthorizationDataService', () => {
|
||||
let service: AuthorizationDataService;
|
||||
let siteService: SiteDataService;
|
||||
let authService: AuthService;
|
||||
|
||||
let site: Site;
|
||||
let ePerson: EPerson;
|
||||
@@ -37,13 +35,9 @@ describe('AuthorizationDataService', () => {
|
||||
uuid: 'test-eperson'
|
||||
});
|
||||
siteService = jasmine.createSpyObj('siteService', {
|
||||
find: observableOf(site)
|
||||
find: observableOf(site),
|
||||
});
|
||||
authService = {
|
||||
isAuthenticated: () => observableOf(true),
|
||||
getAuthenticatedUserFromStore: () => observableOf(ePerson)
|
||||
} as AuthService;
|
||||
service = new AuthorizationDataService(requestService, undefined, undefined, undefined, undefined, undefined, undefined, undefined, authService, siteService);
|
||||
service = new AuthorizationDataService(requestService, undefined, undefined, undefined, siteService);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -2,17 +2,11 @@ import { Observable, of as observableOf } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AUTHORIZATION } from '../../shared/authorization.resource-type';
|
||||
import { dataService } from '../../cache/builders/build-decorators';
|
||||
import { DataService } from '../data.service';
|
||||
import { Authorization } from '../../shared/authorization.model';
|
||||
import { RequestService } from '../request.service';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DSOChangeAnalyzer } from '../dso-change-analyzer.service';
|
||||
import { AuthService } from '../../auth/auth.service';
|
||||
import { SiteDataService } from '../site-data.service';
|
||||
import { followLink, FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { RemoteData } from '../remote-data';
|
||||
@@ -24,31 +18,31 @@ import { AuthorizationSearchParams } from './authorization-search-params';
|
||||
import { addSiteObjectUrlIfEmpty, oneAuthorizationMatchesFeature } from './authorization-utils';
|
||||
import { FeatureID } from './feature-id';
|
||||
import { getFirstCompletedRemoteData } from '../../shared/operators';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { FindListOptions } from '../find-list-options.model';
|
||||
import { BaseDataService } from '../base/base-data.service';
|
||||
import { SearchData, SearchDataImpl } from '../base/search-data';
|
||||
|
||||
/**
|
||||
* A service to retrieve {@link Authorization}s from the REST API
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(AUTHORIZATION)
|
||||
export class AuthorizationDataService extends DataService<Authorization> {
|
||||
export class AuthorizationDataService extends BaseDataService<Authorization> implements SearchData<Authorization> {
|
||||
protected linkPath = 'authorizations';
|
||||
protected searchByObjectPath = 'object';
|
||||
|
||||
private searchData: SearchDataImpl<Authorization>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Authorization>,
|
||||
protected authService: AuthService,
|
||||
protected siteService: SiteDataService
|
||||
protected siteService: SiteDataService,
|
||||
) {
|
||||
super();
|
||||
super('authorizations', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +124,25 @@ export class AuthorizationDataService extends DataService<Authorization> {
|
||||
params.push(new RequestParam('eperson', ePersonUuid));
|
||||
}
|
||||
return Object.assign(new FindListOptions(), options, {
|
||||
searchParams: [...params]
|
||||
searchParams: [...params],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Authorization>[]): Observable<RemoteData<PaginatedList<Authorization>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -1,36 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FEATURE } from '../../shared/feature.resource-type';
|
||||
import { dataService } from '../../cache/builders/build-decorators';
|
||||
import { DataService } from '../data.service';
|
||||
import { Feature } from '../../shared/feature.model';
|
||||
import { RequestService } from '../request.service';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DSOChangeAnalyzer } from '../dso-change-analyzer.service';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { BaseDataService } from '../base/base-data.service';
|
||||
|
||||
/**
|
||||
* A service to retrieve {@link Feature}s from the REST API
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(FEATURE)
|
||||
export class FeatureDataService extends DataService<Feature> {
|
||||
export class FeatureDataService extends BaseDataService<Feature> {
|
||||
protected linkPath = 'features';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Feature>
|
||||
) {
|
||||
super();
|
||||
super('features', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { HrefOnlyDataService } from './href-only-data.service';
|
||||
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { DataService } from './data.service';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
|
||||
describe(`HrefOnlyDataService`, () => {
|
||||
let service: HrefOnlyDataService;
|
||||
@@ -15,12 +15,12 @@ describe(`HrefOnlyDataService`, () => {
|
||||
href = 'https://rest.api/server/api/core/items/de7fa215-4a25-43a7-a4d7-17534a09fdfc';
|
||||
followLinks = [ followLink('link1'), followLink('link2') ];
|
||||
findListOptions = new FindListOptions();
|
||||
service = new HrefOnlyDataService(null, null, null, null, null, null, null, null);
|
||||
service = new HrefOnlyDataService(null, null, null, null);
|
||||
});
|
||||
|
||||
it(`should instantiate a private DataService`, () => {
|
||||
expect((service as any).dataService).toBeDefined();
|
||||
expect((service as any).dataService).toBeInstanceOf(DataService);
|
||||
expect((service as any).dataService).toBeInstanceOf(BaseDataService);
|
||||
});
|
||||
|
||||
describe(`findByHref`, () => {
|
||||
@@ -28,7 +28,7 @@ describe(`HrefOnlyDataService`, () => {
|
||||
spy = spyOn((service as any).dataService, 'findByHref').and.returnValue(createSuccessfulRemoteDataObject$(null));
|
||||
});
|
||||
|
||||
it(`should delegate to findByHref on the internal DataService`, () => {
|
||||
it(`should forward to findByHref on the internal DataService`, () => {
|
||||
service.findByHref(href, false, false, ...followLinks);
|
||||
expect(spy).toHaveBeenCalledWith(href, false, false, ...followLinks);
|
||||
});
|
||||
|
@@ -1,13 +1,7 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { DataService } from './data.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { VOCABULARY_ENTRY } from '../submission/vocabularies/models/vocabularies.resource-type';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
@@ -18,25 +12,8 @@ import { PaginatedList } from './paginated-list.model';
|
||||
import { ITEM_TYPE } from '../shared/item-relationships/item-type.resource-type';
|
||||
import { LICENSE } from '../shared/license.resource-type';
|
||||
import { CacheableObject } from '../cache/cacheable-object.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
|
||||
class DataServiceImpl extends DataService<any> {
|
||||
// linkPath isn't used if we're only searching by href.
|
||||
protected linkPath = undefined;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<any>) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
|
||||
/**
|
||||
* A DataService with only findByHref methods. Its purpose is to be used for resources that don't
|
||||
@@ -46,24 +23,25 @@ class DataServiceImpl extends DataService<any> {
|
||||
* an @dataService annotation can be added for any number of these resource types
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
@dataService(VOCABULARY_ENTRY)
|
||||
@dataService(ITEM_TYPE)
|
||||
@dataService(LICENSE)
|
||||
export class HrefOnlyDataService {
|
||||
private dataService: DataServiceImpl;
|
||||
/**
|
||||
* Not all BaseDataService methods should be exposed, so
|
||||
* @private
|
||||
*/
|
||||
private dataService: BaseDataService<any>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<any>) {
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, store, objectCache, halService, notificationsService, http, comparator);
|
||||
) {
|
||||
this.dataService = new BaseDataService(undefined, requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -21,7 +21,7 @@ import { HALEndpointServiceStub } from 'src/app/shared/testing/hal-endpoint-serv
|
||||
describe('ItemDataService', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: ItemDataService;
|
||||
let bs: BrowseService;
|
||||
let browseService: BrowseService;
|
||||
const requestService = Object.assign(getMockRequestService(), {
|
||||
generateRequestId(): string {
|
||||
return scopeID;
|
||||
@@ -78,14 +78,12 @@ describe('ItemDataService', () => {
|
||||
return new ItemDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
bs,
|
||||
objectCache,
|
||||
halEndpointService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator,
|
||||
bundleService
|
||||
browseService,
|
||||
bundleService,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,7 +93,7 @@ describe('ItemDataService', () => {
|
||||
});
|
||||
|
||||
it('should return the endpoint to fetch Items within the given scope and starting with the given string', () => {
|
||||
bs = initMockBrowseService(true);
|
||||
browseService = initMockBrowseService(true);
|
||||
service = initTestService();
|
||||
|
||||
const result = service.getBrowseEndpoint(options);
|
||||
@@ -106,7 +104,7 @@ describe('ItemDataService', () => {
|
||||
|
||||
describe('if the dc.date.issue browse isn\'t configured for items', () => {
|
||||
beforeEach(() => {
|
||||
bs = initMockBrowseService(false);
|
||||
browseService = initMockBrowseService(false);
|
||||
service = initTestService();
|
||||
});
|
||||
it('should throw an error', () => {
|
||||
|
@@ -1,6 +1,13 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { distinctUntilChanged, filter, find, map, switchMap, take } from 'rxjs/operators';
|
||||
import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
||||
@@ -16,12 +23,10 @@ import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { ITEM } from '../shared/item.resource-type';
|
||||
import { URLCombiner } from '../url-combiner/url-combiner';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { DeleteRequest, GetRequest, PostRequest, PutRequest} from './request.models';
|
||||
import { DeleteRequest, GetRequest, PostRequest, PutRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
import { Bundle } from '../shared/bundle.model';
|
||||
@@ -34,27 +39,41 @@ import { ResponseParsingService } from './parsing.service';
|
||||
import { StatusCodeOnlyResponseParsingService } from './status-code-only-response-parsing.service';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { RestRequest } from './rest-request.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { ConstructIdEndpoint, IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { PatchData, PatchDataImpl } from './base/patch-data';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { CreateData, CreateDataImpl } from './base/create-data';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(ITEM)
|
||||
export class ItemDataService extends DataService<Item> {
|
||||
protected linkPath = 'items';
|
||||
/**
|
||||
* An abstract service for CRUD operations on Items
|
||||
* Doesn't specify an endpoint because multiple endpoints support Item-like functionality (e.g. items, itemtemplates)
|
||||
* Extend this class to implement data services for Items
|
||||
*/
|
||||
export abstract class BaseItemDataService extends IdentifiableDataService<Item> implements CreateData<Item>, PatchData<Item>, DeleteData<Item> {
|
||||
private createData: CreateData<Item>;
|
||||
private patchData: PatchData<Item>;
|
||||
private deleteData: DeleteData<Item>;
|
||||
|
||||
constructor(
|
||||
protected constructor(
|
||||
protected linkPath,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected bs: BrowseService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Item>,
|
||||
protected bundleService: BundleDataService
|
||||
protected browseService: BrowseService,
|
||||
protected bundleService: BundleDataService,
|
||||
protected constructIdEndpoint: ConstructIdEndpoint = (endpoint, resourceID) => `${endpoint}/${resourceID}`,
|
||||
) {
|
||||
super();
|
||||
super(linkPath, requestService, rdbService, objectCache, halService, undefined, constructIdEndpoint);
|
||||
|
||||
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||
this.patchData = new PatchDataImpl<Item>(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,10 +88,11 @@ export class ItemDataService extends DataService<Item> {
|
||||
if (options.sort && options.sort.field) {
|
||||
field = options.sort.field;
|
||||
}
|
||||
return this.bs.getBrowseURLFor(field, linkPath).pipe(
|
||||
return this.browseService.getBrowseURLFor(field, linkPath).pipe(
|
||||
filter((href: string) => isNotEmpty(href)),
|
||||
map((href: string) => new URLCombiner(href, `?scope=${options.scopeID}`).toString()),
|
||||
distinctUntilChanged(),);
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +104,7 @@ export class ItemDataService extends DataService<Item> {
|
||||
public getMappedCollectionsEndpoint(itemId: string, collectionId?: string): Observable<string> {
|
||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||
map((endpoint: string) => this.getIDHref(endpoint, itemId)),
|
||||
map((endpoint: string) => `${endpoint}/mappedCollections${collectionId ? `/${collectionId}` : ''}`)
|
||||
map((endpoint: string) => `${endpoint}/mappedCollections${collectionId ? `/${collectionId}` : ''}`),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -219,7 +239,7 @@ export class ItemDataService extends DataService<Item> {
|
||||
public getMoveItemEndpoint(itemId: string): Observable<string> {
|
||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||
map((endpoint: string) => this.getIDHref(endpoint, itemId)),
|
||||
map((endpoint: string) => `${endpoint}/owningCollection`)
|
||||
map((endpoint: string) => `${endpoint}/owningCollection`),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -299,4 +319,85 @@ export class ItemDataService extends DataService<Item> {
|
||||
this.requestService.setStaleByHrefSubstring('item/' + itemUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
* @param method The RestRequestMethod for which de server sync buffer should be committed
|
||||
*/
|
||||
public commitUpdates(method?: RestRequestMethod): void {
|
||||
this.patchData.commitUpdates(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a patch request for a specified object
|
||||
* @param {T} object The object to send a patch request for
|
||||
* @param {Operation[]} operations The patch operations to be performed
|
||||
*/
|
||||
public patch(object: Item, operations: Operation[]): Observable<RemoteData<Item>> {
|
||||
return this.patchData.patch(object, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
* @param {DSpaceObject} object The given object
|
||||
*/
|
||||
public update(object: Item): Observable<RemoteData<Item>> {
|
||||
return this.patchData.update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new object on the server, and store the response in the object cache
|
||||
*
|
||||
* @param object The object to create
|
||||
* @param params Array with additional params to combine with query string
|
||||
*/
|
||||
public create(object: Item, ...params: RequestParam[]): Observable<RemoteData<Item>> {
|
||||
return this.createData.create(object, ...params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A service for CRUD operations on Items
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(ITEM)
|
||||
export class ItemDataService extends BaseItemDataService {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected comparator: DSOChangeAnalyzer<Item>,
|
||||
protected browseService: BrowseService,
|
||||
protected bundleService: BundleDataService,
|
||||
) {
|
||||
super('items', requestService, rdbService, objectCache, halService, notificationsService, comparator, browseService, bundleService);
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ describe('ItemRequestDataService', () => {
|
||||
getEndpoint: observableOf(restApiEndpoint),
|
||||
});
|
||||
|
||||
service = new ItemRequestDataService(requestService, rdbService, null, null, halService, null, null, null);
|
||||
service = new ItemRequestDataService(requestService, rdbService, null, halService);
|
||||
});
|
||||
|
||||
describe('requestACopy', () => {
|
||||
|
@@ -9,40 +9,27 @@ import { PostRequest, PutRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { ItemRequest } from '../shared/item-request.model';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { DataService } from './data.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { RequestCopyEmail } from '../../request-copy/email-request-copy/request-copy-email.model';
|
||||
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the itemrequests endpoint
|
||||
*/
|
||||
@Injectable(
|
||||
{
|
||||
providedIn: 'root',
|
||||
}
|
||||
)
|
||||
export class ItemRequestDataService extends DataService<ItemRequest> {
|
||||
|
||||
protected linkPath = 'itemrequests';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ItemRequestDataService extends IdentifiableDataService<ItemRequest> {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<ItemRequest>,
|
||||
) {
|
||||
super();
|
||||
super('itemrequests', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
getItemRequestEndpoint(): Observable<string> {
|
||||
@@ -124,9 +111,9 @@ export class ItemRequestDataService extends DataService<ItemRequest> {
|
||||
suggestOpenAccess,
|
||||
}), options);
|
||||
}),
|
||||
sendRequest(this.requestService)).subscribe();
|
||||
sendRequest(this.requestService),
|
||||
).subscribe();
|
||||
|
||||
return this.rdbService.buildFromRequestUUID(requestId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,17 +8,17 @@ import { BrowseService } from '../browse/browse.service';
|
||||
import { cold } from 'jasmine-marbles';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CollectionDataService } from './collection-data.service';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { RestRequest } from './rest-request.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { RequestEntry } from './request-entry.model';
|
||||
import createSpyObj = jasmine.createSpyObj;
|
||||
|
||||
describe('ItemTemplateDataService', () => {
|
||||
let service: ItemTemplateDataService;
|
||||
let itemService: any;
|
||||
let byCollection: any;
|
||||
|
||||
const item = new Item();
|
||||
const collectionEndpoint = 'https://rest.api/core/collections/4af28e99-6a9c-4036-a199-e1b587046d39';
|
||||
@@ -47,14 +47,14 @@ describe('ItemTemplateDataService', () => {
|
||||
} as RequestService;
|
||||
const rdbService = {} as RemoteDataBuildService;
|
||||
const store = {} as Store<CoreState>;
|
||||
const bs = {} as BrowseService;
|
||||
const browseService = {} as BrowseService;
|
||||
const objectCache = {
|
||||
getObjectBySelfLink(self) {
|
||||
return observableOf({});
|
||||
},
|
||||
addPatch(self, operations) {
|
||||
// Do nothing
|
||||
}
|
||||
},
|
||||
} as any;
|
||||
const halEndpointService = {
|
||||
getEndpoint(linkPath: string): Observable<string> {
|
||||
@@ -62,7 +62,6 @@ describe('ItemTemplateDataService', () => {
|
||||
}
|
||||
} as HALEndpointService;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {
|
||||
diff(first, second) {
|
||||
return [{}];
|
||||
@@ -78,60 +77,61 @@ describe('ItemTemplateDataService', () => {
|
||||
service = new ItemTemplateDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
bs,
|
||||
objectCache,
|
||||
halEndpointService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator,
|
||||
browseService,
|
||||
undefined,
|
||||
collectionService
|
||||
collectionService,
|
||||
);
|
||||
itemService = (service as any).dataService;
|
||||
byCollection = (service as any).byCollection;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
initTestService();
|
||||
});
|
||||
|
||||
describe('commitUpdates', () => {
|
||||
it('should call commitUpdates on the item service implementation', () => {
|
||||
spyOn(itemService, 'commitUpdates');
|
||||
service.commitUpdates();
|
||||
expect(itemService.commitUpdates).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
it('should call update on the item service implementation', () => {
|
||||
spyOn(itemService, 'update');
|
||||
service.update(item);
|
||||
expect(itemService.update).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('findByCollectionID', () => {
|
||||
it('should call findByCollectionID on the item service implementation', () => {
|
||||
spyOn(itemService, 'findByCollectionID');
|
||||
it('should call findByCollectionID on the collection-based data service', () => {
|
||||
spyOn(byCollection, 'findById');
|
||||
service.findByCollectionID(scopeID);
|
||||
expect(itemService.findByCollectionID).toHaveBeenCalled();
|
||||
expect(byCollection.findById).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('should call createTemplate on the item service implementation', () => {
|
||||
spyOn(itemService, 'createTemplate');
|
||||
service.create(item, scopeID);
|
||||
expect(itemService.createTemplate).toHaveBeenCalled();
|
||||
describe('createByCollectionID', () => {
|
||||
it('should call createTemplate on the collection-based data service', () => {
|
||||
spyOn(byCollection, 'createTemplate');
|
||||
service.createByCollectionID(item, scopeID);
|
||||
expect(byCollection.createTemplate).toHaveBeenCalledWith(item, scopeID);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteByCollectionID', () => {
|
||||
it('should call deleteByCollectionID on the item service implementation', () => {
|
||||
spyOn(itemService, 'deleteByCollectionID');
|
||||
service.deleteByCollectionID(item, scopeID);
|
||||
expect(itemService.deleteByCollectionID).toHaveBeenCalled();
|
||||
describe('byCollection', () => {
|
||||
beforeEach(() => {
|
||||
byCollection.createData = createSpyObj('createData', {
|
||||
createOnEndpoint: 'TEST createOnEndpoint',
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIDHrefObs', () => {
|
||||
it('should point to the Item template of a given Collection', () => {
|
||||
expect(byCollection.getIDHrefObs(scopeID)).toBeObservable(cold('a', { a: jasmine.stringMatching(`/collections/${scopeID}/itemtemplate`) }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('createTemplate', () => {
|
||||
it('should forward to CreateDataImpl.createOnEndpoint', () => {
|
||||
spyOn(byCollection, 'getIDHrefObs').and.returnValue('TEST getIDHrefObs');
|
||||
|
||||
const out = byCollection.createTemplate(item, scopeID);
|
||||
|
||||
expect(byCollection.getIDHrefObs).toHaveBeenCalledWith(scopeID);
|
||||
expect(byCollection.createData.createOnEndpoint).toHaveBeenCalledWith(item, 'TEST getIDHrefObs');
|
||||
expect(out).toBe('TEST createOnEndpoint');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,147 +1,62 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ItemDataService } from './item-data.service';
|
||||
import { UpdateDataService } from './update-data.service';
|
||||
import { BaseItemDataService } from './item-data.service';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { BrowseService } from '../browse/browse.service';
|
||||
import { CollectionDataService } from './collection-data.service';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { BundleDataService } from './bundle-data.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { Operation } from 'fast-json-patch';
|
||||
import { getFirstCompletedRemoteData } from '../shared/operators';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { CreateDataImpl } from './base/create-data';
|
||||
|
||||
/**
|
||||
* A custom implementation of the ItemDataService, but for collection item templates
|
||||
* Makes sure to change the endpoint before sending out CRUD requests for the item template
|
||||
* Data service for interacting with Item templates via their Collection
|
||||
*/
|
||||
class DataServiceImpl extends ItemDataService {
|
||||
protected collectionLinkPath = 'itemtemplate';
|
||||
protected linkPath = 'itemtemplates';
|
||||
|
||||
/**
|
||||
* Endpoint dynamically changing depending on what request we're sending
|
||||
*/
|
||||
private endpoint$: Observable<string>;
|
||||
|
||||
/**
|
||||
* Is the current endpoint based on a collection?
|
||||
*/
|
||||
private collectionEndpoint = false;
|
||||
class CollectionItemTemplateDataService extends IdentifiableDataService<Item> {
|
||||
private createData: CreateDataImpl<Item>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected bs: BrowseService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Item>,
|
||||
protected bundleService: BundleDataService,
|
||||
protected collectionService: CollectionDataService) {
|
||||
super(requestService, rdbService, store, bs, objectCache, halService, notificationsService, http, comparator, bundleService);
|
||||
protected collectionService: CollectionDataService,
|
||||
) {
|
||||
super('itemtemplates', requestService, rdbService, objectCache, halService, undefined);
|
||||
|
||||
// We only intend to use createOnEndpoint, so this inner data service feature doesn't need an endpoint at all
|
||||
this.createData = new CreateDataImpl<Item>(undefined, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the endpoint based on a collection
|
||||
* @param collectionID The ID of the collection to base the endpoint on
|
||||
* Create an observable for the HREF of a specific object based on its identifier
|
||||
*
|
||||
* Overridden to ensure that {@link findById} works with Collection IDs and points to the template.
|
||||
* @param collectionID the ID of a Collection
|
||||
*/
|
||||
public getCollectionEndpoint(collectionID: string): Observable<string> {
|
||||
public getIDHrefObs(collectionID: string): Observable<string> {
|
||||
return this.collectionService.getIDHrefObs(collectionID).pipe(
|
||||
switchMap((href: string) => this.halService.getEndpoint(this.collectionLinkPath, href))
|
||||
switchMap((href: string) => this.halService.getEndpoint('itemtemplate', href)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the endpoint to be based on a collection
|
||||
* @param collectionID The ID of the collection to base the endpoint on
|
||||
*/
|
||||
private setCollectionEndpoint(collectionID: string) {
|
||||
this.collectionEndpoint = true;
|
||||
this.endpoint$ = this.getCollectionEndpoint(collectionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the endpoint to the regular linkPath
|
||||
*/
|
||||
private setRegularEndpoint() {
|
||||
this.collectionEndpoint = false;
|
||||
this.endpoint$ = this.halService.getEndpoint(this.linkPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base endpoint for all requests
|
||||
* Uses the current collectionID to assemble a request endpoint for the collection's item template
|
||||
*/
|
||||
protected getEndpoint(): Observable<string> {
|
||||
return this.endpoint$;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current endpoint is based on a collection, simply return the collection's template endpoint, otherwise
|
||||
* create a regular template endpoint
|
||||
* @param resourceID
|
||||
*/
|
||||
getIDHrefObs(resourceID: string): Observable<string> {
|
||||
if (this.collectionEndpoint) {
|
||||
return this.getEndpoint();
|
||||
} else {
|
||||
return super.getIDHrefObs(resourceID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the collection ID and send a find by ID request
|
||||
* @param collectionID
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findByCollectionID(collectionID: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Item>[]): Observable<RemoteData<Item>> {
|
||||
this.setCollectionEndpoint(collectionID);
|
||||
return super.findById(collectionID, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the collection ID and send a create request
|
||||
* Create a new item template for a Collection by ID
|
||||
* @param item
|
||||
* @param collectionID
|
||||
*/
|
||||
createTemplate(item: Item, collectionID: string): Observable<RemoteData<Item>> {
|
||||
this.setCollectionEndpoint(collectionID);
|
||||
return super.create(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the collection ID and send a delete request
|
||||
* @param item
|
||||
* @param collectionID
|
||||
*/
|
||||
deleteByCollectionID(item: Item, collectionID: string): Observable<boolean> {
|
||||
this.setRegularEndpoint();
|
||||
return super.delete(item.uuid).pipe(
|
||||
getFirstCompletedRemoteData(),
|
||||
map((response: RemoteData<NoContent>) => hasValue(response) && response.hasSucceeded)
|
||||
);
|
||||
public createTemplate(item: Item, collectionID: string): Observable<RemoteData<Item>> {
|
||||
return this.createData.createOnEndpoint(item, this.getIDHrefObs(collectionID));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,43 +64,23 @@ class DataServiceImpl extends ItemDataService {
|
||||
* A service responsible for fetching/sending data from/to the REST API on a collection's itemtemplates endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
export class ItemTemplateDataService implements UpdateDataService<Item> {
|
||||
/**
|
||||
* The data service responsible for all CRUD actions on the item
|
||||
*/
|
||||
private dataService: DataServiceImpl;
|
||||
export class ItemTemplateDataService extends BaseItemDataService {
|
||||
private byCollection: CollectionItemTemplateDataService;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected bs: BrowseService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Item>,
|
||||
protected browseService: BrowseService,
|
||||
protected bundleService: BundleDataService,
|
||||
protected collectionService: CollectionDataService) {
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, store, bs, objectCache, halService, notificationsService, http, comparator, bundleService, collectionService);
|
||||
}
|
||||
protected collectionService: CollectionDataService,
|
||||
) {
|
||||
super('itemtemplates', requestService, rdbService, objectCache, halService, notificationsService, comparator, browseService, bundleService);
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
*/
|
||||
commitUpdates(method?: RestRequestMethod) {
|
||||
this.dataService.commitUpdates(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
*/
|
||||
update(object: Item): Observable<RemoteData<Item>> {
|
||||
return this.dataService.update(object);
|
||||
}
|
||||
|
||||
patch(dso: Item, operations: Operation[]): Observable<RemoteData<Item>> {
|
||||
return this.dataService.patch(dso, operations);
|
||||
this.byCollection = new CollectionItemTemplateDataService(requestService, rdbService, objectCache, halService, notificationsService, collectionService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,7 +94,7 @@ export class ItemTemplateDataService implements UpdateDataService<Item> {
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findByCollectionID(collectionID: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Item>[]): Observable<RemoteData<Item>> {
|
||||
return this.dataService.findByCollectionID(collectionID, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
return this.byCollection.findById(collectionID, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,17 +102,8 @@ export class ItemTemplateDataService implements UpdateDataService<Item> {
|
||||
* @param item
|
||||
* @param collectionID
|
||||
*/
|
||||
create(item: Item, collectionID: string): Observable<RemoteData<Item>> {
|
||||
return this.dataService.createTemplate(item, collectionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a template item by collection ID
|
||||
* @param item
|
||||
* @param collectionID
|
||||
*/
|
||||
deleteByCollectionID(item: Item, collectionID: string): Observable<boolean> {
|
||||
return this.dataService.deleteByCollectionID(item, collectionID);
|
||||
createByCollectionID(item: Item, collectionID: string): Observable<RemoteData<Item>> {
|
||||
return this.byCollection.createTemplate(item, collectionID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,6 +111,6 @@ export class ItemTemplateDataService implements UpdateDataService<Item> {
|
||||
* @param collectionID The ID of the collection to base the endpoint on
|
||||
*/
|
||||
getCollectionEndpoint(collectionID: string): Observable<string> {
|
||||
return this.dataService.getCollectionEndpoint(collectionID);
|
||||
return this.byCollection.getIDHrefObs(collectionID);
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ import { RemoteDataBuildService } from '../cache/builders/remote-data-build.serv
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
|
||||
describe('MetadataFieldDataService', () => {
|
||||
let metadataFieldService: MetadataFieldDataService;
|
||||
@@ -33,16 +34,19 @@ describe('MetadataFieldDataService', () => {
|
||||
generateRequestId: '34cfed7c-f597-49ef-9cbe-ea351f0023c2',
|
||||
send: {},
|
||||
getByUUID: observableOf({ response: new RestResponse(true, 200, 'OK') }),
|
||||
setStaleByHrefSubstring: {}
|
||||
setStaleByHrefSubstring: {},
|
||||
});
|
||||
halService = Object.assign(new HALEndpointServiceStub(endpoint));
|
||||
notificationsService = jasmine.createSpyObj('notificationsService', {
|
||||
error: {}
|
||||
error: {},
|
||||
});
|
||||
rdbService = jasmine.createSpyObj('rdbService', {
|
||||
buildSingle: createSuccessfulRemoteDataObject$(undefined)
|
||||
buildSingle: createSuccessfulRemoteDataObject$(undefined),
|
||||
buildList: createSuccessfulRemoteDataObject$(createPaginatedList([])),
|
||||
});
|
||||
metadataFieldService = new MetadataFieldDataService(requestService, rdbService, undefined, halService, undefined, undefined, undefined, notificationsService);
|
||||
metadataFieldService = new MetadataFieldDataService(
|
||||
requestService, rdbService, undefined, halService, notificationsService,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -1,17 +1,11 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { DataService } from './data.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { METADATA_FIELD } from '../metadata/metadata-field.resource-type';
|
||||
import { MetadataField } from '../metadata/metadata-field.model';
|
||||
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
||||
@@ -19,29 +13,43 @@ import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { RequestParam } from '../cache/models/request-param.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
import { PutData, PutDataImpl } from './base/put-data';
|
||||
import { CreateData, CreateDataImpl } from './base/create-data';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the metadatafields endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(METADATA_FIELD)
|
||||
export class MetadataFieldDataService extends DataService<MetadataField> {
|
||||
protected linkPath = 'metadatafields';
|
||||
export class MetadataFieldDataService extends IdentifiableDataService<MetadataField> implements CreateData<MetadataField>, PutData<MetadataField>, DeleteData<MetadataField>, SearchData<MetadataField> {
|
||||
private createData: CreateData<MetadataField>;
|
||||
private searchData: SearchData<MetadataField>;
|
||||
private putData: PutData<MetadataField>;
|
||||
private deleteData: DeleteData<MetadataField>;
|
||||
|
||||
protected searchBySchemaLinkPath = 'bySchema';
|
||||
protected searchByFieldNameLinkPath = 'byFieldName';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected comparator: DefaultChangeAnalyzer<MetadataField>,
|
||||
protected http: HttpClient,
|
||||
protected notificationsService: NotificationsService) {
|
||||
super();
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
) {
|
||||
super('metadatafields', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.putData = new PutDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +65,7 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
|
||||
*/
|
||||
findBySchema(schema: MetadataSchema, options: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<MetadataField>[]) {
|
||||
const optionsWithSchema = Object.assign(new FindListOptions(), options, {
|
||||
searchParams: [new RequestParam('schema', schema.prefix)]
|
||||
searchParams: [new RequestParam('schema', schema.prefix)],
|
||||
});
|
||||
return this.searchBy(this.searchBySchemaLinkPath, optionsWithSchema, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
@@ -85,8 +93,8 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
|
||||
new RequestParam('element', hasValue(element) ? element : ''),
|
||||
new RequestParam('qualifier', hasValue(qualifier) ? qualifier : ''),
|
||||
new RequestParam('query', hasValue(query) ? query : ''),
|
||||
new RequestParam('exactName', hasValue(exactName) ? exactName : '')
|
||||
]
|
||||
new RequestParam('exactName', hasValue(exactName) ? exactName : ''),
|
||||
],
|
||||
});
|
||||
return this.searchBy(this.searchByFieldNameLinkPath, optionParams, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
@@ -112,4 +120,80 @@ export class MetadataFieldDataService extends DataService<MetadataField> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a PUT request for the specified object
|
||||
*
|
||||
* @param object The object to send a put request for.
|
||||
*/
|
||||
put(object: MetadataField): Observable<RemoteData<MetadataField>> {
|
||||
return this.putData.put(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new object on the server, and store the response in the object cache
|
||||
*
|
||||
* @param object The object to create
|
||||
* @param params Array with additional params to combine with query string
|
||||
*/
|
||||
create(object: MetadataField, ...params: RequestParam[]): Observable<RemoteData<MetadataField>> {
|
||||
return this.createData.create(object, ...params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HREF for a specific object's search method with given options object
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @return {Observable<string>}
|
||||
* Return an observable that emits created HREF
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
public getSearchByHref(searchMethod: string, options?: FindListOptions, ...linksToFollow: FollowLinkConfig<MetadataField>[]): Observable<string> {
|
||||
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
public searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<MetadataField>[]): Observable<RemoteData<PaginatedList<MetadataField>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,14 +24,20 @@ describe('MetadataSchemaDataService', () => {
|
||||
generateRequestId: '34cfed7c-f597-49ef-9cbe-ea351f0023c2',
|
||||
send: {},
|
||||
getByUUID: observableOf({ response: new RestResponse(true, 200, 'OK') }),
|
||||
removeByHrefSubstring: {}
|
||||
removeByHrefSubstring: {},
|
||||
});
|
||||
halService = Object.assign(new HALEndpointServiceStub(endpoint));
|
||||
notificationsService = jasmine.createSpyObj('notificationsService', {
|
||||
error: {}
|
||||
error: {},
|
||||
});
|
||||
rdbService = getMockRemoteDataBuildService();
|
||||
metadataSchemaService = new MetadataSchemaDataService(requestService, rdbService, undefined, halService, undefined, undefined, undefined, notificationsService);
|
||||
metadataSchemaService = new MetadataSchemaDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
null,
|
||||
halService,
|
||||
notificationsService,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -1,6 +1,4 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
@@ -8,33 +6,45 @@ import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { MetadataSchema } from '../metadata/metadata-schema.model';
|
||||
import { METADATA_SCHEMA } from '../metadata/metadata-schema.resource-type';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { PutData, PutDataImpl } from './base/put-data';
|
||||
import { CreateData, CreateDataImpl } from './base/create-data';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
import { FindAllData, FindAllDataImpl } from './base/find-all-data';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { DeleteData, DeleteDataImpl } from './base/delete-data';
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the metadataschemas endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(METADATA_SCHEMA)
|
||||
export class MetadataSchemaDataService extends DataService<MetadataSchema> {
|
||||
protected linkPath = 'metadataschemas';
|
||||
export class MetadataSchemaDataService extends IdentifiableDataService<MetadataSchema> implements FindAllData<MetadataSchema>, DeleteData<MetadataSchema> {
|
||||
private createData: CreateData<MetadataSchema>;
|
||||
private findAllData: FindAllData<MetadataSchema>;
|
||||
private putData: PutData<MetadataSchema>;
|
||||
private deleteData: DeleteData<MetadataSchema>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected comparator: DefaultChangeAnalyzer<MetadataSchema>,
|
||||
protected http: HttpClient,
|
||||
protected notificationsService: NotificationsService) {
|
||||
super();
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
) {
|
||||
super('metadataschemas', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.createData = new CreateDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive);
|
||||
this.putData = new PutDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.deleteData = new DeleteDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, notificationsService, this.responseMsToLive, this.constructIdEndpoint);
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,9 +59,9 @@ export class MetadataSchemaDataService extends DataService<MetadataSchema> {
|
||||
const isUpdate = hasValue(schema.id);
|
||||
|
||||
if (isUpdate) {
|
||||
return this.put(schema);
|
||||
return this.putData.put(schema);
|
||||
} else {
|
||||
return this.create(schema);
|
||||
return this.createData.create(schema);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +71,50 @@ export class MetadataSchemaDataService extends DataService<MetadataSchema> {
|
||||
*/
|
||||
clearRequests(): Observable<string> {
|
||||
return this.getBrowseEndpoint().pipe(
|
||||
tap((href: string) => this.requestService.removeByHrefSubstring(href))
|
||||
tap((href: string) => this.requestService.removeByHrefSubstring(href)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<MetadataSchema>[]): Observable<RemoteData<PaginatedList<MetadataSchema>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param objectId The id of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
*/
|
||||
public delete(objectId: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.delete(objectId, copyVirtualMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an existing object on the server
|
||||
* @param href The self link of the object to be removed
|
||||
* @param copyVirtualMetadata (optional parameter) the identifiers of the relationship types for which the virtual
|
||||
* metadata should be saved as real metadata
|
||||
* @return A RemoteData observable with an empty payload, but still representing the state of the request: statusCode,
|
||||
* errorMessage, timeCompleted, etc
|
||||
* Only emits once all request related to the DSO has been invalidated.
|
||||
*/
|
||||
public deleteByHref(href: string, copyVirtualMetadata?: string[]): Observable<RemoteData<NoContent>> {
|
||||
return this.deleteData.deleteByHref(href, copyVirtualMetadata);
|
||||
}
|
||||
}
|
||||
|
28
src/app/core/data/persistent-identifier-data.service.ts
Normal file
28
src/app/core/data/persistent-identifier-data.service.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { DSpaceObject } from '../shared/dspace-object.model';
|
||||
|
||||
export class PersistentIdentifierDataService extends IdentifiableDataService<DSpaceObject> {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
) {
|
||||
super('pid', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
}
|
@@ -1,13 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DataService } from '../data.service';
|
||||
import { RequestService } from '../request.service';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from '../default-change-analyzer.service';
|
||||
import { Process } from '../../../process-page/processes/process.model';
|
||||
import { dataService } from '../../cache/builders/build-decorators';
|
||||
import { PROCESS } from '../../../process-page/processes/process.resource-type';
|
||||
@@ -17,24 +12,26 @@ import { PaginatedList } from '../paginated-list.model';
|
||||
import { Bitstream } from '../../shared/bitstream.model';
|
||||
import { RemoteData } from '../remote-data';
|
||||
import { BitstreamDataService } from '../bitstream-data.service';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { IdentifiableDataService } from '../base/identifiable-data.service';
|
||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { FindAllData, FindAllDataImpl } from '../base/find-all-data';
|
||||
import { FindListOptions } from '../find-list-options.model';
|
||||
|
||||
@Injectable()
|
||||
@dataService(PROCESS)
|
||||
export class ProcessDataService extends DataService<Process> {
|
||||
protected linkPath = 'processes';
|
||||
export class ProcessDataService extends IdentifiableDataService<Process> implements FindAllData<Process> {
|
||||
private findAllData: FindAllData<Process>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected bitstreamDataService: BitstreamDataService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Process>) {
|
||||
super();
|
||||
) {
|
||||
super('processes', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,4 +52,22 @@ export class ProcessDataService extends DataService<Process> {
|
||||
const href$ = this.getFilesEndpoint(processId);
|
||||
return this.bitstreamDataService.findAllByHref(href$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Process>[]): Observable<RemoteData<PaginatedList<Process>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,13 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DataService } from '../data.service';
|
||||
import { RemoteDataBuildService } from '../../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from '../default-change-analyzer.service';
|
||||
import { Script } from '../../../process-page/scripts/script.model';
|
||||
import { ProcessParameter } from '../../../process-page/processes/process-parameter.model';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { URLCombiner } from '../../url-combiner/url-combiner';
|
||||
import { RemoteData } from '../remote-data';
|
||||
import { MultipartPostRequest} from '../request.models';
|
||||
import { MultipartPostRequest } from '../request.models';
|
||||
import { RequestService } from '../request.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { dataService } from '../../cache/builders/build-decorators';
|
||||
@@ -21,26 +16,29 @@ import { Process } from '../../../process-page/processes/process.model';
|
||||
import { hasValue } from '../../../shared/empty.util';
|
||||
import { getFirstCompletedRemoteData } from '../../shared/operators';
|
||||
import { RestRequest } from '../rest-request.model';
|
||||
import { CoreState } from '../../core-state.model';
|
||||
import { IdentifiableDataService } from '../base/identifiable-data.service';
|
||||
import { FindAllData, FindAllDataImpl } from '../base/find-all-data';
|
||||
import { FindListOptions } from '../find-list-options.model';
|
||||
import { FollowLinkConfig } from '../../../shared/utils/follow-link-config.model';
|
||||
import { PaginatedList } from '../paginated-list.model';
|
||||
|
||||
export const METADATA_IMPORT_SCRIPT_NAME = 'metadata-import';
|
||||
export const METADATA_EXPORT_SCRIPT_NAME = 'metadata-export';
|
||||
|
||||
@Injectable()
|
||||
@dataService(SCRIPT)
|
||||
export class ScriptDataService extends DataService<Script> {
|
||||
protected linkPath = 'scripts';
|
||||
export class ScriptDataService extends IdentifiableDataService<Script> implements FindAllData<Script> {
|
||||
private findAllData: FindAllDataImpl<Script>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Script>) {
|
||||
super();
|
||||
) {
|
||||
super('scripts', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
public invoke(scriptName: string, parameters: ProcessParameter[], files: File[]): Observable<RemoteData<Process>> {
|
||||
@@ -75,6 +73,25 @@ export class ScriptDataService extends DataService<Script> {
|
||||
getFirstCompletedRemoteData(),
|
||||
map((rd: RemoteData<Script>) => {
|
||||
return hasValue(rd.payload);
|
||||
}));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Script>[]): Observable<RemoteData<PaginatedList<Script>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -2,17 +2,14 @@ import { of as observableOf } from 'rxjs';
|
||||
import { getMockRemoteDataBuildService } from '../../shared/mocks/remote-data-build.service.mock';
|
||||
import { getMockRequestService } from '../../shared/mocks/request.service.mock';
|
||||
import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service.stub';
|
||||
import {
|
||||
createSuccessfulRemoteDataObject,
|
||||
createSuccessfulRemoteDataObject$
|
||||
} from '../../shared/remote-data.utils';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { ItemType } from '../shared/item-relationships/item-type.model';
|
||||
import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
|
||||
import { RelationshipTypeService } from './relationship-type.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { hasValueOperator } from '../../shared/empty.util';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
||||
describe('RelationshipTypeService', () => {
|
||||
let service: RelationshipTypeService;
|
||||
@@ -29,7 +26,6 @@ describe('RelationshipTypeService', () => {
|
||||
let relationshipType1;
|
||||
let relationshipType2;
|
||||
|
||||
let itemService;
|
||||
let buildList;
|
||||
let rdbService;
|
||||
let objectCache;
|
||||
@@ -72,22 +68,14 @@ describe('RelationshipTypeService', () => {
|
||||
/* eslint-enable no-empty, @typescript-eslint/no-empty-function */
|
||||
}) as ObjectCacheService;
|
||||
|
||||
itemService = undefined;
|
||||
|
||||
}
|
||||
|
||||
function initTestService() {
|
||||
return new RelationshipTypeService(
|
||||
itemService,
|
||||
requestService,
|
||||
rdbService,
|
||||
null,
|
||||
halService,
|
||||
objectCache,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
halService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,28 +1,22 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
import { map, mergeMap, switchMap, toArray } from 'rxjs/operators';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { ItemType } from '../shared/item-relationships/item-type.model';
|
||||
import { RelationshipType } from '../shared/item-relationships/relationship-type.model';
|
||||
import { RELATIONSHIP_TYPE } from '../shared/item-relationships/relationship-type.resource-type';
|
||||
import { getFirstSucceededRemoteData, getFirstCompletedRemoteData, getRemoteDataPayload } from '../shared/operators';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { ItemDataService } from './item-data.service';
|
||||
import { getFirstCompletedRemoteData, getFirstSucceededRemoteData, getRemoteDataPayload } from '../shared/operators';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RequestService } from './request.service';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
import { FindAllDataImpl } from './base/find-all-data';
|
||||
import { SearchDataImpl } from './base/search-data';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
||||
/**
|
||||
* Check if one side of a RelationshipType is the ItemType with the given label
|
||||
@@ -38,20 +32,20 @@ const checkSide = (typeRd: RemoteData<ItemType>, label: string): boolean =>
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(RELATIONSHIP_TYPE)
|
||||
export class RelationshipTypeService extends DataService<RelationshipType> {
|
||||
protected linkPath = 'relationshiptypes';
|
||||
export class RelationshipTypeService extends BaseDataService<RelationshipType> {
|
||||
private searchData: SearchDataImpl<RelationshipType>;
|
||||
private findAllData: FindAllDataImpl<RelationshipType>;
|
||||
|
||||
constructor(protected itemService: ItemDataService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<RelationshipType>,
|
||||
protected appStore: Store<AppState>) {
|
||||
super();
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
) {
|
||||
super('relationshiptypes', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,34 +61,34 @@ export class RelationshipTypeService extends DataService<RelationshipType> {
|
||||
*/
|
||||
getRelationshipTypeByLabelAndTypes(relationshipTypeLabel: string, firstItemType: string, secondItemType: string): Observable<RelationshipType> {
|
||||
// Retrieve all relationship types from the server in a single page
|
||||
return this.findAll({ currentPage: 1, elementsPerPage: 9999 }, true, true, followLink('leftType'), followLink('rightType'))
|
||||
.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
// Emit each type in the page array separately
|
||||
switchMap((typeListRD: RemoteData<PaginatedList<RelationshipType>>) => typeListRD.payload.page),
|
||||
// Check each type individually, to see if it matches the provided types
|
||||
mergeMap((relationshipType: RelationshipType) => {
|
||||
if (relationshipType.leftwardType === relationshipTypeLabel) {
|
||||
return this.checkType(relationshipType, firstItemType, secondItemType);
|
||||
} else if (relationshipType.rightwardType === relationshipTypeLabel) {
|
||||
return this.checkType(relationshipType, secondItemType, firstItemType);
|
||||
} else {
|
||||
return [null];
|
||||
}
|
||||
}),
|
||||
// Wait for all types to be checked and emit once, with the results combined back into an
|
||||
// array
|
||||
toArray(),
|
||||
// Look for a match in the array and emit it if found, or null if one isn't found
|
||||
map((types: RelationshipType[]) => {
|
||||
const match = types.find((type: RelationshipType) => hasValue(type));
|
||||
if (hasValue(match)) {
|
||||
return match;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
);
|
||||
return this.findAllData.findAll({ currentPage: 1, elementsPerPage: 9999 }, true, true, followLink('leftType'), followLink('rightType'))
|
||||
.pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
// Emit each type in the page array separately
|
||||
switchMap((typeListRD: RemoteData<PaginatedList<RelationshipType>>) => typeListRD.payload.page),
|
||||
// Check each type individually, to see if it matches the provided types
|
||||
mergeMap((relationshipType: RelationshipType) => {
|
||||
if (relationshipType.leftwardType === relationshipTypeLabel) {
|
||||
return this.checkType(relationshipType, firstItemType, secondItemType);
|
||||
} else if (relationshipType.rightwardType === relationshipTypeLabel) {
|
||||
return this.checkType(relationshipType, secondItemType, firstItemType);
|
||||
} else {
|
||||
return [null];
|
||||
}
|
||||
}),
|
||||
// Wait for all types to be checked and emit once, with the results combined back into an
|
||||
// array
|
||||
toArray(),
|
||||
// Look for a match in the array and emit it if found, or null if one isn't found
|
||||
map((types: RelationshipType[]) => {
|
||||
const match = types.find((type: RelationshipType) => hasValue(type));
|
||||
if (hasValue(match)) {
|
||||
return match;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,27 +121,29 @@ export class RelationshipTypeService extends DataService<RelationshipType> {
|
||||
* Returns an observable of the given RelationshipType if it matches, null if it doesn't
|
||||
*
|
||||
* @param type The RelationshipType to check
|
||||
* @param useCachedVersionIfAvailable
|
||||
* @param reRequestOnStale
|
||||
* @param linksToFollow
|
||||
*/
|
||||
searchByEntityType(type: string,useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<RelationshipType>[]): Observable<PaginatedList<RelationshipType>> {
|
||||
|
||||
return this.searchBy(
|
||||
searchByEntityType(type: string, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<RelationshipType>[]): Observable<PaginatedList<RelationshipType>> {
|
||||
return this.searchData.searchBy(
|
||||
'byEntityType',
|
||||
{
|
||||
searchParams: [
|
||||
{
|
||||
fieldName: 'type',
|
||||
fieldValue: type
|
||||
fieldValue: type,
|
||||
},
|
||||
{
|
||||
fieldName: 'size',
|
||||
fieldValue: 100
|
||||
fieldValue: 100,
|
||||
},
|
||||
]
|
||||
}, useCachedVersionIfAvailable,reRequestOnStale,...linksToFollow).pipe(
|
||||
],
|
||||
}, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow,
|
||||
).pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
getRemoteDataPayload(),
|
||||
) as Observable<PaginatedList<RelationshipType>>;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ import { Relationship } from '../shared/item-relationships/relationship.model';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { buildPaginatedList } from './paginated-list.model';
|
||||
import { DeleteRequest} from './request.models';
|
||||
import { DeleteRequest } from './request.models';
|
||||
import { RelationshipService } from './relationship.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { HALEndpointServiceStub } from '../../shared/testing/hal-endpoint-service.stub';
|
||||
@@ -123,15 +123,11 @@ describe('RelationshipService', () => {
|
||||
|
||||
function initTestService() {
|
||||
return new RelationshipService(
|
||||
itemService,
|
||||
requestService,
|
||||
rdbService,
|
||||
null,
|
||||
halService,
|
||||
objectCache,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
itemService,
|
||||
null,
|
||||
jasmine.createSpy('paginatedRelationsToItems').and.returnValue((v) => v),
|
||||
);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
SetNameVariantAction
|
||||
} from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.actions';
|
||||
import { NameVariantListState } from '../../shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/name-variant.reducer';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
@@ -33,19 +32,19 @@ import {
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
getRemoteDataPayload
|
||||
} from '../shared/operators';
|
||||
import { DataService } from './data.service';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { ItemDataService } from './item-data.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { DeleteRequest, PostRequest} from './request.models';
|
||||
import { DeleteRequest, PostRequest } from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { NoContent } from '../shared/NoContent.model';
|
||||
import { RequestEntryState } from './request-entry-state.model';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { RestRequest } from './rest-request.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { SearchData, SearchDataImpl } from './base/search-data';
|
||||
import { PutData, PutDataImpl } from './base/put-data';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
const relationshipListsStateSelector = (state: AppState) => state.relationshipLists;
|
||||
|
||||
@@ -75,22 +74,23 @@ const compareItemsByUUID = (itemCheck: Item) =>
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(RELATIONSHIP)
|
||||
export class RelationshipService extends DataService<Relationship> {
|
||||
protected linkPath = 'relationships';
|
||||
protected responseMsToLive = 15 * 60 * 1000;
|
||||
export class RelationshipService extends IdentifiableDataService<Relationship> implements SearchData<Relationship> {
|
||||
private searchData: SearchData<Relationship>;
|
||||
private putData: PutData<Relationship>;
|
||||
|
||||
constructor(protected itemService: ItemDataService,
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Relationship>,
|
||||
protected appStore: Store<AppState>,
|
||||
@Inject(PAGINATED_RELATIONS_TO_ITEMS_OPERATOR) private paginatedRelationsToItems: (thisId: string) => (source: Observable<RemoteData<PaginatedList<Relationship>>>) => Observable<RemoteData<PaginatedList<Item>>>) {
|
||||
super();
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected halService: HALEndpointService,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected itemService: ItemDataService,
|
||||
protected appStore: Store<AppState>,
|
||||
@Inject(PAGINATED_RELATIONS_TO_ITEMS_OPERATOR) private paginatedRelationsToItems: (thisId: string) => (source: Observable<RemoteData<PaginatedList<Relationship>>>) => Observable<RemoteData<PaginatedList<Item>>>,
|
||||
) {
|
||||
super('relationships', requestService, rdbService, objectCache, halService, 15 * 60 * 1000);
|
||||
|
||||
this.searchData = new SearchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
this.putData = new PutDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,13 +99,15 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
*/
|
||||
getRelationshipEndpoint(uuid: string) {
|
||||
return this.getBrowseEndpoint().pipe(
|
||||
map((href: string) => `${href}/${uuid}`)
|
||||
map((href: string) => `${href}/${uuid}`),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a delete request for a relationship by ID
|
||||
* @param id
|
||||
* @param id the ID of the relationship to delete
|
||||
* @param copyVirtualMetadata whether to copy this relationship's virtual metadata to the related Items
|
||||
* accepted values: none, all, left, right, configured
|
||||
*/
|
||||
deleteRelationship(id: string, copyVirtualMetadata: string): Observable<RemoteData<NoContent>> {
|
||||
return this.getRelationshipEndpoint(id).pipe(
|
||||
@@ -469,7 +471,7 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
* @param object the {@link Relationship} to update
|
||||
*/
|
||||
update(object: Relationship): Observable<RemoteData<Relationship>> {
|
||||
return this.put(object);
|
||||
return this.putData.put(object);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -513,7 +515,7 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
searchParams.push(
|
||||
{
|
||||
fieldName: 'relatedItem',
|
||||
fieldValue: itemId
|
||||
fieldValue: itemId,
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -521,8 +523,31 @@ export class RelationshipService extends DataService<Relationship> {
|
||||
return this.searchBy(
|
||||
'byItemsAndType',
|
||||
{
|
||||
searchParams: searchParams
|
||||
}) as Observable<RemoteData<PaginatedList<Relationship>>>;
|
||||
searchParams: searchParams,
|
||||
},
|
||||
) as Observable<RemoteData<PaginatedList<Relationship>>>;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new FindListRequest with given search method
|
||||
*
|
||||
* @param searchMethod The search method for the object
|
||||
* @param options The [[FindListOptions]] object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>}
|
||||
* Return an observable that emits response from the server
|
||||
*/
|
||||
searchBy(searchMethod: string, options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Relationship>[]): Observable<RemoteData<PaginatedList<Relationship>>> {
|
||||
return this.searchData.searchBy(searchMethod, options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
getSearchByHref(searchMethod: string, options: FindListOptions, ...linksToFollow: FollowLinkConfig<Relationship>[]): Observable<string> {
|
||||
return this.searchData.getSearchByHref(searchMethod, options, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -12,19 +12,20 @@ describe('RootDataService', () => {
|
||||
let halService: HALEndpointService;
|
||||
let restService;
|
||||
let rootEndpoint;
|
||||
let findByHrefSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
rootEndpoint = 'root-endpoint';
|
||||
halService = jasmine.createSpyObj('halService', {
|
||||
getRootHref: rootEndpoint
|
||||
getRootHref: rootEndpoint,
|
||||
});
|
||||
restService = jasmine.createSpyObj('halService', {
|
||||
get: jasmine.createSpy('get')
|
||||
});
|
||||
service = new RootDataService(null, null, null, null, halService, null, null, null, restService);
|
||||
(service as any).dataService = jasmine.createSpyObj('dataService', {
|
||||
findByHref: createSuccessfulRemoteDataObject$({})
|
||||
get: jasmine.createSpy('get'),
|
||||
});
|
||||
service = new RootDataService(null, null, null, halService, restService);
|
||||
|
||||
findByHrefSpy = spyOn(service as any, 'findByHref');
|
||||
findByHrefSpy.and.returnValue(createSuccessfulRemoteDataObject$({}));
|
||||
});
|
||||
|
||||
describe('findRoot', () => {
|
||||
@@ -36,7 +37,7 @@ describe('RootDataService', () => {
|
||||
|
||||
it('should call findByHref using the root endpoint', (done) => {
|
||||
result$.subscribe(() => {
|
||||
expect((service as any).dataService.findByHref).toHaveBeenCalledWith(rootEndpoint, true, true);
|
||||
expect(findByHrefSpy).toHaveBeenCalledWith(rootEndpoint, true, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@@ -1,70 +1,33 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { DataService } from './data.service';
|
||||
import { Root } from './root.model';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ROOT } from './root.resource-type';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { DspaceRestService } from '../dspace-rest/dspace-rest.service';
|
||||
import { RawRestResponse } from '../dspace-rest/raw-rest-response.model';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
|
||||
/**
|
||||
* A private DataService implementation to delegate specific methods to.
|
||||
*/
|
||||
class DataServiceImpl extends DataService<Root> {
|
||||
protected linkPath = '';
|
||||
protected responseMsToLive = 6 * 60 * 60 * 1000;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Root>) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
||||
/**
|
||||
* A service to retrieve the {@link Root} object from the REST API.
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(ROOT)
|
||||
export class RootDataService {
|
||||
/**
|
||||
* A private DataService instance to delegate specific methods to.
|
||||
*/
|
||||
private dataService: DataServiceImpl;
|
||||
|
||||
export class RootDataService extends BaseDataService<Root> {
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Root>,
|
||||
protected restService: DspaceRestService) {
|
||||
this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, notificationsService, http, comparator);
|
||||
protected restService: DspaceRestService,
|
||||
) {
|
||||
super('', requestService, rdbService, objectCache, halService, 6 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,38 +53,7 @@ export class RootDataService {
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findRoot(useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Root>[]): Observable<RemoteData<Root>> {
|
||||
return this.dataService.findByHref(this.halService.getRootHref(), useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an observable of {@link RemoteData} of an object, based on an href, with a list of
|
||||
* {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object
|
||||
* @param href The url of object we want to retrieve
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findByHref(href: string | Observable<string>, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Root>[]): Observable<RemoteData<Root>> {
|
||||
return this.dataService.findByHref(href, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of observables of {@link RemoteData} of objects, based on an href, with a list
|
||||
* of {@link FollowLinkConfig}, to automatically resolve {@link HALLink}s of the object
|
||||
* @param href The url of object we want to retrieve
|
||||
* @param findListOptions Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
*/
|
||||
findAllByHref(href: string | Observable<string>, findListOptions: FindListOptions = {}, useCachedVersionIfAvailable = true, reRequestOnStale = true, ...linksToFollow: FollowLinkConfig<Root>[]): Observable<RemoteData<PaginatedList<Root>>> {
|
||||
return this.dataService.findAllByHref(href, findListOptions, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
return this.findByHref(this.halService.getRootHref(), useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -4,14 +4,10 @@ import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { Site } from '../shared/site.model';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { createSuccessfulRemoteDataObject } from '../../shared/remote-data.utils';
|
||||
import { createPaginatedList } from '../../shared/testing/utils.test';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
|
||||
describe('SiteDataService', () => {
|
||||
@@ -47,21 +43,13 @@ describe('SiteDataService', () => {
|
||||
})
|
||||
});
|
||||
|
||||
const store = {} as Store<CoreState>;
|
||||
objectCache = {} as ObjectCacheService;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
|
||||
service = new SiteDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparator
|
||||
);
|
||||
});
|
||||
|
||||
|
@@ -1,42 +1,38 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { getFirstSucceededRemoteData } from '../shared/operators';
|
||||
import { Site } from '../shared/site.model';
|
||||
import { SITE } from '../shared/site.resource-type';
|
||||
import { DataService } from './data.service';
|
||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||
import { PaginatedList } from './paginated-list.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { RequestService } from './request.service';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
import { FindAllData, FindAllDataImpl } from './base/find-all-data';
|
||||
import { FollowLinkConfig } from 'src/app/shared/utils/follow-link-config.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
|
||||
/**
|
||||
* Service responsible for handling requests related to the Site object
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(SITE)
|
||||
export class SiteDataService extends DataService<Site> {
|
||||
protected linkPath = 'sites';
|
||||
export class SiteDataService extends BaseDataService<Site> implements FindAllData<Site> {
|
||||
private findAllData: FindAllData<Site>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DSOChangeAnalyzer<Site>,
|
||||
) {
|
||||
super();
|
||||
super('sites', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.findAllData = new FindAllDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, this.responseMsToLive);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,7 +42,25 @@ export class SiteDataService extends DataService<Site> {
|
||||
return this.findAll().pipe(
|
||||
getFirstSucceededRemoteData(),
|
||||
map((remoteData: RemoteData<PaginatedList<Site>>) => remoteData.payload),
|
||||
map((list: PaginatedList<Site>) => list.page[0])
|
||||
map((list: PaginatedList<Site>) => list.page[0]),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RemoteData} of all object with a list of {@link FollowLinkConfig}, to indicate which embedded
|
||||
* info should be added to the objects
|
||||
*
|
||||
* @param options Find list options object
|
||||
* @param useCachedVersionIfAvailable If this is true, the request will only be sent if there's
|
||||
* no valid cached version. Defaults to true
|
||||
* @param reRequestOnStale Whether or not the request should automatically be re-
|
||||
* requested after the response becomes stale
|
||||
* @param linksToFollow List of {@link FollowLinkConfig} that indicate which
|
||||
* {@link HALLink}s should be automatically resolved
|
||||
* @return {Observable<RemoteData<PaginatedList<T>>>}
|
||||
* Return an observable that emits object list
|
||||
*/
|
||||
public findAll(options?: FindListOptions, useCachedVersionIfAvailable?: boolean, reRequestOnStale?: boolean, ...linksToFollow: FollowLinkConfig<Site>[]): Observable<RemoteData<PaginatedList<Site>>> {
|
||||
return this.findAllData.findAll(options, useCachedVersionIfAvailable, reRequestOnStale, ...linksToFollow);
|
||||
}
|
||||
}
|
||||
|
@@ -1,18 +1,12 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { RequestService } from './request.service';
|
||||
import { PageInfo } from '../shared/page-info.model';
|
||||
import { createSuccessfulRemoteDataObject, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
import { HrefOnlyDataService } from './href-only-data.service';
|
||||
import { getMockHrefOnlyDataService } from '../../shared/mocks/href-only-data.service.mock';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { RestResponse } from '../cache/response.models';
|
||||
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||
import { Item } from '../shared/item.model';
|
||||
@@ -20,10 +14,8 @@ import { VersionDataService } from './version-data.service';
|
||||
import { Version } from '../shared/version.model';
|
||||
import { VersionHistory } from '../shared/version-history.model';
|
||||
import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { RequestEntry } from './request-entry.model';
|
||||
|
||||
|
||||
describe('VersionDataService test', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: VersionDataService;
|
||||
@@ -80,29 +72,17 @@ describe('VersionDataService test', () => {
|
||||
const mockVersionRD = createSuccessfulRemoteDataObject(mockVersion);
|
||||
|
||||
const endpointURL = `https://rest.api/rest/api/versioning/versions`;
|
||||
const findByIdRequestURL = `https://rest.api/rest/api/versioning/versions/${mockVersion.id}`;
|
||||
const findByIdRequestURL$ = observableOf(findByIdRequestURL);
|
||||
|
||||
const requestUUID = '8b3c613a-5a4b-438b-9686-be1d5b4a1c5a';
|
||||
|
||||
objectCache = {} as ObjectCacheService;
|
||||
const notificationsService = {} as NotificationsService;
|
||||
const http = {} as HttpClient;
|
||||
const comparator = {} as any;
|
||||
const comparatorEntry = {} as any;
|
||||
const store = {} as Store<CoreState>;
|
||||
const pageInfo = new PageInfo();
|
||||
|
||||
function initTestService() {
|
||||
hrefOnlyDataService = getMockHrefOnlyDataService();
|
||||
return new VersionDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
store,
|
||||
objectCache,
|
||||
halService,
|
||||
notificationsService,
|
||||
http,
|
||||
comparatorEntry
|
||||
);
|
||||
}
|
||||
@@ -134,8 +114,7 @@ describe('VersionDataService test', () => {
|
||||
|
||||
service = initTestService();
|
||||
|
||||
spyOn((service as any), 'findByHref').and.callThrough();
|
||||
spyOn((service as any), 'getIDHrefObs').and.returnValue(findByIdRequestURL$);
|
||||
spyOn((service as any), 'findById').and.callThrough();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -147,7 +126,7 @@ describe('VersionDataService test', () => {
|
||||
scheduler.schedule(() => service.getHistoryFromVersion(mockVersion, true, true));
|
||||
scheduler.flush();
|
||||
|
||||
expect((service as any).findByHref).toHaveBeenCalledWith(findByIdRequestURL$, true, true, followLink('versionhistory'));
|
||||
expect((service as any).findById).toHaveBeenCalledWith(mockVersion.id, true, true, followLink('versionhistory'));
|
||||
});
|
||||
|
||||
it('should return a VersionHistory', () => {
|
||||
|
@@ -1,14 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DataService } from './data.service';
|
||||
import { Version } from '../shared/version.model';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { VERSION } from '../shared/version.resource-type';
|
||||
@@ -17,26 +12,30 @@ import { followLink } from '../../shared/utils/follow-link-config.model';
|
||||
import { getFirstSucceededRemoteDataPayload } from '../shared/operators';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { isNotEmpty } from '../../shared/empty.util';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { RemoteData } from './remote-data';
|
||||
import { PatchData, PatchDataImpl } from './base/patch-data';
|
||||
import { RestRequestMethod } from './rest-request-method';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
/**
|
||||
* Service responsible for handling requests related to the Version object
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(VERSION)
|
||||
export class VersionDataService extends DataService<Version> {
|
||||
protected linkPath = 'versions';
|
||||
export class VersionDataService extends IdentifiableDataService<Version> implements PatchData<Version> {
|
||||
private patchData: PatchData<Version>;
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<Version>) {
|
||||
super();
|
||||
protected comparator: DefaultChangeAnalyzer<Version>,
|
||||
) {
|
||||
super('versions', requestService, rdbService, objectCache, halService);
|
||||
|
||||
this.patchData = new PatchDataImpl(this.linkPath, requestService, rdbService, objectCache, halService, comparator, this.responseMsToLive, this.constructIdEndpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,4 +64,29 @@ export class VersionDataService extends DataService<Version> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a patch request for a specified object
|
||||
* @param {T} object The object to send a patch request for
|
||||
* @param {Operation[]} operations The patch operations to be performed
|
||||
*/
|
||||
public patch(object: Version, operations: []): Observable<RemoteData<Version>> {
|
||||
return this.patchData.patch(object, operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new patch to the object cache
|
||||
* The patch is derived from the differences between the given object and its version in the object cache
|
||||
* @param {DSpaceObject} object The given object
|
||||
*/
|
||||
public update(object: Version): Observable<RemoteData<Version>> {
|
||||
return this.patchData.update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit current object changes to the server
|
||||
* @param method The RestRequestMethod for which de server sync buffer should be committed
|
||||
*/
|
||||
public commitUpdates(method?: RestRequestMethod): void {
|
||||
this.patchData.commitUpdates(method);
|
||||
}
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@ describe('VersionHistoryDataService', () => {
|
||||
buildFromRequestUUID: jasmine.createSpy('buildFromRequestUUID'),
|
||||
});
|
||||
objectCache = jasmine.createSpyObj('objectCache', {
|
||||
remove: jasmine.createSpy('remove')
|
||||
remove: jasmine.createSpy('remove'),
|
||||
});
|
||||
versionService = jasmine.createSpyObj('objectCache', {
|
||||
findByHref: jasmine.createSpy('findByHref'),
|
||||
@@ -112,7 +112,13 @@ describe('VersionHistoryDataService', () => {
|
||||
halService = new HALEndpointServiceStub(url);
|
||||
notificationsService = new NotificationsServiceStub();
|
||||
|
||||
service = new VersionHistoryDataService(requestService, rdbService, null, objectCache, halService, notificationsService, versionService, null, null);
|
||||
service = new VersionHistoryDataService(
|
||||
requestService,
|
||||
rdbService,
|
||||
objectCache,
|
||||
halService,
|
||||
versionService,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
|
@@ -1,14 +1,10 @@
|
||||
import { DataService } from './data.service';
|
||||
import { VersionHistory } from '../shared/version-history.model';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
import { PostRequest } from './request.models';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { PaginatedSearchOptions } from '../../shared/search/models/paginated-search-options.model';
|
||||
@@ -21,40 +17,31 @@ import { VERSION_HISTORY } from '../shared/version-history.resource-type';
|
||||
import { followLink, FollowLinkConfig } from '../../shared/utils/follow-link-config.model';
|
||||
import { VersionDataService } from './version-data.service';
|
||||
import { HttpOptions } from '../dspace-rest/dspace-rest.service';
|
||||
import {
|
||||
getAllSucceededRemoteData,
|
||||
getFirstCompletedRemoteData,
|
||||
getFirstSucceededRemoteDataPayload,
|
||||
getRemoteDataPayload
|
||||
} from '../shared/operators';
|
||||
import { getAllSucceededRemoteData, getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload, getRemoteDataPayload } from '../shared/operators';
|
||||
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
||||
import { hasValueOperator } from '../../shared/empty.util';
|
||||
import { Item } from '../shared/item.model';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { sendRequest } from '../shared/request.operators';
|
||||
import { RestRequest } from './rest-request.model';
|
||||
import { IdentifiableDataService } from './base/identifiable-data.service';
|
||||
|
||||
/**
|
||||
* Service responsible for handling requests related to the VersionHistory object
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(VERSION_HISTORY)
|
||||
export class VersionHistoryDataService extends DataService<VersionHistory> {
|
||||
protected linkPath = 'versionhistories';
|
||||
export class VersionHistoryDataService extends IdentifiableDataService<VersionHistory> {
|
||||
protected versionsEndpoint = 'versions';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected versionDataService: VersionDataService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<VersionHistory>) {
|
||||
super();
|
||||
) {
|
||||
super('versionhistories', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,41 +1,27 @@
|
||||
import { DataService } from './data.service';
|
||||
import { WorkflowAction } from '../tasks/models/workflow-action-object.model';
|
||||
import { RequestService } from './request.service';
|
||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { DefaultChangeAnalyzer } from './default-change-analyzer.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { dataService } from '../cache/builders/build-decorators';
|
||||
import { WORKFLOW_ACTION } from '../tasks/models/workflow-action-object.resource-type';
|
||||
import { CoreState } from '../core-state.model';
|
||||
import { FindListOptions } from './find-list-options.model';
|
||||
import { BaseDataService } from './base/base-data.service';
|
||||
|
||||
/**
|
||||
* A service responsible for fetching/sending data from/to the REST API on the workflowactions endpoint
|
||||
*/
|
||||
@Injectable()
|
||||
@dataService(WORKFLOW_ACTION)
|
||||
export class WorkflowActionDataService extends DataService<WorkflowAction> {
|
||||
export class WorkflowActionDataService extends BaseDataService<WorkflowAction> {
|
||||
protected linkPath = 'workflowactions';
|
||||
|
||||
constructor(
|
||||
protected requestService: RequestService,
|
||||
protected rdbService: RemoteDataBuildService,
|
||||
protected store: Store<CoreState>,
|
||||
protected objectCache: ObjectCacheService,
|
||||
protected halService: HALEndpointService,
|
||||
protected notificationsService: NotificationsService,
|
||||
protected http: HttpClient,
|
||||
protected comparator: DefaultChangeAnalyzer<WorkflowAction>) {
|
||||
super();
|
||||
}
|
||||
|
||||
getBrowseEndpoint(options: FindListOptions, linkPath?: string): Observable<string> {
|
||||
return this.halService.getEndpoint(this.linkPath);
|
||||
) {
|
||||
super('workflowactions', requestService, rdbService, objectCache, halService);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user