diff --git a/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapper.java b/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapper.java index 8d7f1f8..80cc9c3 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapper.java @@ -4,17 +4,23 @@ package io.github.genomicdatainfrastructure.daam.gateways; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import io.github.genomicdatainfrastructure.daam.model.*; import io.github.genomicdatainfrastructure.daam.remote.rems.model.*; import jakarta.enterprise.context.ApplicationScoped; +import lombok.RequiredArgsConstructor; import java.util.*; import static java.util.Optional.ofNullable; @ApplicationScoped +@RequiredArgsConstructor public class RemsApplicationMapper { + private final ObjectMapper mapper; + public RetrievedApplication from(String userId, Application application) { return RetrievedApplication .builder() @@ -172,31 +178,79 @@ private List toFormFields(Form form) { return potentialFields.map(fields -> fields .stream() + .filter(Objects::nonNull) .map(this::toFormField) .toList()) .orElse(null); } private RetrievedApplicationFormField toFormField(Field formField) { - var potentialFormField = ofNullable(formField); - - return new RetrievedApplicationFormField(potentialFormField.map(Field::getFieldId).orElse( - null), - potentialFormField.map(Field::getFieldValue).orElse(null), - potentialFormField.map(Field::getFieldOptional).orElse(null), - potentialFormField.map(Field::getFieldPrivate).orElse(null), - potentialFormField.map(Field::getFieldVisible).orElse(null), - potentialFormField.map(f -> toLabelObject(f.getFieldTitle())).orElse(null), - potentialFormField.map(this::toFieldType).orElse(null)); - } + var type = formField.getFieldType(); + + var value = formField.getFieldValue(); - private String toFieldType(Field field) { - var fieldType = Optional.of(field.getFieldType()); + String stringValue = null; + var tableValues = List.>of(); - return fieldType.map(Field.FieldTypeEnum::value) + if (Field.FieldTypeEnum.TABLE == type) { + tableValues = mapper.convertValue(value, new TypeReference<>() { + }); + } else { + stringValue = ofNullable(value).map(Object::toString).orElse(null); + } + + return RetrievedApplicationFormField.builder() + .id(formField.getFieldId()) + .value(stringValue) + .optional(formField.getFieldOptional()) + ._private(formField.getFieldPrivate()) + .visible(formField.getFieldVisible()) + .title(toLabelObject(formField.getFieldTitle())) + .type(ofNullable(type).map(Field.FieldTypeEnum::value).orElse(null)) + .tableValues(tableValues) + .infoText(formField.getFieldInfoText()) + .maxLength(formField.getFieldMaxLength()) + .privacy(toPrivacy(formField)) + .options(toOptions(formField)) + .tableColumns(toColumns(formField)) + .build(); + } + + private RetrievedApplicationFormField.PrivacyEnum toPrivacy(Field formField) { + return ofNullable(formField) + .map(Field::getFieldPrivacy) + .map(it -> RetrievedApplicationFormField.PrivacyEnum.valueOf(it.value())) .orElse(null); } + private List toOptions(Field formField) { + var nonNullOptions = ofNullable(formField) + .map(Field::getFieldOptions) + .orElseGet(List::of); + + return nonNullOptions.stream() + .filter(Objects::nonNull) + .map(it -> FormFieldOption.builder() + .key(it.getKey()) + .label(toLabelObject(it.getLabel())) + .build()) + .toList(); + } + + private List toColumns(Field formField) { + var nonNullOptions = ofNullable(formField) + .map(Field::getFieldColumns) + .orElseGet(List::of); + + return nonNullOptions.stream() + .filter(Objects::nonNull) + .map(it -> FormFieldTableColumn.builder() + .key(it.getKey()) + .label(toLabelObject(it.getLabel())) + .build()) + .toList(); + } + private List toPermissions(Application application) { var potentialPermissions = ofNullable(application.getApplicationPermissions()); @@ -210,7 +264,8 @@ private List toPermissions(Application application) { private String toPermission(Application.ApplicationPermissionsEnum permission) { var potentialPermission = ofNullable(permission); - return potentialPermission.map(Application.ApplicationPermissionsEnum::value) + return potentialPermission + .map(Application.ApplicationPermissionsEnum::value) .orElse(null); } @@ -220,25 +275,22 @@ private List toEvents(Application application) { return potentialEvents .stream() - .map(this::toEvent) .filter(Objects::nonNull) + .map(this::toEvent) .sorted(Comparator.comparing(RetrievedApplicationEvent::getEventTime).reversed()) .toList(); } private RetrievedApplicationEvent toEvent(Event event) { - var potentialEvent = ofNullable(event); - - return new RetrievedApplicationEvent( - potentialEvent.map(this::toUserId).orElse(null), - potentialEvent.map(Event::getEventTime).orElse(null), - potentialEvent.map(Event::getEventType).orElse(null)); + return RetrievedApplicationEvent.builder() + .actorId(toUserId(event)) + .eventTime(event.getEventTime()) + .eventType(event.getEventType()) + .build(); } private String toUserId(Event event) { - var eventActorAttributes = ofNullable(event - .getEventActorAttributes()); - + var eventActorAttributes = ofNullable(event.getEventActorAttributes()); return eventActorAttributes.map(UserWithAttributes::getUserid).orElse(null); } diff --git a/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/SaveDraftCommandMapper.java b/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/SaveDraftCommandMapper.java index 969d001..3467036 100644 --- a/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/SaveDraftCommandMapper.java +++ b/src/main/java/io/github/genomicdatainfrastructure/daam/gateways/SaveDraftCommandMapper.java @@ -4,18 +4,21 @@ package io.github.genomicdatainfrastructure.daam.gateways; -import static java.util.Optional.ofNullable; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - import io.github.genomicdatainfrastructure.daam.model.SaveForm; import io.github.genomicdatainfrastructure.daam.model.SaveFormField; import io.github.genomicdatainfrastructure.daam.model.SaveFormsAndDuos; +import io.github.genomicdatainfrastructure.daam.remote.rems.model.FormTemplateTableValue; import io.github.genomicdatainfrastructure.daam.remote.rems.model.SaveDraftCommand; import io.github.genomicdatainfrastructure.daam.remote.rems.model.SaveDraftCommandFieldValues; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; + +import static java.util.Optional.ofNullable; +import static java.util.function.Predicate.not; + public class SaveDraftCommandMapper { private SaveDraftCommandMapper() { @@ -47,10 +50,23 @@ private static Stream parseFieldValues(SaveForm for } private static SaveDraftCommandFieldValues parseFieldValue(SaveForm form, SaveFormField field) { + Object value = field.getValue(); + if (Objects.nonNull(field.getTableValues())) { + value = field.getTableValues().stream() + .filter(Objects::nonNull) + .filter(not(Collection::isEmpty)) + .map(it -> it.stream() + .map(columnValue -> FormTemplateTableValue.builder() + .column(columnValue.getColumn()) + .value(columnValue.getValue()) + .build()).toList() + ) + .toList(); + } return SaveDraftCommandFieldValues.builder() .form(form.getFormId()) .field(field.getFieldId()) - .value(field.getValue()) + .value(value) .build(); } } diff --git a/src/main/openapi/daam.yaml b/src/main/openapi/daam.yaml index 7962bf2..feaf73e 100644 --- a/src/main/openapi/daam.yaml +++ b/src/main/openapi/daam.yaml @@ -656,6 +656,12 @@ components: value: type: string title: Field value + tableValues: + type: array + items: + type: array + items: + $ref: "#/components/schemas/FormFieldTableValue" SaveDUOCode: properties: duoId: @@ -689,7 +695,6 @@ components: type: integer format: int64 applicant: - title: Applicant $ref: "#/components/schemas/RetrievedApplicationApplicant" members: type: array @@ -867,6 +872,54 @@ components: type: type: string title: Field type + tableValues: + title: Table Values + type: array + items: + type: array + items: + $ref: "#/components/schemas/FormFieldTableValue" + tableColumns: + title: Table Columns + type: array + items: + $ref: "#/components/schemas/FormFieldTableColumn" + infoText: + type: string + maxLength: + type: integer + format: int64 + privacy: + type: string + enum: + - private + - public + options: + type: array + items: + $ref: "#/components/schemas/FormFieldOption" + FormFieldTableValue: + properties: + column: + type: string + value: + type: string + FormFieldOption: + properties: + key: + type: string + label: + type: array + items: + $ref: "#/components/schemas/Label" + FormFieldTableColumn: + properties: + key: + type: string + label: + type: array + items: + $ref: "#/components/schemas/Label" Label: properties: language: diff --git a/src/main/openapi/rems.yaml b/src/main/openapi/rems.yaml index af8ac7e..f22c226 100644 --- a/src/main/openapi/rems.yaml +++ b/src/main/openapi/rems.yaml @@ -931,7 +931,6 @@ components: values: type: array items: - type: object $ref: "#/components/schemas/Response10953ResourcesDuoCodesRestrictionsValues" Response10953ResourcesDuoCodesRestrictionsValues: required: @@ -1111,6 +1110,7 @@ components: items: type: object V2License: + type: object required: - license/type - license/title @@ -1136,16 +1136,12 @@ components: license/archived: type: boolean license/link: - type: object $ref: "#/components/schemas/LocalizedString" license/attachment-filename: - type: object $ref: "#/components/schemas/LocalizedString" license/text: - type: object $ref: "#/components/schemas/LocalizedString" license/attachment-id: - type: object $ref: "#/components/schemas/LocalizedInt" Form: required: @@ -1157,6 +1153,8 @@ components: form/id: type: integer format: int64 + form/title: + type: string form/internal-name: type: string form/external-title: @@ -1198,13 +1196,59 @@ components: - attachment - text field/value: - type: string + # Parsing from OpenAPI to Java does not support oneOf + #oneOf: + # - type: string + # - type: array + # items: + # $ref: "#/components/schemas/FormTemplateTableValue" + type: object example: value description: 'A string for most fields, or [[{"column": string, "value": string}]] for table fields' field/id: type: string + field/info-text: + type: string field/optional: type: boolean + field/max-length: + type: integer + format: int64 + field/privacy: + type: string + nullable: true + enum: + - private + - public + field/options: + type: array + items: + $ref: "#/components/schemas/FormTemplateFieldOption" + field/columns: + type: array + items: + $ref: "#/components/schemas/FormTemplateFieldColumn" + FormTemplateTableValue: + type: object + properties: + column: + type: string + value: + type: string + FormTemplateFieldOption: + type: object + properties: + key: + type: string + label: + $ref: "#/components/schemas/LocalizedString" + FormTemplateFieldColumn: + type: object + properties: + key: + type: string + label: + $ref: "#/components/schemas/LocalizedString" Event: required: - event/type @@ -1360,9 +1404,9 @@ components: field: type: string value: + type: object example: value description: 'A string for most fields, or [[{"column": string, "value": string}]] for table fields' - type: string additionalProperties: false required: - form diff --git a/src/test/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapperTest.java b/src/test/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapperTest.java index 0ea22e0..bd15069 100644 --- a/src/test/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapperTest.java +++ b/src/test/java/io/github/genomicdatainfrastructure/daam/gateways/RemsApplicationMapperTest.java @@ -4,6 +4,7 @@ package io.github.genomicdatainfrastructure.daam.gateways; +import com.fasterxml.jackson.databind.ObjectMapper; import io.github.genomicdatainfrastructure.daam.model.*; import io.github.genomicdatainfrastructure.daam.remote.rems.model.*; import org.junit.jupiter.api.BeforeEach; @@ -22,12 +23,12 @@ class RemsApplicationMapperTest { @BeforeEach void setUp() { - underTest = new RemsApplicationMapper(); + underTest = new RemsApplicationMapper(new ObjectMapper()); } @Test void should_map_correctly_complete_rems_application_to_retrieved_application() { - RetrievedApplication retrievedApplication = underTest.from("dummy", createApplication()); + var retrievedApplication = underTest.from("dummy", createApplication()); assertThat(retrievedApplication.getId()).isEqualTo(1L); assertThat(retrievedApplication.getExternalId()).isEqualTo("APP20240328"); @@ -63,16 +64,32 @@ void should_map_correctly_complete_rems_application_to_retrieved_application() { new Label("de", "Title in German")), List.of(new Label("fr", "Url info in French"), new Label("de", "Url info in German")))); - assertThat(retrievedApplication.getForms()).containsExactlyInAnyOrder( - new RetrievedApplicationForm( - 4L, - "form-access-1", - List.of(new Label("en", "External title in English"), new Label("fr", - "External title in French")), - List.of(new RetrievedApplicationFormField("98", "ulrich.smith@outlook.de", - true, false, true, - List.of(new Label("en", "Field in English"), new Label("fr", - "Field in French")), "email")))); + assertThat(retrievedApplication.getForms()) + .containsExactlyInAnyOrder(RetrievedApplicationForm.builder() + .id(4L) + .internalName("form-access-1") + .externalTitle(List.of( + new Label("en", "External title in English"), + new Label("fr", "External title in French") + )) + .fields(List.of( + RetrievedApplicationFormField.builder() + .id("98") + .value("ulrich.smith@outlook.de") + .optional(true) + ._private(false) + .visible(true) + .title(List.of( + new Label("en", "Field in English"), + new Label("fr", "Field in French") + )) + .type("email") + .options(List.of()) + .tableValues(List.of()) + .tableColumns(List.of()) + .build() + )) + .build()); assertThat(retrievedApplication.getInvitedMembers()).containsExactlyInAnyOrder( new RetrievedApplicationInvitedMember("Kate", "kate.tominay@gmail.com"), @@ -161,9 +178,20 @@ private List
createForms() { fieldTitleResourceId4.put("fr", "Field in French"); return List.of( - new Form(4L, "form-access-1", formTitleResourceId4, - List.of(new Field(false, fieldTitleResourceId4, true, - Field.FieldTypeEnum.EMAIL, "ulrich.smith@outlook.de", "98", true))) + Form.builder() + .formId(4L) + .formInternalName("form-access-1") + .formExternalTitle(formTitleResourceId4) + .formFields(List.of(Field.builder() + .fieldId("98") + .fieldValue("ulrich.smith@outlook.de") + .fieldOptional(true) + .fieldPrivate(false) + .fieldVisible(true) + .fieldTitle(fieldTitleResourceId4) + .fieldType(Field.FieldTypeEnum.EMAIL) + .build())) + .build() ); }