Fixed merge issues

This commit is contained in:
Giuseppe
2018-10-17 12:25:46 +02:00
parent 8bc7d31864
commit 7b483ce052
43 changed files with 295 additions and 209 deletions

View File

@@ -184,7 +184,7 @@ describe('BrowseService', () => {
scheduler.schedule(() => service.getBrowseItemsFor(browseDefinitions[1].id, mockAuthorName).subscribe());
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(expected);
expect(requestService.configure).toHaveBeenCalledWith(expected, undefined);
});
it('should call RemoteDataBuildService to create the RemoteData Observable', () => {

View File

@@ -13,6 +13,10 @@ import { NormalizedEPerson } from '../../eperson/models/normalized-eperson.model
import { NormalizedGroup } from '../../eperson/models/normalized-group.model';
import { NormalizedWorkflowItem } from '../../submission/models/normalized-workflowitem.model';
import { NormalizedBitstreamFormat } from './normalized-bitstream-format.model';
import { SubmissionResourceType } from '../../submission/submission-resource-type';
import { SubmissionDefinitionsModel } from '../../shared/config/config-submission-definitions.model';
import { SubmissionFormsModel } from '../../shared/config/config-submission-forms.model';
import { SubmissionSectionModel } from '../../shared/config/config-submission-section.model';
export class NormalizedObjectFactory {
public static getConstructor(type: ResourceType): GenericConstructor<NormalizedObject> {
@@ -53,6 +57,18 @@ export class NormalizedObjectFactory {
case ResourceType.BitstreamFormat: {
return NormalizedBitstreamFormat
}
case ResourceType.SubmissionDefinition:
case ResourceType.SubmissionDefinitions: {
return SubmissionDefinitionsModel
}
case ResourceType.SubmissionForm:
case ResourceType.SubmissionForms: {
return SubmissionFormsModel
}
case ResourceType.SubmissionSection:
case ResourceType.SubmissionSections: {
return SubmissionSectionModel
}
default: {
return undefined;
}

View File

@@ -28,9 +28,8 @@ export class NormalizedResourcePolicy extends NormalizedObject {
/**
* The uuid of the Group this Resource Policy applies to
*/
@relationship(ResourceType.Group, false)
@autoserializeAs(String, 'groupUUID')
group: string;
@autoserialize
groupUUID: string;
/**
* Identifier for this Resource Policy
@@ -46,4 +45,5 @@ export class NormalizedResourcePolicy extends NormalizedObject {
*/
@autoserializeAs(new IDToUUIDSerializer('resource-policy'), 'id')
uuid: string;
}

View File

@@ -11,6 +11,7 @@ import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafie
import { RegistryBitstreamformatsResponse } from '../registry/registry-bitstreamformats-response.model';
import { AuthStatus } from '../auth/models/auth-status.model';
import { NormalizedObject } from './models/normalized-object.model';
import { PaginatedList } from '../data/paginated-list';
/* tslint:disable:max-classes-per-file */
export class RestResponse {
@@ -160,7 +161,7 @@ export class ErrorResponse extends RestResponse {
export class ConfigSuccessResponse extends RestResponse {
constructor(
public configDefinition: ConfigObject[],
public configDefinition: ConfigObject,
public statusCode: number,
public statusText: string,
public pageInfo?: PageInfo
@@ -183,7 +184,7 @@ export class AuthStatusResponse extends RestResponse {
export class IntegrationSuccessResponse extends RestResponse {
constructor(
public dataDefinition: IntegrationModel[],
public dataDefinition: PaginatedList<IntegrationModel>,
public statusCode: number,
public statusText: string,
public pageInfo?: PageInfo
@@ -194,7 +195,7 @@ export class IntegrationSuccessResponse extends RestResponse {
export class PostPatchSuccessResponse extends RestResponse {
constructor(
public dataDefinition: any[],
public dataDefinition: any,
public statusCode: number,
public statusText: string,
public pageInfo?: PageInfo

View File

@@ -7,7 +7,7 @@ import { ConfigObject } from '../shared/config/config.model';
export class ConfigData {
constructor(
public pageInfo: PageInfo,
public payload: ConfigObject[]
public payload: ConfigObject
) {
}
}

View File

@@ -6,7 +6,6 @@ import { ObjectCacheService } from '../cache/object-cache.service';
import { GlobalConfig } from '../../../config/global-config.interface';
import { GenericConstructor } from '../shared/generic-constructor';
import { PaginatedList } from './paginated-list';
import { NormalizedObject } from '../cache/models/normalized-object.model';
import { ResourceType } from '../shared/resource-type';
import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
@@ -15,7 +14,7 @@ function isObjectLevel(halObj: any) {
}
function isPaginatedResponse(halObj: any) {
return isNotEmpty(halObj.page) && hasValue(halObj._embedded);
return hasValue(halObj.page) && hasValue(halObj._embedded);
}
/* tslint:disable:max-classes-per-file */
@@ -47,11 +46,11 @@ export abstract class BaseResponseParsingService {
if (isNotEmpty(parsedObj)) {
if (isPaginatedResponse(data._embedded[property])) {
object[property] = parsedObj;
object[property].page = parsedObj.page.map((obj) => obj.self);
object[property].page = parsedObj.page.map((obj) => this.retrieveObjectOrUrl(obj));
} else if (isObjectLevel(data._embedded[property])) {
object[property] = parsedObj.self;
object[property] = this.retrieveObjectOrUrl(parsedObj);
} else if (Array.isArray(parsedObj)) {
object[property] = parsedObj.map((obj) => obj.self)
object[property] = parsedObj.map((obj) => this.retrieveObjectOrUrl(obj))
}
}
});
@@ -65,8 +64,7 @@ export abstract class BaseResponseParsingService {
.filter((property) => data.hasOwnProperty(property))
.filter((property) => hasValue(data[property]))
.forEach((property) => {
const obj = this.process(data[property], requestHref);
result[property] = obj;
result[property] = this.process(data[property], requestHref);
});
return result;
@@ -101,8 +99,7 @@ export abstract class BaseResponseParsingService {
if (hasValue(normObjConstructor)) {
const serializer = new DSpaceRESTv2Serializer(normObjConstructor);
const res = serializer.deserialize(obj);
return res;
return serializer.deserialize(obj);
} else {
// TODO: move check to Validator?
// throw new Error(`The server returned an object with an unknown a known type: ${type}`);
@@ -150,6 +147,11 @@ export abstract class BaseResponseParsingService {
return obj[keys[0]];
}
protected retrieveObjectOrUrl(obj: any): any {
return this.toCache ? obj.self : obj;
// return obj.self;
}
// TODO Remove when https://jira.duraspace.org/browse/DS-4006 is fixed
// See https://github.com/DSpace/dspace-angular/issues/292
private fixBadEPersonRestResponse(obj: any): any {

View File

@@ -106,7 +106,8 @@ describe('BrowseItemsResponseParsingService', () => {
number: 0
}
},
statusCode: '200'
statusCode: 200,
statusText: 'OK'
} as DSpaceRESTV2Response;
const invalidResponseNotAList = {
@@ -142,11 +143,12 @@ describe('BrowseItemsResponseParsingService', () => {
}
}
},
statusCode: '200'
statusCode: 200,
statusText: 'OK'
} as DSpaceRESTV2Response;
const invalidResponseStatusCode = {
payload: {}, statusCode: '500'
payload: {}, statusCode: 500, statusText: 'Internal Server Error'
} as DSpaceRESTV2Response;
it('should return a GenericSuccessResponse if data contains a valid browse items response', () => {

View File

@@ -44,12 +44,12 @@ export class BrowseItemsResponseParsingService extends BaseResponseParsingServic
&& Array.isArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]])) {
const serializer = new DSpaceRESTv2Serializer(DSpaceObject);
const items = serializer.deserializeArray(data.payload._embedded[Object.keys(data.payload._embedded)[0]]);
return new GenericSuccessResponse(items, data.statusCode, this.processPageInfo(data.payload));
return new GenericSuccessResponse(items, data.statusCode, data.statusText, this.processPageInfo(data.payload));
} else {
return new ErrorResponse(
Object.assign(
new Error('Unexpected response from browse endpoint'),
{ statusText: data.statusCode }
{ statusCode: data.statusCode, statusText: data.statusText }
)
);
}

View File

@@ -9,6 +9,7 @@ import { CoreState } from '../core.reducers';
import { SubmissionDefinitionsModel } from '../shared/config/config-submission-definitions.model';
import { PaginatedList } from './paginated-list';
import { PageInfo } from '../shared/page-info.model';
import { SubmissionSectionModel } from '../shared/config/config-submission-section.model';
describe('ConfigResponseParsingService', () => {
let service: ConfigResponseParsingService;
@@ -176,10 +177,65 @@ describe('ConfigResponseParsingService', () => {
},
self: 'https://rest.api/config/submissiondefinitions/traditional',
sections: new PaginatedList(pageinfo, [
'https://rest.api/config/submissionsections/traditionalpageone',
'https://rest.api/config/submissionsections/traditionalpagetwo',
'https://rest.api/config/submissionsections/upload',
'https://rest.api/config/submissionsections/license'
Object.assign(new SubmissionSectionModel(), {
header: 'submit.progressbar.describe.stepone',
mandatory: true,
sectionType: 'submission-form',
visibility:{
main:null,
other:'READONLY'
},
type: 'submissionsection',
_links: {
self: 'https://rest.api/config/submissionsections/traditionalpageone',
config: 'https://rest.api/config/submissionforms/traditionalpageone'
},
self: 'https://rest.api/config/submissionsections/traditionalpageone',
}),
Object.assign(new SubmissionSectionModel(), {
header: 'submit.progressbar.describe.steptwo',
mandatory: true,
sectionType: 'submission-form',
visibility:{
main:null,
other:'READONLY'
},
type: 'submissionsection',
_links: {
self: 'https://rest.api/config/submissionsections/traditionalpagetwo',
config: 'https://rest.api/config/submissionforms/traditionalpagetwo'
},
self: 'https://rest.api/config/submissionsections/traditionalpagetwo',
}),
Object.assign(new SubmissionSectionModel(), {
header: 'submit.progressbar.upload',
mandatory: false,
sectionType: 'upload',
visibility:{
main:null,
other:'READONLY'
},
type: 'submissionsection',
_links: {
self: 'https://rest.api/config/submissionsections/upload',
config: 'https://rest.api/config/submissionuploads/upload'
},
self: 'https://rest.api/config/submissionsections/upload',
}),
Object.assign(new SubmissionSectionModel(), {
header: 'submit.progressbar.license',
mandatory: true,
sectionType: 'license',
visibility:{
main:null,
other:'READONLY'
},
type: 'submissionsection',
_links: {
self: 'https://rest.api/config/submissionsections/license'
},
self: 'https://rest.api/config/submissionsections/license',
})
])
});

View File

@@ -7,6 +7,7 @@ import { CoreState } from '../core.reducers';
import { Store } from '@ngrx/store';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { FindAllOptions } from './request.models';
import { SortOptions, SortDirection } from '../cache/models/sort-options.model';
@@ -17,6 +18,7 @@ class NormalizedTestObject extends NormalizedObject {
}
class TestService extends DataService<NormalizedTestObject, any> {
protected forceBypassCache = false;
constructor(
protected responseCache: ResponseCacheService,
protected requestService: RequestService,

View File

@@ -57,7 +57,7 @@ describe('DSpaceObjectDataService', () => {
scheduler.schedule(() => service.findById(testObject.uuid));
scheduler.flush();
expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestURL, testObject.uuid));
expect(requestService.configure).toHaveBeenCalledWith(new FindByIDRequest(requestUUID, requestURL, testObject.uuid), false);
});
it('should return a RemoteData<DSpaceObject> for the object with the given ID', () => {

View File

@@ -15,6 +15,7 @@ import { FindAllOptions } from './request.models';
/* tslint:disable:max-classes-per-file */
class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject> {
protected linkPath = 'dso';
protected forceBypassCache = false;
constructor(
protected responseCache: ResponseCacheService,

View File

@@ -1,7 +1,7 @@
import { Observable } from 'rxjs/Observable';
import { RequestService } from '../data/request.service';
import { ResponseCacheService } from '../cache/response-cache.service';
import { EpersonRequest } from '../data/request.models';
import { EpersonRequest, FindAllOptions } from '../data/request.models';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { NormalizedObject } from '../cache/models/normalized-object.model';
import { DataService } from '../data/data.service';
@@ -14,7 +14,7 @@ export abstract class EpersonService<TNormalized extends NormalizedObject, TDoma
protected abstract browseEndpoint: string;
protected abstract halService: HALEndpointService;
public getScopedEndpoint(scopeID: string): Observable<string> {
public getBrowseEndpoint(options: FindAllOptions): Observable<string> {
return this.halService.getEndpoint(this.linkPath);
}
}

View File

@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { filter, map, take } from 'rxjs/operators';
@@ -8,10 +9,9 @@ import { ResponseCacheService } from '../cache/response-cache.service';
import { RequestService } from '../data/request.service';
import { FindAllOptions } from '../data/request.models';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { NormalizedGroupModel } from './models/NormalizedGroup.model';
import { NormalizedGroup } from './models/normalized-group.model';
import { Group } from './models/group.model';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { Store } from '@ngrx/store';
import { CoreState } from '../core.reducers';
import { ObjectCacheService } from '../cache/object-cache.service';
import { SearchParam } from '../cache/models/search-param.model';
@@ -19,7 +19,7 @@ import { RemoteData } from '../data/remote-data';
import { PaginatedList } from '../data/paginated-list';
@Injectable()
export class GroupEpersonService extends EpersonService<NormalizedGroupModel, Group> {
export class GroupEpersonService extends EpersonService<NormalizedGroup, Group> {
protected linkPath = 'groups';
protected browseEndpoint = '';
protected forceBypassCache = false;

View File

@@ -3,10 +3,9 @@ import { CacheableObject } from '../../cache/object-cache.reducer';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { EPerson } from './eperson.model';
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { ResourceType } from '../../shared/resource-type';
import { mapsTo } from '../../cache/builders/build-decorators';
import { Group } from './group.model';
import { NormalizedGroupModel } from './NormalizedGroup.model';
import { NormalizedGroup } from './normalized-group.model';
@mapsTo(EPerson)
@inheritSerialization(NormalizedDSpaceObject)
@@ -15,7 +14,7 @@ export class NormalizedEPerson extends NormalizedDSpaceObject implements Cacheab
@autoserialize
public handle: string;
@autoserializeAs(NormalizedGroupModel)
@autoserializeAs(NormalizedGroup)
groups: Group[];
@autoserialize

View File

@@ -9,7 +9,7 @@ import { JsonPatchOperationPathObject } from './json-patch-operation-path-combin
import { Injectable } from '@angular/core';
import { isEmpty, isNotEmpty } from '../../../shared/empty.util';
import { dateToGMTString } from '../../../shared/date.util';
import { AuthorityValueModel } from '../../integration/models/authority-value.model';
import { AuthorityValue } from '../../integration/models/authority.value';
import { FormFieldMetadataValueObject } from '../../../shared/form/builder/models/form-field-metadata-value.model';
import { FormFieldLanguageValueObject } from '../../../shared/form/builder/models/form-field-language-value.model';
@@ -77,7 +77,7 @@ export class JsonPatchOperationsBuilder {
operationValue = value;
} else if (value instanceof Date) {
operationValue = new FormFieldMetadataValueObject(dateToGMTString(value));
} else if (value instanceof AuthorityValueModel) {
} else if (value instanceof AuthorityValue) {
operationValue = this.prepareAuthorityValue(value);
} else if (value instanceof FormFieldLanguageValueObject) {
operationValue = new FormFieldMetadataValueObject(value.value, value.language);

View File

@@ -5,6 +5,7 @@ import { RemoteData } from '../data/remote-data';
import { Observable } from 'rxjs/Observable';
import { License } from './license.model';
import { ResourcePolicy } from './resource-policy.model';
import { PaginatedList } from '../data/paginated-list';
export class Collection extends DSpaceObject {
@@ -66,7 +67,7 @@ export class Collection extends DSpaceObject {
/**
* The default access conditions of this Collection
*/
defaultAccessConditions: Observable<RemoteData<ResourcePolicy[]>>;
defaultAccessConditions: Observable<RemoteData<PaginatedList<ResourcePolicy>>>;
/**
* An array of Collections that are direct parents of this Collection

View File

@@ -10,7 +10,7 @@ export class SubmissionUploadsModel extends ConfigObject {
accessConditionOptions: AccessConditionOption[];
@autoserializeAs(SubmissionFormsModel)
metadata: SubmissionFormsModel[];
metadata: SubmissionFormsModel;
@autoserialize
required: boolean;

View File

@@ -1,12 +1,13 @@
import { autoserialize, autoserializeAs } from 'cerialize';
import { NormalizedObject } from '../../cache/models/normalized-object.model';
export abstract class ConfigObject {
export abstract class ConfigObject extends NormalizedObject{
@autoserialize
public name: string;
@autoserialize
public type: string;
public type: any;
@autoserialize
public _links: {

View File

@@ -18,9 +18,9 @@ export class ResourcePolicy implements CacheableObject {
name: string;
/**
* The Group this Resource Policy applies to
* The uuid of the Group this Resource Policy applies to
*/
group: Group;
groupUUID: string;
/**
* The link to the rest endpoint where this Resource Policy can be found

View File

@@ -12,4 +12,10 @@ export enum ResourceType {
License = 'license',
Workflowitem = 'workflowitem',
Workspaceitem = 'workspaceitem',
SubmissionDefinitions = 'submissiondefinitions',
SubmissionDefinition = 'submissiondefinition',
SubmissionForm = 'submissionform',
SubmissionForms = 'submissionforms',
SubmissionSections = 'submissionsections',
SubmissionSection = 'submissionsection',
}

View File

@@ -1,47 +1,10 @@
import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { NormalizedWorkspaceItem } from './normalized-workspaceitem.model';
import { inheritSerialization } from 'cerialize';
import { mapsTo } from '../../cache/builders/build-decorators';
import { NormalizedSubmissionObject } from './normalized-submission-object.model';
import { ResourceType } from '../../shared/resource-type';
import { SubmissionDefinitionsModel } from '../../shared/config/config-submission-definitions.model';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
import { SubmissionObjectError } from './submission-object.model';
import { EditItem } from './edititem.model';
@mapsTo(EditItem)
@inheritSerialization(NormalizedWorkspaceItem)
@inheritSerialization(NormalizedSubmissionObject)
export class NormalizedEditItem extends NormalizedSubmissionObject {
/**
* The item identifier
*/
@autoserialize
id: string;
/**
* The item last modified date
*/
@autoserialize
lastModified: Date;
@autoserialize
@relationship(ResourceType.Collection, true)
collection: string[];
@autoserialize
@relationship(ResourceType.Item, true)
item: string[];
@autoserialize
sections: WorkspaceitemSectionsObject;
@autoserializeAs(SubmissionDefinitionsModel)
submissionDefinition: SubmissionDefinitionsModel;
@autoserialize
@relationship(ResourceType.Eperson, true)
submitter: string[];
@autoserialize
errors: SubmissionObjectError[]
}

View File

@@ -1,8 +1,35 @@
import { autoserialize, inheritSerialization } from 'cerialize';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
import { SubmissionObjectError } from './submission-object.model';
/**
* An abstract model class for a DSpaceObject.
* An abstract model class for a NormalizedSubmissionObject.
*/
export abstract class NormalizedSubmissionObject extends NormalizedDSpaceObject {
@inheritSerialization(NormalizedDSpaceObject)
export class NormalizedSubmissionObject extends NormalizedDSpaceObject {
/**
* The workspaceitem/workflowitem identifier
*/
@autoserialize
id: string;
/**
* The workspaceitem/workflowitem last modified date
*/
@autoserialize
lastModified: Date;
/**
* The workspaceitem/workflowitem last sections data
*/
@autoserialize
sections: WorkspaceitemSectionsObject;
/**
* The workspaceitem/workflowitem last sections errors
*/
@autoserialize
errors: SubmissionObjectError[];
}

View File

@@ -1,47 +1,28 @@
import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
import { autoserialize, inheritSerialization } from 'cerialize';
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { Workflowitem } from './workflowitem.model';
import { NormalizedWorkspaceItem } from './normalized-workspaceitem.model';
import { NormalizedSubmissionObject } from './normalized-submission-object.model';
import { ResourceType } from '../../shared/resource-type';
import { SubmissionDefinitionsModel } from '../../shared/config/config-submission-definitions.model';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
import { SubmissionObjectError } from './submission-object.model';
@mapsTo(Workflowitem)
@inheritSerialization(NormalizedWorkspaceItem)
@inheritSerialization(NormalizedSubmissionObject)
export class NormalizedWorkflowItem extends NormalizedSubmissionObject {
/**
* The workspaceitem identifier
*/
@autoserialize
id: string;
/**
* The workspaceitem last modified date
*/
@autoserialize
lastModified: Date;
@relationship(ResourceType.Collection, false)
collection: string;
@autoserialize
@relationship(ResourceType.Collection, true)
collection: string[];
@relationship(ResourceType.Item, false)
item: string;
@autoserialize
@relationship(ResourceType.Item, true)
item: string[];
@relationship(ResourceType.SubmissionDefinition, false)
submissionDefinition: string;
@autoserialize
sections: WorkspaceitemSectionsObject;
@relationship(ResourceType.EPerson, false)
submitter: string;
@autoserializeAs(SubmissionDefinitionsModel)
submissionDefinition: SubmissionDefinitionsModel;
@autoserialize
@relationship(ResourceType.Eperson, true)
submitter: string[];
@autoserialize
errors: SubmissionObjectError[]
}

View File

@@ -1,51 +1,29 @@
import { autoserialize, autoserializeAs, inheritSerialization } from 'cerialize';
import { autoserialize, inheritSerialization } from 'cerialize';
import { Workspaceitem } from './workspaceitem.model';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
import { NormalizedSubmissionObject } from './normalized-submission-object.model';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { mapsTo, relationship } from '../../cache/builders/build-decorators';
import { NormalizedCollection } from '../../cache/models/normalized-collection.model';
import { NormalizedDSpaceObject } from '../../cache/models/normalized-dspace-object.model';
import { ResourceType } from '../../shared/resource-type';
import { SubmissionDefinitionsModel } from '../../shared/config/config-submission-definitions.model';
import { Eperson } from '../../eperson/models/eperson.model';
import { SubmissionObjectError } from './submission-object.model';
@mapsTo(Workspaceitem)
@inheritSerialization(NormalizedDSpaceObject)
@inheritSerialization(NormalizedSubmissionObject)
export class NormalizedWorkspaceItem extends NormalizedSubmissionObject {
/**
* The workspaceitem identifier
*/
@autoserialize
id: string;
/**
* The workspaceitem last modified date
*/
@autoserialize
lastModified: Date;
@relationship(ResourceType.Collection, false)
collection: string;
@autoserialize
@relationship(ResourceType.Collection, true)
collection: string[];
@relationship(ResourceType.Item, false)
item: string;
@autoserialize
@relationship(ResourceType.Item, true)
item: string[];
@relationship(ResourceType.SubmissionDefinition, false)
submissionDefinition: string;
@autoserialize
sections: WorkspaceitemSectionsObject;
@autoserializeAs(SubmissionDefinitionsModel)
submissionDefinition: SubmissionDefinitionsModel;
@autoserialize
@relationship(ResourceType.Eperson, true)
submitter: string[];
@autoserialize
errors: SubmissionObjectError[]
@relationship(ResourceType.EPerson, false)
submitter: string;
}

View File

@@ -1,12 +1,13 @@
import { Observable } from 'rxjs/Observable';
import { CacheableObject } from '../../cache/object-cache.reducer';
import { ListableObject } from '../../../shared/object-collection/shared/listable-object.model';
import { DSpaceObject } from '../../shared/dspace-object.model';
import { Eperson } from '../../eperson/models/eperson.model';
import { EPerson } from '../../eperson/models/eperson.model';
import { RemoteData } from '../../data/remote-data';
import { Collection } from '../../shared/collection.model';
import { Item } from '../../shared/item.model';
import { SubmissionDefinitionsModel } from '../../shared/config/config-submission-definitions.model';
import { Observable } from 'rxjs/Observable';
import { WorkspaceitemSectionsObject } from './workspaceitem-sections.model';
export interface SubmissionObjectError {
@@ -15,29 +16,47 @@ export interface SubmissionObjectError {
}
/**
* An abstract model class for a DSpaceObject.
* An abstract model class for a SubmissionObject.
*/
export abstract class SubmissionObject extends DSpaceObject implements CacheableObject, ListableObject {
/**
* The workspaceitem identifier
* The workspaceitem/workflowitem identifier
*/
id: string;
/**
* The workspaceitem last modified date
* The workspaceitem/workflowitem last modified date
*/
lastModified: Date;
collection: Observable<RemoteData<Collection[]>> | Collection[];
/**
* The collection this submission applies to
*/
collection: Observable<RemoteData<Collection>> | Collection;
item: Observable<RemoteData<Item[]>> | Item[];
/**
* The submission item
*/
item: Observable<RemoteData<Item>> | Item;
/**
* The workspaceitem/workflowitem last sections data
*/
sections: WorkspaceitemSectionsObject;
/**
* The submission config definition
*/
submissionDefinition: SubmissionDefinitionsModel;
submitter: Observable<RemoteData<Eperson[]>> | Eperson[];
/**
* The workspaceitem submitter
*/
submitter: Observable<RemoteData<EPerson>> | EPerson;
/**
* The workspaceitem/workflowitem last sections errors
*/
errors: SubmissionObjectError[];
}

View File

@@ -15,6 +15,9 @@ import { SubmissionResourceType } from './submission-resource-type';
import { NormalizedResourcePolicy } from '../cache/models/normalized-resource-policy.model';
import { NormalizedWorkflowItem } from './models/normalized-workflowitem.model';
import { NormalizedEditItem } from './models/normalized-edititem.model';
import { ResourceType } from '../shared/resource-type';
import { NormalizedEPerson } from '../eperson/models/normalized-eperson.model';
import { NormalizedGroup } from '../eperson/models/normalized-group.model';
export class NormalizedSubmissionObjectFactory {
public static getConstructor(type: SubmissionResourceType): GenericConstructor<NormalizedObject | ConfigObject> {
@@ -40,6 +43,12 @@ export class NormalizedSubmissionObjectFactory {
case SubmissionResourceType.License: {
return NormalizedLicense
}
case SubmissionResourceType.EPerson: {
return NormalizedEPerson
}
case SubmissionResourceType.Group: {
return NormalizedGroup
}
case SubmissionResourceType.WorkspaceItem: {
return NormalizedWorkspaceItem
}

View File

@@ -9,8 +9,10 @@ export enum SubmissionResourceType {
Item = 'item',
Collection = 'collection',
Community = 'community',
ResourcePolicy = 'resourcePolicies',
ResourcePolicy = 'resourcePolicy',
License = 'license',
EPerson = 'eperson',
Group = 'group',
WorkspaceItem = 'workspaceitem',
WorkflowItem = 'workflowitem',
EditItem = 'edititem',

View File

@@ -7,7 +7,7 @@ import { ErrorResponse, RestResponse, SubmissionSuccessResponse } from '../cache
import { isEmpty, isNotEmpty, isNotNull } from '../../shared/empty.util';
import { ConfigObject } from '../shared/config/config.model';
import { BaseResponseParsingService, ProcessRequestDTO } from '../data/base-response-parsing.service';
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';
@@ -18,6 +18,9 @@ import { NormalizedWorkspaceItem } from './models/normalized-workspaceitem.model
import { normalizeSectionData } from './models/workspaceitem-sections.model';
import { NormalizedWorkflowItem } from './models/normalized-workflowitem.model';
import { NormalizedEditItem } from './models/normalized-edititem.model';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { NormalizedSubmissionObject } from './models/normalized-submission-object.model';
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
@Injectable()
export class SubmissionResponseParsingService extends BaseResponseParsingService implements ResponseParsingService {
@@ -26,7 +29,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
protected toCache = false;
constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
protected objectCache: ObjectCacheService,) {
protected objectCache: ObjectCacheService) {
super();
}
@@ -35,7 +38,7 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
&& isNotEmpty(data.payload._links)
&& (data.statusCode === 201 || data.statusCode === 200)) {
const dataDefinition = this.processResponse<NormalizedObject | ConfigObject, SubmissionResourceType>(data.payload, request.href);
return new SubmissionSuccessResponse(dataDefinition[Object.keys(dataDefinition)[0]], data.statusCode, data.statusText, this.processPageInfo(data.payload));
return new SubmissionSuccessResponse(dataDefinition, data.statusCode, data.statusText, this.processPageInfo(data.payload));
} else if (isEmpty(data.payload) && data.statusCode === 204) {
// Response from a DELETE request
return new SubmissionSuccessResponse(null, data.statusCode, data.statusText);
@@ -49,11 +52,13 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
}
}
protected processResponse<ObjectDomain, ObjectType>(data: any, requestHref: string): ProcessRequestDTO<ObjectDomain> {
protected processResponse<ObjectDomain, ObjectType>(data: any, requestHref: string): any[] {
const dataDefinition = this.process<NormalizedObject | ConfigObject, SubmissionResourceType>(data, requestHref);
const normalizedDefinition = Object.create({});
normalizedDefinition[Object.keys(dataDefinition)[0]] = [];
dataDefinition[Object.keys(dataDefinition)[0]].forEach((item, index) => {
const normalizedDefinition = Array.of();
const processedList = Array.isArray(dataDefinition) ? dataDefinition : Array.of(dataDefinition);
processedList.forEach((item, index) => {
let normalizedItem = Object.assign({}, item);
// In case data is an Instance of NormalizedWorkspaceItem normalize field value of all the section of type form
if (item instanceof NormalizedWorkspaceItem
@@ -90,10 +95,10 @@ export class SubmissionResponseParsingService extends BaseResponseParsingService
normalizedItem = Object.assign({}, item, {sections: precessedSection});
}
}
normalizedDefinition[Object.keys(dataDefinition)[0]][index] = normalizedItem;
normalizedDefinition.push( normalizedItem);
});
return normalizedDefinition as ProcessRequestDTO<ObjectDomain>;
return normalizedDefinition;
}
}

View File

@@ -12,6 +12,7 @@ import { RequestService } from '../data/request.service';
import { NormalizedWorkflowItem } from './models/normalized-workflowitem.model';
import { Workflowitem } from './models/workflowitem.model';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { FindAllOptions } from '../data/request.models';
@Injectable()
export class WorkflowitemDataService extends DataService<NormalizedWorkflowItem, Workflowitem> {
@@ -28,7 +29,7 @@ export class WorkflowitemDataService extends DataService<NormalizedWorkflowItem,
super();
}
public getScopedEndpoint(scopeID: string): Observable<string> {
public getBrowseEndpoint(options: FindAllOptions) {
return this.halService.getEndpoint(this.linkPath);
}

View File

@@ -12,6 +12,7 @@ import { RequestService } from '../data/request.service';
import { Workspaceitem } from './models/workspaceitem.model';
import { NormalizedWorkspaceItem } from './models/normalized-workspaceitem.model';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { FindAllOptions } from '../data/request.models';
@Injectable()
export class WorkspaceitemDataService extends DataService<NormalizedWorkspaceItem, Workspaceitem> {
@@ -28,7 +29,7 @@ export class WorkspaceitemDataService extends DataService<NormalizedWorkspaceIte
super();
}
public getScopedEndpoint(scopeID: string): Observable<string> {
public getBrowseEndpoint(options: FindAllOptions) {
return this.halService.getEndpoint(this.linkPath);
}

View File

@@ -1,4 +1,4 @@
<div *ngIf="!dismissed" class="alert {{type}} alert-dismissible fade show" role="alert" [@enterLeave]="animate">
<div *ngIf="!dismissed" class="alert {{type}} alert-dismissible fade show w-100" role="alert" [@enterLeave]="animate">
<span *ngIf="content" [innerHTML]="content | translate"></span>
<ng-content></ng-content>

View File

@@ -10,6 +10,7 @@ import { SubmissionService } from '../submission.service';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
import { Collection } from '../../core/shared/collection.model';
@Component({
selector: 'ds-submission-edit',
@@ -51,10 +52,10 @@ export class SubmissionEditComponent implements OnDestroy, OnInit {
this.notificationsService.info(null, this.translate.get('submission.general.cannot_submit'));
this.router.navigate(['/mydspace']);
} else {
this.collectionId = submissionObject.collection[0].id;
this.collectionId = (submissionObject.collection as Collection).id;
this.selfUrl = submissionObject.self;
this.sections = submissionObject.sections;
this.submissionDefinition = submissionObject.submissionDefinition[0];
this.submissionDefinition = (submissionObject.submissionDefinition as SubmissionDefinitionsModel);
this.changeDetectorRef.detectChanges();
}
}

View File

@@ -93,9 +93,9 @@ export class SubmissionFormCollectionComponent implements OnChanges, OnInit {
.subscribe((communityData: Community) => {
this.subs.push(communityData.collections
.filter((collections: RemoteData<Collection[]>) => !collections.isResponsePending && collections.hasSucceeded)
.filter((collections: RemoteData<PaginatedList<Collection>>) => !collections.isResponsePending && collections.hasSucceeded)
.first()
.switchMap((collections: RemoteData<Collection[]>) => collections.payload)
.switchMap((collections: RemoteData<PaginatedList<Collection>>) => collections.payload.page)
.filter((collectionData: Collection) => isNotEmpty(collectionData))
.subscribe((collectionData: Collection) => {
if (collectionData.id === this.selectedCollectionId) {

View File

@@ -11,6 +11,8 @@ import { Observable } from 'rxjs/Observable';
import { SectionDataObject } from '../sections/models/section-data.model';
import { UploaderOptions } from '../../shared/uploader/uploader-options.model';
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
import { Collection } from '../../core/shared/collection.model';
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
@Component({
selector: 'ds-submission-submit-form',
@@ -99,16 +101,16 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
.forEach((subscription) => subscription.unsubscribe());
}
onCollectionChange(workspaceItemObject: Workspaceitem) {
this.collectionId = workspaceItemObject.collection[0].id;
if (this.definitionId !== workspaceItemObject.submissionDefinition[0].name) {
this.sections = workspaceItemObject.sections;
this.submissionDefinition = workspaceItemObject.submissionDefinition[0];
onCollectionChange(submissionObject: SubmissionObject) {
this.collectionId = (submissionObject.collection as Collection).id;
if (this.definitionId !== submissionObject.submissionDefinition.name) {
this.sections = submissionObject.sections;
this.submissionDefinition = submissionObject.submissionDefinition;
this.definitionId = this.submissionDefinition.name;
this.submissionService.resetSubmissionObject(
this.collectionId,
this.submissionId,
workspaceItemObject.self,
submissionObject.self,
this.submissionDefinition,
this.sections);
} else {
@@ -117,7 +119,6 @@ export class SubmissionFormComponent implements OnChanges, OnDestroy {
}
isLoading(): Observable<boolean> {
// return isUndefined(this.loading) || this.loading === true;
return this.loading;
}

View File

@@ -54,7 +54,7 @@ export class SubmissionObjectEffects {
.map((action: InitSubmissionFormAction) => {
const definition = action.payload.submissionDefinition;
const mappedActions = [];
definition.sections.forEach((sectionDefinition: SubmissionSectionModel, index: number) => {
definition.sections.page.forEach((sectionDefinition: SubmissionSectionModel, index: number) => {
const sectionId = sectionDefinition._links.self.substr(sectionDefinition._links.self.lastIndexOf('/') + 1);
const config = sectionDefinition._links.config || '';
const enabled = (sectionDefinition.mandatory && sectionDefinition.sectionType !== SectionsType.DetectDuplicate) || (isNotEmpty(action.payload.sections) && action.payload.sections.hasOwnProperty(sectionId));

View File

@@ -8,3 +8,10 @@
border-radius: $border-radius;
box-shadow: $btn-focus-box-shadow;
}
// TODO to remove the following when upgrading @ng-bootstrap
:host /deep/ .card:first-of-type {
border-bottom: $card-border-width solid $card-border-color !important;
border-bottom-left-radius: $card-border-radius !important;
border-bottom-right-radius: $card-border-radius !important;
}

View File

@@ -1,7 +1,7 @@
<ds-item-list-preview
<!--<ds-item-list-preview
[item]="item"
[object]="object"
></ds-item-list-preview>
></ds-item-list-preview>-->
<div *ngIf="isWorkFlow" class="mt-2">
<form>

View File

@@ -71,7 +71,7 @@ export class FormSectionComponent extends SectionModelComponent implements OnDes
this.formId = this.formService.getUniqueId(this.sectionData.id);
this.formConfigService.getConfigByHref(this.sectionData.config)
.flatMap((config: ConfigData) => config.payload)
.map((config: ConfigData) => config.payload)
.subscribe((config: SubmissionFormsModel) => {
this.formConfig = config;
this.sectionService.getSectionData(this.submissionId, this.sectionData.id)

View File

@@ -19,6 +19,10 @@ import { RemoteData } from '../../../core/data/remote-data';
import { Group } from '../../../core/eperson/models/group.model';
import { SectionsService } from '../sections.service';
import { SubmissionService } from '../../submission.service';
import { Collection } from '../../../core/shared/collection.model';
import { PaginatedList } from '../../../core/data/paginated-list';
import { ResourcePolicy } from '../../../core/shared/resource-policy.model';
import { AccessConditionOption } from '../../../core/shared/config/config-access-condition-option.model';
export const POLICY_DEFAULT_NO_LIST = 1; // Banner1
export const POLICY_DEFAULT_WITH_LIST = 2; // Banner2
@@ -53,7 +57,7 @@ export class UploadSectionComponent extends SectionModelComponent implements OnD
/*
* List of available access conditions that could be setted to files
*/
public availableAccessConditionOptions: any[]; // List of accessConditions that an user can select
public availableAccessConditionOptions: AccessConditionOption[]; // List of accessConditions that an user can select
/*
* List of Groups available for every access condition
@@ -76,11 +80,11 @@ export class UploadSectionComponent extends SectionModelComponent implements OnD
onSectionInit() {
const config$ = this.uploadsConfigService.getConfigByHref(this.sectionData.config)
.flatMap((config) => config.payload);
.map((config) => config.payload);
this.configMetadataForm$ = config$
.take(1)
.map((config: SubmissionUploadsModel) => config.metadata[0]);
.map((config: SubmissionUploadsModel) => config.metadata);
this.subs.push(
this.submissionService.getSubmissionObject(this.submissionId)
@@ -89,26 +93,28 @@ export class UploadSectionComponent extends SectionModelComponent implements OnD
.subscribe((submissionObject: SubmissionObjectEntry) => {
this.collectionId = submissionObject.collection;
this.collectionDataService.findById(this.collectionId)
.filter((collectionData) => isNotUndefined((collectionData.payload)))
.filter((rd: RemoteData<Collection>) => isNotUndefined((rd.payload)))
.take(1)
.subscribe((collectionData) => {
this.collectionName = collectionData.payload.name;
.subscribe((collectionRemoteData: RemoteData<Collection>) => {
this.collectionName = collectionRemoteData.payload.name;
// Default Access Conditions
this.subs.push(collectionData.payload.defaultAccessConditions
.filter((accessConditions) => isNotUndefined((accessConditions.payload)))
this.subs.push(collectionRemoteData.payload.defaultAccessConditions
.filter((defaultAccessConditionsRemoteData: RemoteData<PaginatedList<ResourcePolicy>>) =>
defaultAccessConditionsRemoteData.hasSucceeded)
.take(1)
.subscribe((defaultAccessConditions) => {
.subscribe((defaultAccessConditionsRemoteData: RemoteData<PaginatedList<ResourcePolicy>>) => {
if (isNotEmpty(defaultAccessConditions.payload)) {
this.collectionDefaultAccessConditions = Array.isArray(defaultAccessConditions.payload)
? defaultAccessConditions.payload : [defaultAccessConditions.payload];
if (isNotEmpty(defaultAccessConditionsRemoteData.payload)) {
this.collectionDefaultAccessConditions = Array.isArray(defaultAccessConditionsRemoteData.payload.page)
? defaultAccessConditionsRemoteData.payload.page : [defaultAccessConditionsRemoteData.payload.page];
}
// Edit Form Configuration, access policy list
this.subs.push(config$
.take(1)
.subscribe((config: SubmissionUploadsModel) => {
this.availableAccessConditionOptions = isNotEmpty(config.accessConditionOptions) ? config.accessConditionOptions : [];
this.collectionPolicyType = this.availableAccessConditionOptions.length > 0
@@ -118,7 +124,7 @@ export class UploadSectionComponent extends SectionModelComponent implements OnD
this.availableGroups = new Map();
const groupsObs = [];
// Retrieve Groups for accessConditionPolicies
this.availableAccessConditionOptions.forEach((accessCondition) => {
this.availableAccessConditionOptions.forEach((accessCondition: AccessConditionOption) => {
if (accessCondition.hasEndDate === true || accessCondition.hasStartDate === true) {
groupsObs.push(
this.groupService.findById(accessCondition.groupUUID)

View File

@@ -5,12 +5,7 @@ import { Store } from '@ngrx/store';
import { ResponseCacheService } from '../core/cache/response-cache.service';
import { RequestService } from '../core/data/request.service';
import { ResponseCacheEntry } from '../core/cache/response-cache.reducer';
import {
ErrorResponse,
PostPatchSuccessResponse,
RestResponse,
SubmissionSuccessResponse
} from '../core/cache/response-cache.models';
import { ErrorResponse, RestResponse, SubmissionSuccessResponse } from '../core/cache/response-cache.models';
import { isNotEmpty } from '../shared/empty.util';
import {
ConfigRequest,
@@ -26,12 +21,14 @@ import { SubmitDataResponseDefinitionObject } from '../core/shared/submit-data-r
import { CoreState } from '../core/core.reducers';
import { HttpOptions } from '../core/dspace-rest-v2/dspace-rest-v2.service';
import { HALEndpointService } from '../core/shared/hal-endpoint.service';
import { RemoteDataBuildService } from '../core/cache/builders/remote-data-build.service';
@Injectable()
export class SubmissionRestService {
protected linkPath = 'workspaceitems';
constructor(
protected rdbService: RemoteDataBuildService,
protected responseCache: ResponseCacheService,
protected requestService: RequestService,
protected store: Store<CoreState>,
@@ -46,8 +43,8 @@ export class SubmissionRestService {
errorResponse.flatMap((response: ErrorResponse) =>
Observable.throw(new Error(`Couldn't send data to server`))),
successResponse
.filter((response: PostPatchSuccessResponse) => isNotEmpty(response))
.map((response: PostPatchSuccessResponse) => response.dataDefinition)
.filter((response: SubmissionSuccessResponse) => isNotEmpty(response))
.map((response: SubmissionSuccessResponse) => response.dataDefinition)
.distinctUntilChanged());
}

View File

@@ -60,7 +60,7 @@ export class SubmissionService {
createSubmission(): Observable<SubmissionObject> {
return this.restService.postToEndpoint('workspaceitems', {})
.map((workspaceitems) => workspaceitems[0])
.map((workspaceitem: SubmissionObject) => workspaceitem[0])
.catch(() => Observable.of({}))
}

View File

@@ -9,6 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { SubmissionService } from '../submission.service';
import { SubmissionObject } from '../../core/submission/models/submission-object.model';
import { Collection } from '../../core/shared/collection.model';
@Component({
selector: 'ds-submit-page',
@@ -44,9 +45,9 @@ export class SubmissionSubmitComponent implements OnDestroy, OnInit {
this.notificationsService.info(null, this.translate.get('submission.general.cannot_submit'));
this.router.navigate(['/mydspace']);
} else {
this.collectionId = submissionObject.collection[0].id;
this.collectionId = (submissionObject.collection as Collection).id;
this.selfUrl = submissionObject.self;
this.submissionDefinition = submissionObject.submissionDefinition[0];
this.submissionDefinition = (submissionObject.submissionDefinition as SubmissionDefinitionsModel);
this.submissionId = submissionObject.id;
this.changeDetectorRef.detectChanges();
}