mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Added services and models
This commit is contained in:
@@ -12,6 +12,8 @@ import { NormalizedWorkspaceItem } from '../../submission/models/normalized-work
|
|||||||
import { NormalizedEPerson } from '../../eperson/models/normalized-eperson.model';
|
import { NormalizedEPerson } from '../../eperson/models/normalized-eperson.model';
|
||||||
import { NormalizedGroup } from '../../eperson/models/normalized-group.model';
|
import { NormalizedGroup } from '../../eperson/models/normalized-group.model';
|
||||||
import { NormalizedWorkflowItem } from '../../submission/models/normalized-workflowitem.model';
|
import { NormalizedWorkflowItem } from '../../submission/models/normalized-workflowitem.model';
|
||||||
|
import { NormalizedClaimedTask } from '../../tasks/models/normalized-claimed-task-object.model';
|
||||||
|
import { NormalizedPoolTask } from '../../tasks/models/normalized-pool-task-object.model';
|
||||||
import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model';
|
import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model';
|
||||||
import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model';
|
import { SubmissionDefinitionsModel } from '../../config/models/config-submission-definitions.model';
|
||||||
import { SubmissionFormsModel } from '../../config/models/config-submission-forms.model';
|
import { SubmissionFormsModel } from '../../config/models/config-submission-forms.model';
|
||||||
@@ -63,6 +65,12 @@ export class NormalizedObjectFactory {
|
|||||||
case ResourceType.Workflowitem: {
|
case ResourceType.Workflowitem: {
|
||||||
return NormalizedWorkflowItem
|
return NormalizedWorkflowItem
|
||||||
}
|
}
|
||||||
|
case ResourceType.ClaimedTask: {
|
||||||
|
return NormalizedClaimedTask
|
||||||
|
}
|
||||||
|
case ResourceType.PoolTask: {
|
||||||
|
return NormalizedPoolTask
|
||||||
|
}
|
||||||
case ResourceType.BitstreamFormat: {
|
case ResourceType.BitstreamFormat: {
|
||||||
return NormalizedBitstreamFormat
|
return NormalizedBitstreamFormat
|
||||||
}
|
}
|
||||||
|
24
src/app/core/cache/response.models.ts
vendored
24
src/app/core/cache/response.models.ts
vendored
@@ -253,4 +253,28 @@ export class EpersonSuccessResponse extends RestResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MessageResponse extends RestResponse {
|
||||||
|
public toCache = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public statusCode: number,
|
||||||
|
public statusText: string,
|
||||||
|
public pageInfo?: PageInfo
|
||||||
|
) {
|
||||||
|
super(true, statusCode, statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaskResponse extends RestResponse {
|
||||||
|
public toCache = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public statusCode: number,
|
||||||
|
public statusText: string,
|
||||||
|
public pageInfo?: PageInfo
|
||||||
|
) {
|
||||||
|
super(true, statusCode, statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* tslint:enable:max-classes-per-file */
|
/* tslint:enable:max-classes-per-file */
|
||||||
|
@@ -77,6 +77,14 @@ import { MenuService } from '../shared/menu/menu.service';
|
|||||||
import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service';
|
import { SubmissionJsonPatchOperationsService } from './submission/submission-json-patch-operations.service';
|
||||||
import { NormalizedObjectBuildService } from './cache/builders/normalized-object-build.service';
|
import { NormalizedObjectBuildService } from './cache/builders/normalized-object-build.service';
|
||||||
import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service';
|
import { DSOChangeAnalyzer } from './data/dso-change-analyzer.service';
|
||||||
|
import { RoleService } from './roles/role.service';
|
||||||
|
import { MyDSpaceGuard } from '../+my-dspace-page/my-dspace.guard';
|
||||||
|
import { MyDSpaceResponseParsingService } from './data/mydspace-response-parsing.service';
|
||||||
|
import { MessageService } from './message/message.service';
|
||||||
|
import { ClaimedTaskDataService } from './tasks/claimed-task-data.service';
|
||||||
|
import { PoolTaskDataService } from './tasks/pool-task-data.service';
|
||||||
|
import { TaskResponseParsingService } from './tasks/task-response-parsing.service';
|
||||||
|
import { MessageResponseParsingService } from './message/message-response-parsing.service';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -128,6 +136,7 @@ const PROVIDERS = [
|
|||||||
RegistryBitstreamformatsResponseParsingService,
|
RegistryBitstreamformatsResponseParsingService,
|
||||||
DebugResponseParsingService,
|
DebugResponseParsingService,
|
||||||
SearchResponseParsingService,
|
SearchResponseParsingService,
|
||||||
|
MyDSpaceResponseParsingService,
|
||||||
ServerResponseService,
|
ServerResponseService,
|
||||||
BrowseResponseParsingService,
|
BrowseResponseParsingService,
|
||||||
BrowseEntriesResponseParsingService,
|
BrowseEntriesResponseParsingService,
|
||||||
@@ -156,6 +165,13 @@ const PROVIDERS = [
|
|||||||
DSOChangeAnalyzer,
|
DSOChangeAnalyzer,
|
||||||
CSSVariableService,
|
CSSVariableService,
|
||||||
MenuService,
|
MenuService,
|
||||||
|
MyDSpaceGuard,
|
||||||
|
RoleService,
|
||||||
|
MessageResponseParsingService,
|
||||||
|
MessageService,
|
||||||
|
TaskResponseParsingService,
|
||||||
|
ClaimedTaskDataService,
|
||||||
|
PoolTaskDataService,
|
||||||
// register AuthInterceptor as HttpInterceptor
|
// register AuthInterceptor as HttpInterceptor
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
@@ -166,15 +182,20 @@ const PROVIDERS = [
|
|||||||
{ provide: NativeWindowService, useFactory: NativeWindowFactory }
|
{ provide: NativeWindowService, useFactory: NativeWindowFactory }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const DIRECTIVES = [
|
||||||
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
...IMPORTS
|
...IMPORTS
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
...DECLARATIONS
|
...DECLARATIONS,
|
||||||
|
...DIRECTIVES
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
...EXPORTS
|
...EXPORTS,
|
||||||
|
...DIRECTIVES
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
...PROVIDERS
|
...PROVIDERS
|
||||||
|
@@ -160,4 +160,10 @@ export abstract class BaseResponseParsingService {
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected isSuccessStatus(statusCode: number) {
|
||||||
|
return (statusCode === 201
|
||||||
|
|| statusCode === 200
|
||||||
|
|| statusCode === 204)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { filter, map, take } from 'rxjs/operators';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
|
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
@@ -13,6 +16,10 @@ import { NotificationsService } from '../../shared/notifications/notifications.s
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
import { DSOChangeAnalyzer } from './dso-change-analyzer.service';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { FindAllOptions } from './request.models';
|
||||||
|
import { RemoteData } from './remote-data';
|
||||||
|
import { PaginatedList } from './paginated-list';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
|
export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
|
||||||
@@ -34,4 +41,21 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find whether there is a collection whom user has authorization to submit to
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
* true if the user has at least one collection to submit to
|
||||||
|
*/
|
||||||
|
hasAuthorizedCollection(): Observable<boolean> {
|
||||||
|
const searchHref = 'findAuthorized';
|
||||||
|
const options = new FindAllOptions();
|
||||||
|
options.elementsPerPage = 1;
|
||||||
|
|
||||||
|
return this.searchBy(searchHref, options).pipe(
|
||||||
|
filter((collections: RemoteData<PaginatedList<Collection>>) => !collections.isResponsePending),
|
||||||
|
take(1),
|
||||||
|
map((collections: RemoteData<PaginatedList<Collection>>) => collections.payload.totalElements > 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
59
src/app/core/data/mydspace-response-parsing.service.ts
Normal file
59
src/app/core/data/mydspace-response-parsing.service.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { RestResponse, SearchSuccessResponse } from '../cache/response.models';
|
||||||
|
import { DSOResponseParsingService } from './dso-response-parsing.service';
|
||||||
|
import { ResponseParsingService } from './parsing.service';
|
||||||
|
import { RestRequest } from './request.models';
|
||||||
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
|
import { hasValue } from '../../shared/empty.util';
|
||||||
|
import { SearchQueryResponse } from '../../+search-page/search-service/search-query-response.model';
|
||||||
|
import { MetadataMap, MetadataValue } from '../shared/metadata.interfaces';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MyDSpaceResponseParsingService implements ResponseParsingService {
|
||||||
|
constructor(private dsoParser: DSOResponseParsingService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
|
// fallback for unexpected empty response
|
||||||
|
const emptyPayload = {
|
||||||
|
_embedded : {
|
||||||
|
objects: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const payload = data.payload._embedded.searchResult || emptyPayload;
|
||||||
|
const hitHighlights: MetadataMap[] = payload._embedded.objects
|
||||||
|
.map((object) => object.hitHighlights)
|
||||||
|
.map((hhObject) => {
|
||||||
|
const mdMap: MetadataMap = {};
|
||||||
|
if (hhObject) {
|
||||||
|
for (const key of Object.keys(hhObject)) {
|
||||||
|
const value: MetadataValue = { value: hhObject[key].join('...'), language: null };
|
||||||
|
mdMap[key] = [ value ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mdMap;
|
||||||
|
});
|
||||||
|
|
||||||
|
const dsoSelfLinks = payload._embedded.objects
|
||||||
|
.filter((object) => hasValue(object._embedded))
|
||||||
|
.map((object) => object._embedded.rObject)
|
||||||
|
.map((dso) => this.dsoParser.parse(request, {
|
||||||
|
payload: dso,
|
||||||
|
statusCode: data.statusCode,
|
||||||
|
statusText: data.statusText
|
||||||
|
}))
|
||||||
|
.map((obj) => obj.resourceSelfLinks)
|
||||||
|
.reduce((combined, thisElement) => [...combined, ...thisElement], []);
|
||||||
|
|
||||||
|
const objects = payload._embedded.objects
|
||||||
|
.filter((object) => hasValue(object._embedded))
|
||||||
|
.map((object, index) => Object.assign({}, object, {
|
||||||
|
rObject: dsoSelfLinks[index],
|
||||||
|
hitHighlights: hitHighlights[index]
|
||||||
|
}));
|
||||||
|
payload.objects = objects;
|
||||||
|
const deserialized = new DSpaceRESTv2Serializer(SearchQueryResponse).deserialize(payload);
|
||||||
|
return new SearchSuccessResponse(deserialized, data.statusCode, data.statusText, this.dsoParser.processPageInfo(payload));
|
||||||
|
}
|
||||||
|
}
|
@@ -11,7 +11,7 @@ export class PaginatedList<T> {
|
|||||||
if (hasValue(this.pageInfo) && hasValue(this.pageInfo.elementsPerPage)) {
|
if (hasValue(this.pageInfo) && hasValue(this.pageInfo.elementsPerPage)) {
|
||||||
return this.pageInfo.elementsPerPage;
|
return this.pageInfo.elementsPerPage;
|
||||||
}
|
}
|
||||||
return this.page.length;
|
return this.getPageLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
set elementsPerPage(value: number) {
|
set elementsPerPage(value: number) {
|
||||||
@@ -22,7 +22,7 @@ export class PaginatedList<T> {
|
|||||||
if (hasValue(this.pageInfo) && hasValue(this.pageInfo.totalElements)) {
|
if (hasValue(this.pageInfo) && hasValue(this.pageInfo.totalElements)) {
|
||||||
return this.pageInfo.totalElements;
|
return this.pageInfo.totalElements;
|
||||||
}
|
}
|
||||||
return this.page.length;
|
return this.getPageLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
set totalElements(value: number) {
|
set totalElements(value: number) {
|
||||||
@@ -89,4 +89,8 @@ export class PaginatedList<T> {
|
|||||||
set self(self: string) {
|
set self(self: string) {
|
||||||
this.pageInfo.self = self;
|
this.pageInfo.self = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getPageLength() {
|
||||||
|
return (Array.isArray(this.page)) ? this.page.length : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,8 @@ import { BrowseItemsResponseParsingService } from './browse-items-response-parsi
|
|||||||
import { RegistryMetadataschemasResponseParsingService } from './registry-metadataschemas-response-parsing.service';
|
import { RegistryMetadataschemasResponseParsingService } from './registry-metadataschemas-response-parsing.service';
|
||||||
import { MetadataschemaParsingService } from './metadataschema-parsing.service';
|
import { MetadataschemaParsingService } from './metadataschema-parsing.service';
|
||||||
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
import { MetadatafieldParsingService } from './metadatafield-parsing.service';
|
||||||
|
import { TaskResponseParsingService } from '../tasks/task-response-parsing.service';
|
||||||
|
import { MessageResponseParsingService } from '../message/message-response-parsing.service';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
@@ -370,6 +372,46 @@ export class DeleteByIDRequest extends DeleteRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MessagePostRequest extends PostRequest {
|
||||||
|
constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) {
|
||||||
|
super(uuid, href, body, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||||
|
return MessageResponseParsingService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MessageGetRequest extends GetRequest {
|
||||||
|
constructor(uuid: string, href: string, public options?: HttpOptions) {
|
||||||
|
super(uuid, href, null, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||||
|
return MessageResponseParsingService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaskPostRequest extends PostRequest {
|
||||||
|
constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) {
|
||||||
|
super(uuid, href, body, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||||
|
return TaskResponseParsingService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TaskDeleteRequest extends DeleteRequest {
|
||||||
|
constructor(uuid: string, href: string, public body?: any, public options?: HttpOptions) {
|
||||||
|
super(uuid, href, body, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
getResponseParser(): GenericConstructor<ResponseParsingService> {
|
||||||
|
return TaskResponseParsingService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class RequestError extends Error {
|
export class RequestError extends Error {
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
statusText: string;
|
statusText: string;
|
||||||
|
@@ -4,7 +4,7 @@ import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
|
|||||||
import { merge as observableMerge, Observable, of as observableOf, race as observableRace } from 'rxjs';
|
import { merge as observableMerge, Observable, of as observableOf, race as observableRace } from 'rxjs';
|
||||||
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
|
import { filter, map, mergeMap, switchMap, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import { hasNoValue, hasValue, isNotEmpty } from '../../shared/empty.util';
|
import { hasNoValue, hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
import { DSOSuccessResponse, RestResponse } from '../cache/response.models';
|
import { DSOSuccessResponse, RestResponse } from '../cache/response.models';
|
||||||
@@ -123,9 +123,9 @@ export class RequestService {
|
|||||||
// TODO to review "forceBypassCache" param when https://github.com/DSpace/dspace-angular/issues/217 will be fixed
|
// TODO to review "forceBypassCache" param when https://github.com/DSpace/dspace-angular/issues/217 will be fixed
|
||||||
configure<T extends CacheableObject>(request: RestRequest, forceBypassCache: boolean = false): void {
|
configure<T extends CacheableObject>(request: RestRequest, forceBypassCache: boolean = false): void {
|
||||||
const isGetRequest = request.method === RestRequestMethod.GET;
|
const isGetRequest = request.method === RestRequestMethod.GET;
|
||||||
if (!isGetRequest || !this.isCachedOrPending(request) || forceBypassCache) {
|
if (!isGetRequest || !this.isCachedOrPending(request) || (forceBypassCache && !this.isPending(request))) {
|
||||||
this.dispatchRequest(request);
|
this.dispatchRequest(request);
|
||||||
if (isGetRequest && !forceBypassCache) {
|
if (isGetRequest) {
|
||||||
this.trackRequestsOnTheirWayToTheStore(request);
|
this.trackRequestsOnTheirWayToTheStore(request);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -139,6 +139,29 @@ export class RequestService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert request Payload to a URL-encoded string
|
||||||
|
*
|
||||||
|
* e.g. prepareBody({param: value, param1: value1})
|
||||||
|
* returns: param=value¶m1=value1
|
||||||
|
*
|
||||||
|
* @param body
|
||||||
|
* The request Payload to convert
|
||||||
|
* @return string
|
||||||
|
* URL-encoded string
|
||||||
|
*/
|
||||||
|
public prepareBody(body: any) {
|
||||||
|
let queryParams = '';
|
||||||
|
if (isNotEmpty(body) && typeof body === 'object') {
|
||||||
|
Object.keys(body)
|
||||||
|
.forEach((param) => {
|
||||||
|
const paramValue = `${param}=${body[param]}`;
|
||||||
|
queryParams = isEmpty(queryParams) ? queryParams.concat(paramValue) : queryParams.concat('&', paramValue);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return encodeURI(queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all request cache providing (part of) the href
|
* Remove all request cache providing (part of) the href
|
||||||
* This also includes href-to-uuid index cache
|
* This also includes href-to-uuid index cache
|
||||||
|
@@ -15,7 +15,13 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
const payload = data.payload._embedded.searchResult;
|
// fallback for unexpected empty response
|
||||||
|
const emptyPayload = {
|
||||||
|
_embedded : {
|
||||||
|
objects: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const payload = data.payload._embedded.searchResult || emptyPayload;
|
||||||
const hitHighlights: MetadataMap[] = payload._embedded.objects
|
const hitHighlights: MetadataMap[] = payload._embedded.objects
|
||||||
.map((object) => object.hitHighlights)
|
.map((object) => object.hitHighlights)
|
||||||
.map((hhObject) => {
|
.map((hhObject) => {
|
||||||
@@ -31,7 +37,7 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
|||||||
|
|
||||||
const dsoSelfLinks = payload._embedded.objects
|
const dsoSelfLinks = payload._embedded.objects
|
||||||
.filter((object) => hasValue(object._embedded))
|
.filter((object) => hasValue(object._embedded))
|
||||||
.map((object) => object._embedded.dspaceObject)
|
.map((object) => object._embedded.rObject)
|
||||||
// we don't need embedded collections, bitstreamformats, etc for search results.
|
// we don't need embedded collections, bitstreamformats, etc for search results.
|
||||||
// And parsing them all takes up a lot of time. Throw them away to improve performance
|
// And parsing them all takes up a lot of time. Throw them away to improve performance
|
||||||
// until objs until partial results are supported by the rest api
|
// until objs until partial results are supported by the rest api
|
||||||
@@ -47,7 +53,7 @@ export class SearchResponseParsingService implements ResponseParsingService {
|
|||||||
const objects = payload._embedded.objects
|
const objects = payload._embedded.objects
|
||||||
.filter((object) => hasValue(object._embedded))
|
.filter((object) => hasValue(object._embedded))
|
||||||
.map((object, index) => Object.assign({}, object, {
|
.map((object, index) => Object.assign({}, object, {
|
||||||
dspaceObject: dsoSelfLinks[index],
|
rObject: dsoSelfLinks[index],
|
||||||
hitHighlights: hitHighlights[index],
|
hitHighlights: hitHighlights[index],
|
||||||
// we don't need embedded collections, bitstreamformats, etc for search results.
|
// we don't need embedded collections, bitstreamformats, etc for search results.
|
||||||
// And parsing them all takes up a lot of time. Throw them away to improve performance
|
// And parsing them all takes up a lot of time. Throw them away to improve performance
|
||||||
|
17
src/app/core/message/message-data-response.ts
Normal file
17
src/app/core/message/message-data-response.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { RemoteDataError } from '../data/remote-data-error';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent the data retrieved by after processing a message
|
||||||
|
*/
|
||||||
|
export class MessageDataResponse {
|
||||||
|
constructor(
|
||||||
|
private isSuccessful: boolean,
|
||||||
|
public error?: RemoteDataError,
|
||||||
|
public payload?: any
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSucceeded(): boolean {
|
||||||
|
return this.isSuccessful;
|
||||||
|
}
|
||||||
|
}
|
37
src/app/core/message/message-response-parsing.service.ts
Normal file
37
src/app/core/message/message-response-parsing.service.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Inject, Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { ResponseParsingService } from '../data/parsing.service';
|
||||||
|
import { RestRequest } from '../data/request.models';
|
||||||
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
|
import { BaseResponseParsingService } from '../data/base-response-parsing.service';
|
||||||
|
import { GLOBAL_CONFIG } from '../../../config';
|
||||||
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { NormalizedSubmissionObjectFactory } from '../submission/normalized-submission-object-factory';
|
||||||
|
import { ErrorResponse, MessageResponse, RestResponse } from '../cache/response.models';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MessageResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
|
||||||
|
|
||||||
|
protected objectFactory = NormalizedSubmissionObjectFactory;
|
||||||
|
protected toCache = false;
|
||||||
|
|
||||||
|
constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
|
protected objectCache: ObjectCacheService,) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
|
if (this.isSuccessStatus(data.statusCode)) {
|
||||||
|
return new MessageResponse( data.statusCode, data.statusText);
|
||||||
|
} else {
|
||||||
|
return new ErrorResponse(
|
||||||
|
Object.assign(
|
||||||
|
new Error('Unexpected response from server'),
|
||||||
|
{ statusCode: data.statusCode, statusText: data.statusText }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
src/app/core/message/message.service.ts
Normal file
107
src/app/core/message/message.service.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { merge as observableMerge, Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { catchError, distinctUntilChanged, filter, flatMap, map, mergeMap, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
|
import { MessageGetRequest, MessagePostRequest, PostRequest, RestRequest } from '../data/request.models';
|
||||||
|
import { DSpaceRESTv2Service, HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||||
|
import { MessageDataResponse } from './message-data-response';
|
||||||
|
import { RemoteDataError } from '../data/remote-data-error';
|
||||||
|
import { getResponseFromEntry } from '../shared/operators';
|
||||||
|
import { ErrorResponse, MessageResponse, RestResponse } from '../cache/response.models';
|
||||||
|
import { RestRequestMethod } from '../data/rest-request-method';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MessageService {
|
||||||
|
protected linkPath = 'messages';
|
||||||
|
|
||||||
|
constructor(protected http: DSpaceRESTv2Service,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected halService: HALEndpointService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fetchRequest(requestId: string): Observable<MessageDataResponse> {
|
||||||
|
const responses = this.requestService.getByUUID(requestId).pipe(
|
||||||
|
getResponseFromEntry()
|
||||||
|
);
|
||||||
|
const errorResponses = responses.pipe(
|
||||||
|
filter((response: RestResponse) => !response.isSuccessful),
|
||||||
|
mergeMap((response: ErrorResponse) => observableOf(
|
||||||
|
new MessageDataResponse(
|
||||||
|
response.isSuccessful,
|
||||||
|
new RemoteDataError(response.statusCode, response.statusText, response.errorMessage)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
const successResponses = responses.pipe(
|
||||||
|
filter((response: RestResponse) => response.isSuccessful),
|
||||||
|
map((response: MessageResponse) => new MessageDataResponse(response.isSuccessful)),
|
||||||
|
distinctUntilChanged()
|
||||||
|
);
|
||||||
|
return observableMerge(errorResponses, successResponses);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getEndpointByMethod(endpoint: string, method: string): string {
|
||||||
|
return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public postToEndpoint(method: string, body: any, options?: HttpOptions): Observable<MessageDataResponse> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
|
filter((href: string) => isNotEmpty(href)),
|
||||||
|
map((endpointURL: string) => this.getEndpointByMethod(endpointURL, method)),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) => new MessagePostRequest(requestId, endpointURL, body, options)),
|
||||||
|
tap((request: PostRequest) => this.requestService.configure(request)),
|
||||||
|
flatMap((request: PostRequest) => this.fetchRequest(requestId)),
|
||||||
|
distinctUntilChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
public getRequest(method: string, options?: HttpOptions): Observable<any> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
|
map((endpointURL: string) => this.getEndpointByMethod(endpointURL, method)),
|
||||||
|
filter((href: string) => isNotEmpty(href)),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) => new MessageGetRequest(requestId, endpointURL)),
|
||||||
|
tap((request: RestRequest) => this.requestService.configure(request, true)),
|
||||||
|
flatMap((request: RestRequest) => this.fetchRequest(requestId)),
|
||||||
|
distinctUntilChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
public createMessage(body: any, options?: HttpOptions): Observable<MessageDataResponse> {
|
||||||
|
return this.postToEndpoint('', this.requestService.prepareBody(body), this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public markAsRead(body: any, options?: HttpOptions): Observable<MessageDataResponse> {
|
||||||
|
return this.postToEndpoint('read', this.requestService.prepareBody(body), this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public markAsUnread(body: any, options?: HttpOptions): Observable<MessageDataResponse> {
|
||||||
|
return this.postToEndpoint('unread', this.requestService.prepareBody(body), this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected makeHttpOptions() {
|
||||||
|
const options: HttpOptions = Object.create({});
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
options.headers = headers;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessageContent(url: string): Observable<any> {
|
||||||
|
if (isNotEmpty(url)) {
|
||||||
|
const options: HttpOptions = Object.create({});
|
||||||
|
options.observe = 'response';
|
||||||
|
options.responseType = 'text';
|
||||||
|
return this.http.request(RestRequestMethod.GET, url, null, options).pipe(
|
||||||
|
map((res) => ({ payload: res.payload })),
|
||||||
|
catchError((err) => observableOf({ payload: '' })));
|
||||||
|
} else {
|
||||||
|
return observableOf({ payload: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
src/app/core/roles/role-types.ts
Normal file
5
src/app/core/roles/role-types.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum RoleType {
|
||||||
|
Submitter = 'submitter',
|
||||||
|
Controller = 'controller',
|
||||||
|
Admin = 'admin'
|
||||||
|
}
|
52
src/app/core/roles/role.service.ts
Normal file
52
src/app/core/roles/role.service.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { AppState } from '../../app.reducer';
|
||||||
|
|
||||||
|
import { Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { distinctUntilChanged } from 'rxjs/operators';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { RoleType } from './role-types';
|
||||||
|
import { CollectionDataService } from '../data/collection-data.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RoleService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private collectionService: CollectionDataService,
|
||||||
|
private store: Store<AppState>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitter(): Observable<boolean> {
|
||||||
|
return this.collectionService.hasAuthorizedCollection().pipe(
|
||||||
|
distinctUntilChanged()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isController(): Observable<boolean> {
|
||||||
|
// TODO find a way to check if user is a controller
|
||||||
|
return observableOf(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin(): Observable<boolean> {
|
||||||
|
// TODO find a way to check if user is an admin
|
||||||
|
return observableOf(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRole(role: RoleType): Observable<boolean> {
|
||||||
|
let check: Observable<boolean>;
|
||||||
|
switch (role) {
|
||||||
|
case RoleType.Submitter:
|
||||||
|
check = this.isSubmitter();
|
||||||
|
break;
|
||||||
|
case RoleType.Controller:
|
||||||
|
check = this.isController();
|
||||||
|
break;
|
||||||
|
case RoleType.Admin:
|
||||||
|
check = this.isAdmin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
}
|
@@ -20,4 +20,6 @@ export enum ResourceType {
|
|||||||
SubmissionForms = 'submissionforms',
|
SubmissionForms = 'submissionforms',
|
||||||
SubmissionSections = 'submissionsections',
|
SubmissionSections = 'submissionsections',
|
||||||
SubmissionSection = 'submissionsection',
|
SubmissionSection = 'submissionsection',
|
||||||
|
ClaimedTask = 'claimedtask',
|
||||||
|
PoolTask = 'pooltask'
|
||||||
}
|
}
|
||||||
|
@@ -4,5 +4,6 @@
|
|||||||
|
|
||||||
export enum ViewMode {
|
export enum ViewMode {
|
||||||
List = 'list',
|
List = 'list',
|
||||||
Grid = 'grid'
|
Grid = 'grid',
|
||||||
|
Detail = 'detail'
|
||||||
}
|
}
|
||||||
|
56
src/app/core/tasks/claimed-task-data.service.ts
Normal file
56
src/app/core/tasks/claimed-task-data.service.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { NormalizedClaimedTask } from './models/normalized-claimed-task-object.model';
|
||||||
|
import { ClaimedTask } from './models/claimed-task-object.model';
|
||||||
|
import { TasksService } from './tasks.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ClaimedTaskDataService extends TasksService<NormalizedClaimedTask, ClaimedTask> {
|
||||||
|
protected linkPath = 'claimedtasks';
|
||||||
|
protected forceBypassCache = true;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: NormalizedObjectBuildService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOChangeAnalyzer) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public approveTask(scopeId: string): Observable<any> {
|
||||||
|
const body = {
|
||||||
|
submit_approve: 'true'
|
||||||
|
};
|
||||||
|
return this.postToEndpoint(this.linkPath, this.requestService.prepareBody(body), scopeId, this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public rejectTask(reason: string, scopeId: string): Observable<any> {
|
||||||
|
const body = {
|
||||||
|
submit_reject: 'true',
|
||||||
|
reason
|
||||||
|
};
|
||||||
|
return this.postToEndpoint(this.linkPath, this.requestService.prepareBody(body), scopeId, this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public returnToPoolTask(scopeId: string): Observable<any> {
|
||||||
|
return this.deleteById(this.linkPath, scopeId, this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
src/app/core/tasks/models/claimed-task-object.model.ts
Normal file
5
src/app/core/tasks/models/claimed-task-object.model.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { TaskObject } from './task-object.model';
|
||||||
|
|
||||||
|
export class ClaimedTask extends TaskObject {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,39 @@
|
|||||||
|
import { NormalizedTaskObject } from './normalized-task-object.model';
|
||||||
|
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
|
||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { ClaimedTask } from './claimed-task-object.model';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model class for a NormalizedClaimedTaskObject.
|
||||||
|
*/
|
||||||
|
@mapsTo(ClaimedTask)
|
||||||
|
@inheritSerialization(NormalizedTaskObject)
|
||||||
|
export class NormalizedClaimedTask extends NormalizedTaskObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task identifier
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflow step
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
step: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task action type
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
action: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflowitem object whom this task is related
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
@relationship(ResourceType.Workflowitem, false)
|
||||||
|
workflowitem: string;
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
import { NormalizedTaskObject } from './normalized-task-object.model';
|
||||||
|
import { PoolTask } from './pool-task-object.model';
|
||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model class for a NormalizedPoolTaskObject.
|
||||||
|
*/
|
||||||
|
@mapsTo(PoolTask)
|
||||||
|
@inheritSerialization(NormalizedTaskObject)
|
||||||
|
export class NormalizedPoolTask extends NormalizedTaskObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task identifier
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflow step
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
step: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task action type
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
action: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflowitem object whom this task is related
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
@relationship(ResourceType.Workflowitem, false)
|
||||||
|
workflowitem: string;
|
||||||
|
}
|
38
src/app/core/tasks/models/normalized-task-object.model.ts
Normal file
38
src/app/core/tasks/models/normalized-task-object.model.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
|
||||||
|
import { TaskObject } from './task-object.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract model class for a DSpaceObject.
|
||||||
|
*/
|
||||||
|
@mapsTo(TaskObject)
|
||||||
|
@inheritSerialization(NormalizedDSpaceObject)
|
||||||
|
export abstract class NormalizedTaskObject extends NormalizedDSpaceObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task identifier
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflow step
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
step: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task action type
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
action: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflowitem object whom this task is related
|
||||||
|
*/
|
||||||
|
@autoserialize
|
||||||
|
@relationship(ResourceType.Workflowitem, false)
|
||||||
|
workflowitem: string;
|
||||||
|
}
|
5
src/app/core/tasks/models/pool-task-object.model.ts
Normal file
5
src/app/core/tasks/models/pool-task-object.model.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { TaskObject } from './task-object.model';
|
||||||
|
|
||||||
|
export class PoolTask extends TaskObject {
|
||||||
|
|
||||||
|
}
|
17
src/app/core/tasks/models/process-task-response.ts
Normal file
17
src/app/core/tasks/models/process-task-response.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { RemoteDataError } from '../../data/remote-data-error';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to represent the data retrieved by after processing a task
|
||||||
|
*/
|
||||||
|
export class ProcessTaskResponse {
|
||||||
|
constructor(
|
||||||
|
private isSuccessful: boolean,
|
||||||
|
public error?: RemoteDataError,
|
||||||
|
public payload?: any
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSucceeded(): boolean {
|
||||||
|
return this.isSuccessful;
|
||||||
|
}
|
||||||
|
}
|
30
src/app/core/tasks/models/task-object.model.ts
Normal file
30
src/app/core/tasks/models/task-object.model.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { CacheableObject } from '../../cache/object-cache.reducer';
|
||||||
|
import { DSpaceObject } from '../../shared/dspace-object.model';
|
||||||
|
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
|
||||||
|
import { RemoteData } from '../../data/remote-data';
|
||||||
|
import { Workflowitem } from '../../submission/models/workflowitem.model';
|
||||||
|
|
||||||
|
export class TaskObject extends DSpaceObject implements CacheableObject, ListableObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task identifier
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflow step
|
||||||
|
*/
|
||||||
|
step: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The task action type
|
||||||
|
*/
|
||||||
|
action: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workflowitem object whom this task is related
|
||||||
|
*/
|
||||||
|
workflowitem: Observable<RemoteData<Workflowitem>> | Workflowitem;
|
||||||
|
}
|
40
src/app/core/tasks/pool-task-data.service.ts
Normal file
40
src/app/core/tasks/pool-task-data.service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { NormalizedPoolTask } from './models/normalized-pool-task-object.model';
|
||||||
|
import { PoolTask } from './models/pool-task-object.model';
|
||||||
|
import { TasksService } from './tasks.service';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { NormalizedObjectBuildService } from '../cache/builders/normalized-object-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { DSOChangeAnalyzer } from '../data/dso-change-analyzer.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PoolTaskDataService extends TasksService<NormalizedPoolTask, PoolTask> {
|
||||||
|
protected linkPath = 'pooltasks';
|
||||||
|
protected forceBypassCache = true;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: NormalizedObjectBuildService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOChangeAnalyzer) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public claimTask(scopeId: string): Observable<any> {
|
||||||
|
return this.postToEndpoint(this.linkPath, {}, scopeId, this.makeHttpOptions());
|
||||||
|
}
|
||||||
|
}
|
38
src/app/core/tasks/task-response-parsing.service.ts
Normal file
38
src/app/core/tasks/task-response-parsing.service.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Inject, Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { ResponseParsingService } from '../data/parsing.service';
|
||||||
|
import { RestRequest } from '../data/request.models';
|
||||||
|
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
|
||||||
|
|
||||||
|
import { BaseResponseParsingService } from '../data/base-response-parsing.service';
|
||||||
|
import { GLOBAL_CONFIG } from '../../../config';
|
||||||
|
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||||
|
import { ErrorResponse, RestResponse, TaskResponse } from '../cache/response.models';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TaskResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
|
||||||
|
|
||||||
|
protected objectFactory = NormalizedObjectFactory;
|
||||||
|
protected toCache = false;
|
||||||
|
|
||||||
|
constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||||
|
protected objectCache: ObjectCacheService,) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(request: RestRequest, data: DSpaceRESTV2Response): RestResponse {
|
||||||
|
if (this.isSuccessStatus(data.statusCode)) {
|
||||||
|
return new TaskResponse( data.statusCode, data.statusText);
|
||||||
|
} else {
|
||||||
|
return new ErrorResponse(
|
||||||
|
Object.assign(
|
||||||
|
new Error('Unexpected response from server'),
|
||||||
|
{ statusCode: data.statusCode, statusText: data.statusText }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
src/app/core/tasks/tasks.service.ts
Normal file
82
src/app/core/tasks/tasks.service.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
|
|
||||||
|
import { merge as observableMerge, Observable, of as observableOf } from 'rxjs';
|
||||||
|
import { distinctUntilChanged, filter, flatMap, map, mergeMap, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { DataService } from '../data/data.service';
|
||||||
|
import { DeleteRequest, FindAllOptions, PostRequest, TaskDeleteRequest, TaskPostRequest } from '../data/request.models';
|
||||||
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
|
import { HttpOptions } from '../dspace-rest-v2/dspace-rest-v2.service';
|
||||||
|
import { ProcessTaskResponse } from './models/process-task-response';
|
||||||
|
import { RemoteDataError } from '../data/remote-data-error';
|
||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
import { getResponseFromEntry } from '../shared/operators';
|
||||||
|
import { ErrorResponse, MessageResponse, RestResponse } from '../cache/response.models';
|
||||||
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
|
||||||
|
export abstract class TasksService<TNormalized extends NormalizedObject, TDomain extends CacheableObject> extends DataService<TNormalized, TDomain> {
|
||||||
|
|
||||||
|
public getBrowseEndpoint(options: FindAllOptions): Observable<string> {
|
||||||
|
return this.halService.getEndpoint(this.linkPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fetchRequest(requestId: string): Observable<ProcessTaskResponse> {
|
||||||
|
const responses = this.requestService.getByUUID(requestId).pipe(
|
||||||
|
getResponseFromEntry()
|
||||||
|
);
|
||||||
|
const errorResponses = responses.pipe(
|
||||||
|
filter((response: RestResponse) => !response.isSuccessful),
|
||||||
|
mergeMap((response: ErrorResponse) => observableOf(
|
||||||
|
new ProcessTaskResponse(
|
||||||
|
response.isSuccessful,
|
||||||
|
new RemoteDataError(response.statusCode, response.statusText, response.errorMessage)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
const successResponses = responses.pipe(
|
||||||
|
filter((response: RestResponse) => response.isSuccessful),
|
||||||
|
map((response: MessageResponse) => new ProcessTaskResponse(response.isSuccessful)),
|
||||||
|
distinctUntilChanged()
|
||||||
|
);
|
||||||
|
return observableMerge(errorResponses, successResponses);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getEndpointByIDHref(endpoint, resourceID): string {
|
||||||
|
return isNotEmpty(resourceID) ? `${endpoint}/${resourceID}` : `${endpoint}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getEndpointByMethod(endpoint: string, method: string): string {
|
||||||
|
return isNotEmpty(method) ? `${endpoint}/${method}` : `${endpoint}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public postToEndpoint(linkPath: string, body: any, scopeId?: string, options?: HttpOptions): Observable<ProcessTaskResponse> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
return this.halService.getEndpoint(linkPath).pipe(
|
||||||
|
filter((href: string) => isNotEmpty(href)),
|
||||||
|
map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId)),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) => new TaskPostRequest(requestId, endpointURL, body, options)),
|
||||||
|
tap((request: PostRequest) => this.requestService.configure(request)),
|
||||||
|
flatMap((request: PostRequest) => this.fetchRequest(requestId)),
|
||||||
|
distinctUntilChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteById(linkName: string, scopeId: string, options?: HttpOptions): Observable<ProcessTaskResponse> {
|
||||||
|
const requestId = this.requestService.generateRequestId();
|
||||||
|
return this.halService.getEndpoint(linkName || this.linkPath).pipe(
|
||||||
|
filter((href: string) => isNotEmpty(href)),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((endpointURL: string) => this.getEndpointByIDHref(endpointURL, scopeId)),
|
||||||
|
map((endpointURL: string) => new TaskDeleteRequest(requestId, endpointURL, null, options)),
|
||||||
|
tap((request: DeleteRequest) => this.requestService.configure(request)),
|
||||||
|
flatMap((request: DeleteRequest) => this.fetchRequest(requestId)),
|
||||||
|
distinctUntilChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected makeHttpOptions() {
|
||||||
|
const options: HttpOptions = Object.create({});
|
||||||
|
let headers = new HttpHeaders();
|
||||||
|
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
options.headers = headers;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user