Skip to content

Commit

Permalink
Merge pull request #508 from atmire/refactor-submission-parsers
Browse files Browse the repository at this point in the history
Refactor Submission Parsers
  • Loading branch information
tdonohue committed Dec 3, 2019
2 parents 6e0bd0c + 7474c0a commit 33972cb
Show file tree
Hide file tree
Showing 32 changed files with 476 additions and 150 deletions.
95 changes: 95 additions & 0 deletions src/app/core/submission/submission-object-data.service.spec.ts
@@ -0,0 +1,95 @@
import { Observable } from 'rxjs';
import { SubmissionService } from '../../submission/submission.service';
import { RemoteData } from '../data/remote-data';
import { SubmissionObject } from './models/submission-object.model';
import { WorkspaceItem } from './models/workspaceitem.model';
import { SubmissionObjectDataService } from './submission-object-data.service';
import { SubmissionScopeType } from './submission-scope-type';
import { WorkflowItemDataService } from './workflowitem-data.service';
import { WorkspaceitemDataService } from './workspaceitem-data.service';

describe('SubmissionObjectDataService', () => {
let service: SubmissionObjectDataService;
let submissionService: SubmissionService;
let workspaceitemDataService: WorkspaceitemDataService;
let workflowItemDataService: WorkflowItemDataService;

const submissionId = '1234';
const wsiResult = 'wsiResult' as any;
const wfiResult = 'wfiResult' as any;

beforeEach(() => {
workspaceitemDataService = jasmine.createSpyObj('WorkspaceitemDataService', {
findById: wsiResult
});
workflowItemDataService = jasmine.createSpyObj('WorkflowItemDataService', {
findById: wfiResult
});
});

describe('findById', () => {
it('should call SubmissionService.getSubmissionScope to determine the type of submission object', () => {
submissionService = jasmine.createSpyObj('SubmissionService', {
getSubmissionScope: {}
});
service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
service.findById(submissionId);
expect(submissionService.getSubmissionScope).toHaveBeenCalled();
});

describe('when the submission ID refers to a WorkspaceItem', () => {
beforeEach(() => {
submissionService = jasmine.createSpyObj('SubmissionService', {
getSubmissionScope: SubmissionScopeType.WorkspaceItem
});
service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
});

it('should forward the result of WorkspaceitemDataService.findById()', () => {
const result = service.findById(submissionId);
expect(workspaceitemDataService.findById).toHaveBeenCalledWith(submissionId);
expect(result).toBe(wsiResult);
});
});

describe('when the submission ID refers to a WorkflowItem', () => {
beforeEach(() => {
submissionService = jasmine.createSpyObj('SubmissionService', {
getSubmissionScope: SubmissionScopeType.WorkflowItem
});
service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
});

it('should forward the result of WorkflowItemDataService.findById()', () => {
const result = service.findById(submissionId);
expect(workflowItemDataService.findById).toHaveBeenCalledWith(submissionId);
expect(result).toBe(wfiResult);
});
});

describe('when the type of submission object is unknown', () => {
beforeEach(() => {
submissionService = jasmine.createSpyObj('SubmissionService', {
getSubmissionScope: 'Something else'
});
service = new SubmissionObjectDataService(workspaceitemDataService, workflowItemDataService, submissionService);
});

it('shouldn\'t call any data service methods', () => {
service.findById(submissionId);
expect(workspaceitemDataService.findById).not.toHaveBeenCalled();
expect(workflowItemDataService.findById).not.toHaveBeenCalled();
});

it('should return a RemoteData containing an error', (done) => {
const result = service.findById(submissionId);
result.subscribe((rd: RemoteData<SubmissionObject>) => {
expect(rd.hasFailed).toBe(true);
expect(rd.error).toBeDefined();
done();
})
});
});

});
});
46 changes: 46 additions & 0 deletions src/app/core/submission/submission-object-data.service.ts
@@ -0,0 +1,46 @@
import { Injectable } from '@angular/core';
import { of as observableOf, Observable } from 'rxjs';
import { SubmissionService } from '../../submission/submission.service';
import { RemoteData } from '../data/remote-data';
import { RemoteDataError } from '../data/remote-data-error';
import { SubmissionObject } from './models/submission-object.model';
import { SubmissionScopeType } from './submission-scope-type';
import { WorkflowItemDataService } from './workflowitem-data.service';
import { WorkspaceitemDataService } from './workspaceitem-data.service';

/**
* A service to retrieve submission objects (WorkspaceItem/WorkflowItem)
* without knowing their type
*/
@Injectable({
providedIn: 'root'
})
export class SubmissionObjectDataService {
constructor(
private workspaceitemDataService: WorkspaceitemDataService,
private workflowItemDataService: WorkflowItemDataService,
private submissionService: SubmissionService
) {
}

/**
* Retrieve a submission object based on its ID.
*
* @param id The identifier of a submission object
*/
findById(id: string): Observable<RemoteData<SubmissionObject>> {
switch (this.submissionService.getSubmissionScope()) {
case SubmissionScopeType.WorkspaceItem:
return this.workspaceitemDataService.findById(id);
case SubmissionScopeType.WorkflowItem:
return this.workflowItemDataService.findById(id);
default:
const error = new RemoteDataError(
undefined,
undefined,
'The request couldn\'t be sent. Unable to determine the type of submission object'
);
return observableOf(new RemoteData(false, false, false, error, undefined));
}
}
}
Expand Up @@ -112,6 +112,7 @@ describe('DsDynamicFormControlContainerComponent test suite', () => {
repeatable: false
}),
new DynamicRelationGroupModel({
submissionId: '1234',
id: 'relationGroup',
formConfiguration: [],
mandatoryField: '',
Expand Down
Expand Up @@ -33,6 +33,8 @@ export let FORM_GROUP_TEST_GROUP;

const config: GlobalConfig = MOCK_SUBMISSION_CONFIG;

const submissionId = '1234';

function init() {
FORM_GROUP_TEST_MODEL_CONFIG = {
disabled: false,
Expand Down Expand Up @@ -67,6 +69,7 @@ function init() {
}]
} as FormFieldModel]
} as FormRowModel],
submissionId,
id: 'dc_contributor_author',
label: 'Authors',
mandatoryField: 'dc.contributor.author',
Expand Down Expand Up @@ -183,7 +186,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {

it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const formModel = service.modelFromConfiguration(submissionId, formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips([], 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(false);
Expand Down Expand Up @@ -257,7 +260,7 @@ describe('DsDynamicRelationGroupComponent test suite', () => {

it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const formConfig = { rows: groupComp.model.formConfiguration } as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const formModel = service.modelFromConfiguration(submissionId, formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
groupComp.formCollapsed.subscribe((value) => {
expect(value).toEqual(true);
Expand Down
Expand Up @@ -93,6 +93,7 @@ export class DsDynamicRelationGroupComponent extends DynamicFormControlComponent

this.formId = this.formService.getUniqueId(this.model.id);
this.formModel = this.formBuilderService.modelFromConfiguration(
this.model.submissionId,
config,
this.model.scopeUUID,
{},
Expand Down
Expand Up @@ -10,6 +10,7 @@ export const PLACEHOLDER_PARENT_METADATA = '#PLACEHOLDER_PARENT_METADATA_VALUE#'
* Dynamic Group Model configuration interface
*/
export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConfig {
submissionId: string,
formConfiguration: FormRowModel[],
mandatoryField: string,
relationFields: string[],
Expand All @@ -21,6 +22,7 @@ export interface DynamicRelationGroupModelConfig extends DsDynamicInputModelConf
* Dynamic Group Model class
*/
export class DynamicRelationGroupModel extends DsDynamicInputModel {
@serializable() submissionId: string;
@serializable() formConfiguration: FormRowModel[];
@serializable() mandatoryField: string;
@serializable() relationFields: string[];
Expand All @@ -32,6 +34,7 @@ export class DynamicRelationGroupModel extends DsDynamicInputModel {
constructor(config: DynamicRelationGroupModelConfig, layout?: DynamicFormControlLayout) {
super(config, layout);

this.submissionId = config.submissionId;
this.formConfiguration = config.formConfiguration;
this.mandatoryField = config.mandatoryField;
this.relationFields = config.relationFields;
Expand Down
19 changes: 11 additions & 8 deletions src/app/shared/form/builder/form-builder.service.spec.ts
Expand Up @@ -56,6 +56,8 @@ describe('FormBuilderService test suite', () => {
let testFormConfiguration: SubmissionFormsModel;
let service: FormBuilderService;

const submissionId = '1234';

function testValidator() {
return {testValidator: {valid: true}};
}
Expand Down Expand Up @@ -204,6 +206,7 @@ describe('FormBuilderService test suite', () => {
new DynamicListRadioGroupModel({id: 'testRadioList', authorityOptions: authorityOptions, repeatable: false}),

new DynamicRelationGroupModel({
submissionId,
id: 'testRelationGroup',
formConfiguration: [{
fields: [{
Expand Down Expand Up @@ -406,7 +409,7 @@ describe('FormBuilderService test suite', () => {
});

it('should create an array of form models', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');

expect(formModel[0] instanceof DynamicRowGroupModel).toBe(true);
expect((formModel[0] as DynamicRowGroupModel).group.length).toBe(3);
Expand All @@ -427,7 +430,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return form\'s fields value from form model', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let value = {} as any;

expect(service.getValueFromModel(formModel)).toEqual(value);
Expand All @@ -448,7 +451,7 @@ describe('FormBuilderService test suite', () => {
});

it('should clear all form\'s fields value', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
const value = {} as any;

((formModel[0] as DynamicRowGroupModel).get(1) as DsDynamicInputModel).valueUpdates.next('test');
Expand All @@ -460,7 +463,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return true when model has a custom group model as parent', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_VALUE', formModel);
let modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
model.parent = modelParent;
Expand Down Expand Up @@ -489,7 +492,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return true when model value is a map', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
const model = service.findById('dc_identifier_QUALDROP_VALUE', formModel);
const modelParent = service.findById('dc_identifier_QUALDROP_GROUP', formModel);
model.parent = modelParent;
Expand All @@ -498,7 +501,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return true when model is a Qualdrop Group', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);

expect(service.isQualdropGroup(model)).toBe(true);
Expand All @@ -509,7 +512,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return true when model is a Custom or List Group', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);

expect(service.isCustomOrListGroup(model)).toBe(true);
Expand All @@ -528,7 +531,7 @@ describe('FormBuilderService test suite', () => {
});

it('should return true when model is a Custom Group', () => {
const formModel = service.modelFromConfiguration(testFormConfiguration, 'testScopeUUID');
const formModel = service.modelFromConfiguration(submissionId, testFormConfiguration, 'testScopeUUID');
let model = service.findById('dc_identifier_QUALDROP_GROUP', formModel);

expect(service.isCustomGroup(model)).toBe(true);
Expand Down
13 changes: 10 additions & 3 deletions src/app/shared/form/builder/form-builder.service.ts
Expand Up @@ -10,7 +10,7 @@ import {
DynamicFormArrayModel,
DynamicFormControlModel,
DynamicFormGroupModel,
DynamicFormService,
DynamicFormService, DynamicFormValidationService,
DynamicPathable,
JSONUtils,
} from '@ng-dynamic-forms/core';
Expand All @@ -33,6 +33,13 @@ import { isNgbDateStruct } from '../../date.util';
@Injectable()
export class FormBuilderService extends DynamicFormService {

constructor(
validationService: DynamicFormValidationService,
protected rowParser: RowParser
) {
super(validationService);
}

findById(id: string, groupModel: DynamicFormControlModel[], arrayIndex = null): DynamicFormControlModel | null {

let result = null;
Expand Down Expand Up @@ -198,13 +205,13 @@ export class FormBuilderService extends DynamicFormService {
return result;
}

modelFromConfiguration(json: string | SubmissionFormsModel, scopeUUID: string, initFormValues: any = {}, submissionScope?: string, readOnly = false): DynamicFormControlModel[] | never {
modelFromConfiguration(submissionId: string, json: string | SubmissionFormsModel, scopeUUID: string, sectionData: any = {}, submissionScope?: string, readOnly = false): DynamicFormControlModel[] | never {
let rows: DynamicFormControlModel[] = [];
const rawData = typeof json === 'string' ? JSON.parse(json, JSONUtils.parseReviver) : json;

if (rawData.rows && !isEmpty(rawData.rows)) {
rawData.rows.forEach((currentRow) => {
const rowParsed = new RowParser(currentRow, scopeUUID, initFormValues, submissionScope, readOnly).parse();
const rowParsed = this.rowParser.parse(submissionId, currentRow, scopeUUID, sectionData, submissionScope, readOnly);
if (isNotNull(rowParsed)) {
if (Array.isArray(rowParsed)) {
rows = rows.concat(rowParsed);
Expand Down
19 changes: 14 additions & 5 deletions src/app/shared/form/builder/parsers/concat-field-parser.ts
@@ -1,4 +1,11 @@
import { FieldParser } from './field-parser';
import { Inject } from '@angular/core';
import {
CONFIG_DATA,
FieldParser,
INIT_FORM_VALUES,
PARSER_OPTIONS,
SUBMISSION_ID
} from './field-parser';
import { FormFieldModel } from '../models/form-field.model';
import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model';
import { DynamicFormControlLayout, DynamicInputModel, DynamicInputModelConfig } from '@ng-dynamic-forms/core';
Expand All @@ -14,13 +21,15 @@ import { ParserOptions } from './parser-options';

export class ConcatFieldParser extends FieldParser {

constructor(protected configData: FormFieldModel,
protected initFormValues,
protected parserOptions: ParserOptions,
constructor(
@Inject(SUBMISSION_ID) submissionId: string,
@Inject(CONFIG_DATA) configData: FormFieldModel,
@Inject(INIT_FORM_VALUES) initFormValues,
@Inject(PARSER_OPTIONS) parserOptions: ParserOptions,
protected separator: string,
protected firstPlaceholder: string = null,
protected secondPlaceholder: string = null) {
super(configData, initFormValues, parserOptions);
super(submissionId, configData, initFormValues, parserOptions);

this.separator = separator;
this.firstPlaceholder = firstPlaceholder;
Expand Down

0 comments on commit 33972cb

Please sign in to comment.