/** * * Copyright * 2009-2015 Jayway Products AB * 2016-2017 Föreningen Sambruk * * Licensed under AGPL, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/agpl.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package se.streamsource.streamflow.web.domain.structure.form; import com.petebevin.markdown.MarkdownProcessor; import org.qi4j.api.common.Optional; import org.qi4j.api.entity.Aggregated; import org.qi4j.api.entity.EntityBuilder; import org.qi4j.api.entity.EntityReference; import org.qi4j.api.entity.IdentityGenerator; import org.qi4j.api.entity.Queryable; import org.qi4j.api.entity.association.ManyAssociation; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.This; import org.qi4j.api.mixin.Mixins; import org.qi4j.api.structure.Module; import org.qi4j.api.unitofwork.UnitOfWork; import org.qi4j.api.value.ValueBuilder; import se.streamsource.dci.api.RoleMap; import se.streamsource.streamflow.api.ErrorResources; import se.streamsource.streamflow.api.administration.form.*; import se.streamsource.streamflow.api.workspace.cases.general.FieldSubmissionDTO; import se.streamsource.streamflow.api.workspace.cases.general.FormDraftDTO; import se.streamsource.streamflow.api.workspace.cases.general.PageSubmissionDTO; import se.streamsource.streamflow.infrastructure.event.domain.DomainEvent; import se.streamsource.streamflow.util.Strings; import se.streamsource.streamflow.web.domain.entity.form.FormDraftEntity; import se.streamsource.streamflow.web.domain.entity.organization.OrganizationsEntity; import se.streamsource.streamflow.web.domain.structure.SubmittedFieldValue; import se.streamsource.streamflow.web.domain.structure.attachment.Attachment; import se.streamsource.streamflow.web.domain.structure.attachment.FormAttachments; import se.streamsource.streamflow.web.domain.structure.casetype.CaseType; import se.streamsource.streamflow.web.domain.structure.casetype.FormOnClose; import se.streamsource.streamflow.web.domain.structure.casetype.TypedCase; import se.streamsource.streamflow.web.domain.structure.organization.FormOnRemove; import se.streamsource.streamflow.web.domain.structure.organization.Organizations; import se.streamsource.streamflow.web.domain.structure.organization.WebAPReplacedSelectionFieldValues; import java.util.ArrayList; /** * JAVADOC */ @Mixins(FormDrafts.Mixin.class) public interface FormDrafts { FormDraft getFormDraft(Form form); FormDraft createFormDraft(Form form); void discardFormDraft(FormDraft form); interface Data { @Aggregated @Queryable(false) ManyAssociation<FormDraft> formDrafts(); FormDraft createdFormDraft(@Optional DomainEvent event, String id); void discardedFormDraft(@Optional DomainEvent event, FormDraft formDraft); } abstract class Mixin implements FormDrafts, Data { @Structure Module module; @This TypedCase.Data typedCase; @This SubmittedForms.Data submittedForms; @Service IdentityGenerator idgen; public FormDraft getFormDraft(Form form) { for (FormDraft formDraft : formDrafts().toList()) { if (formDraft.getFormDraftValue() == null) return null; if (formDraft.getFormDraftValue().form().get().identity().equals( form.toString() )) { return formDraft; } } return null; } public FormDraft createFormDraft(Form form) { if (getFormDraft( form ) != null) { // already exists, don't create return null; } Organizations.Data orgs = module.unitOfWorkFactory().currentUnitOfWork().get( OrganizationsEntity.class, OrganizationsEntity.ORGANIZATIONS_ID ); FormOnRemove.Data data = (FormOnRemove.Data) orgs.organization().get(); Form formOnRemove = data.formOnRemove().get(); if ( formOnRemove != null && form.equals( formOnRemove ) ) { return createDraft( form ); } CaseType caseType = typedCase.caseType().get(); if (caseType != null) { SelectedForms.Data forms = (SelectedForms.Data) caseType; FormOnClose.Data formOnClose = (FormOnClose.Data) caseType; if (forms.selectedForms().contains( form ) || form.equals( formOnClose.formOnClose().get() )) { return createDraft( form ); } } return null; } private FormDraft createDraft( Form form ) { SubmittedFormValue submittedFormValue = findLatestSubmittedForm( form ); ValueBuilder<FormDraftDTO> builder = module.valueBuilderFactory().newValueBuilder( FormDraftDTO.class ); builder.prototype().description().set( form.getDescription() ); builder.prototype().form().set( EntityReference.getEntityReference( form ) ); ValueBuilder<PageSubmissionDTO> pageBuilder = module.valueBuilderFactory().newValueBuilder( PageSubmissionDTO.class ); ValueBuilder<FieldSubmissionDTO> fieldBuilder = module.valueBuilderFactory().newValueBuilder( FieldSubmissionDTO.class ); ValueBuilder<FieldDefinitionValue> valueBuilder = module.valueBuilderFactory().newValueBuilder( FieldDefinitionValue.class ); builder.prototype().pages().set( new ArrayList<PageSubmissionDTO>() ); Pages.Data pageEntities = (Pages.Data) form; for (Page page : pageEntities.pages()) { pageBuilder.prototype().title().set( page.getDescription() ); pageBuilder.prototype().page().set( EntityReference.getEntityReference( page ) ); pageBuilder.prototype().fields().set( new ArrayList<FieldSubmissionDTO>() ); pageBuilder.prototype().rule().set( page.getRule() ); Fields.Data fieldEntities = (Fields.Data) page; for (Field field : fieldEntities.fields()) { FieldValue fieldValue = ((FieldValueDefinition.Data) field).fieldValue().get(); if (fieldValue instanceof FieldGroupFieldValue) { UnitOfWork uow = module.unitOfWorkFactory().currentUnitOfWork(); FieldGroup fieldGroup = uow.get( FieldGroup.class, ((FieldGroupFieldValue)fieldValue).fieldGroup().get().identity() ); ValueBuilder<FieldGroupFieldValue> fieldValueBuilder = module.valueBuilderFactory().newValueBuilder( FieldGroupFieldValue.class ).withPrototype( (FieldGroupFieldValue) fieldValue ); fieldValueBuilder.prototype().fieldCount().set( ((Fields.Data)fieldGroup).fields().count() ); FieldSubmissionDTO fieldGroupDefinition = createFieldSubmission( field, fieldValueBuilder.newInstance(), submittedFormValue, fieldBuilder, valueBuilder ); pageBuilder.prototype().fields().get().add( fieldGroupDefinition ); for (Field subField : page.listFieldGroupFields( field )) { FieldValue subFieldValue = ((FieldValueDefinition.Data) subField).fieldValue().get(); ValueBuilder<FieldSubmissionDTO> fieldSubmissionBuilder = fieldSubmissionBuilder( subField, subFieldValue, submittedFormValue, fieldBuilder, valueBuilder ); valueBuilder.prototype().field().set( EntityReference.getEntityReference( subField ) ); fieldSubmissionBuilder.prototype().field().set( valueBuilder.newInstance() ); pageBuilder.prototype().fields().get().add( fieldSubmissionBuilder.newInstance() ); } } else { pageBuilder.prototype().fields().get().add( createFieldSubmission( field, fieldValue, submittedFormValue, fieldBuilder, valueBuilder ) ); } } builder.prototype().pages().get().add( pageBuilder.newInstance() ); } int pages = builder.prototype().pages().get().size(); if( pages == 0 ) { throw new IllegalArgumentException( ErrorResources.form_without_pages.name() ); } builder.prototype().pages().get().remove( pages - 1 ); builder.prototype().pages().get().add( pageBuilder.newInstance() ); FormDraft draft = createdFormDraft( null, idgen.generate( FormDraftEntity.class ) ); draft.changeFormDraftValue( builder.newInstance() ); return draft; } private FieldSubmissionDTO createFieldSubmission(Field field, FieldValue fieldValue, SubmittedFormValue submittedFormValue, ValueBuilder<FieldSubmissionDTO> fieldBuilder, ValueBuilder<FieldDefinitionValue> valueBuilder) { return fieldSubmissionBuilder( field, fieldValue, submittedFormValue, fieldBuilder, valueBuilder ).newInstance(); } /** * Create a field submission builder and try to determine whether to set the FieldValue from * any AccessPoint replacement or from a already done field submission. * SubmittedFieldValue has precedence before WebAPReplacedSelectionFieldValues. * * @param field - The form field * @param fieldValue - The original FieldValue from FieldDefintionValue * @param submittedFormValue - The SubmittedFormValue from last form submission. * @param fieldBuilder - The FieldSubmissionDTO builder. * @param definitionValueBuilder - The FieldDefinitionValue builder. * @return The visiting FieldSubmissionDTO builder. */ private ValueBuilder<FieldSubmissionDTO> fieldSubmissionBuilder(Field field, FieldValue fieldValue, SubmittedFormValue submittedFormValue, ValueBuilder<FieldSubmissionDTO> fieldBuilder, ValueBuilder<FieldDefinitionValue> definitionValueBuilder) { // SF-846 Try to establish if there is an AccessPoint in the role map. WebAPReplacedSelectionFieldValues replacedSelectionFieldValues = null; try { replacedSelectionFieldValues = RoleMap.role(WebAPReplacedSelectionFieldValues.class ); } catch( IllegalArgumentException e ) { // do nothing - no AccessPoint found in role map. } SubmittedFieldValue submittedFieldValue = getSubmittedValue( field, submittedFormValue ); if( submittedFieldValue == null ) { fieldBuilder.prototype().value().set( null ); } else { fieldBuilder.prototype().value().set("".equals( submittedFieldValue.value().get() ) ? null : submittedFieldValue.value().get() ); } fieldBuilder.prototype().enabled().set( true ); definitionValueBuilder.prototype().description().set( field.getDescription() ); if (fieldValue instanceof CommentFieldValue) { definitionValueBuilder.prototype().note().set( (new MarkdownProcessor()).markdown( field.getNote()) ); } else { definitionValueBuilder.prototype().note().set( field.getNote() ); } definitionValueBuilder.prototype().field().set( EntityReference.getEntityReference( field ) ); definitionValueBuilder.prototype().fieldId().set( ((FieldId.Data) field).fieldId().get() ); DatatypeDefinition datatypeDefinition = ((Datatype.Data) field).datatype().get(); if (datatypeDefinition != null) { definitionValueBuilder.prototype().datatypeUrl().set( datatypeDefinition.getUrl() ); if (fieldValue instanceof TextFieldValue) { TextFieldValue textFieldValue = (TextFieldValue) fieldValue; if (Strings.empty( textFieldValue.regularExpression().get() ) && !Strings.empty( datatypeDefinition.getRegularExpression() )) { ValueBuilder<TextFieldValue> fieldValueBuilder = module.valueBuilderFactory() .newValueBuilder( TextFieldValue.class ).withPrototype( (TextFieldValue) fieldValue ); fieldValueBuilder.prototype().regularExpression().set( datatypeDefinition.getRegularExpression() ); fieldValueBuilder.prototype().mandatory().set( field.isMandatory() ); fieldValue = fieldValueBuilder.newInstance(); } } } definitionValueBuilder.prototype().mandatory().set( field.isMandatory() ); // SF-846 Replace FieldValue with saved one if there is one saved in last submission. if( submittedFieldValue == null ) { if( replacedSelectionFieldValues != null && replacedSelectionFieldValues.getReplacementFieldValue( field.toString()) != null ) { SelectionFieldValue replacementValue = replacedSelectionFieldValues.getReplacementFieldValue( field.toString() ); if( fieldValue instanceof OpenSelectionFieldValue) { ValueBuilder<OpenSelectionFieldValue> valueBuilder = ((OpenSelectionFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set( valueBuilder.newInstance() ); } else if( fieldValue instanceof CheckboxesFieldValue ) { ValueBuilder<CheckboxesFieldValue> valueBuilder = ((CheckboxesFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set(valueBuilder.newInstance()); } else if( fieldValue instanceof ListBoxFieldValue) { ValueBuilder<ListBoxFieldValue> valueBuilder = ((ListBoxFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set(valueBuilder.newInstance()); } else if( fieldValue instanceof GeoLocationFieldValue ) { ValueBuilder<GeoLocationFieldValue> valueBuilder = ((GeoLocationFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set(valueBuilder.newInstance()); } else if( fieldValue instanceof ComboBoxFieldValue ) { ValueBuilder<ComboBoxFieldValue> valueBuilder = ((ComboBoxFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set(valueBuilder.newInstance()); } else if( fieldValue instanceof OptionButtonsFieldValue ) { ValueBuilder<OptionButtonsFieldValue> valueBuilder = ((OptionButtonsFieldValue) fieldValue).buildWith(); valueBuilder.prototype().values().set( replacementValue.values().get() ); definitionValueBuilder.prototype().fieldValue().set(valueBuilder.newInstance()); } } else { definitionValueBuilder.prototype().fieldValue().set( fieldValue ); } } else { definitionValueBuilder.prototype().fieldValue().set( submittedFieldValue.origFieldValue().get() == null ? fieldValue : submittedFieldValue.origFieldValue().get() ); } definitionValueBuilder.prototype().rule().set( field.getRule() ); fieldBuilder.prototype().field().set(definitionValueBuilder.newInstance()); return fieldBuilder; } public FormDraft createdFormDraft(@Optional DomainEvent event, String id) { EntityBuilder<FormDraft> submissionEntityBuilder = module.unitOfWorkFactory().currentUnitOfWork() .newEntityBuilder( FormDraft.class, id ); FormDraft formSubmission = submissionEntityBuilder.newInstance(); formDrafts().add( formSubmission ); return formSubmission; } private SubmittedFieldValue getSubmittedValue(Field field, SubmittedFormValue submittedFormValue) { if (submittedFormValue == null) return null; for (SubmittedPageValue submittedPageValue : submittedFormValue.pages().get()) { for (SubmittedFieldValue submittedFieldValue : submittedPageValue.fields().get()) { if (submittedFieldValue.field().get().equals( EntityReference.getEntityReference( field ) )) { return submittedFieldValue; } } } return null; } private SubmittedFormValue findLatestSubmittedForm(Form form) { SubmittedFormValue value = null; for (SubmittedFormValue submittedFormValue : submittedForms.submittedForms().get()) { if (submittedFormValue.form().get().equals( EntityReference.getEntityReference( form ) )) { value = submittedFormValue; } } return value; } public void discardFormDraft(FormDraft formDraft) { if (formDrafts().contains( formDraft )) { for (Attachment attachment : ((FormAttachments.Data) formDraft).formAttachments().toList()) { ((FormAttachments) formDraft).removeFormAttachment( attachment ); } discardedFormDraft( null, formDraft ); } } public void discardedFormDraft(@Optional DomainEvent event, FormDraft formDraft) { formDrafts().remove( formDraft ); // uowf.currentUnitOfWork().remove( formDraft ); } } }