From 3ddcd2522def539b09e1ce169a9151642f9cd41c Mon Sep 17 00:00:00 2001 From: vkovtun <viktor.kovtun@id.ethz.ch> Date: Sat, 11 Mar 2023 09:06:09 +0100 Subject: [PATCH] SSDM-13256: Added Registration Date, Registrator, Modification Date and Modifier export support for samples. --- .../export/helper/XLSSampleExportHelper.java | 24 +++++++++++- .../server/xls/export/SampleExpectations.java | 36 ++++++++++++++++++ .../server/xls/export/XLSExportTest.java | 28 +++++++------- .../xls/export/resources/export-sample.xlsx | Bin 6222 -> 6497 bytes 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java index 89c334d66be..c1a4f3469af 100644 --- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java +++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSSampleExportHelper.java @@ -72,7 +72,7 @@ public class XLSSampleExportHelper extends AbstractXLSEntityExportHelper<Sample, protected String[] getAttributeNames(final Sample entity) { return new String[] { "$", "Identifier", "Code", "Space", "Project", "Experiment", - "Auto generate code", "Parents", "Children" }; + "Auto generate code", "Parents", "Children", "Registrator", "Registration Date", "Modifier", "Modification Date" }; } @Override @@ -89,6 +89,8 @@ public class XLSSampleExportHelper extends AbstractXLSEntityExportHelper<Sample, fetchOptions.withChildren(); fetchOptions.withType().withPropertyAssignments().withPropertyType(); fetchOptions.withProperties(); + fetchOptions.withRegistrator(); + fetchOptions.withModifier(); return api.getSamples(sessionToken, samplePermIds, fetchOptions).values(); } @@ -136,6 +138,22 @@ public class XLSSampleExportHelper extends AbstractXLSEntityExportHelper<Sample, .map(child -> child.getIdentifier().getIdentifier()) .collect(Collectors.joining("\n")); } + case "Registrator": + { + return sample.getRegistrator().getUserId(); + } + case "Registration Date": + { + return DATE_FORMAT.format(sample.getRegistrationDate()); + } + case "Modifier": + { + return sample.getModifier().getUserId(); + } + case "Modification Date": + { + return DATE_FORMAT.format(sample.getModificationDate()); + } default: { return null; @@ -155,7 +173,9 @@ public class XLSSampleExportHelper extends AbstractXLSEntityExportHelper<Sample, .collect(Collectors.joining("\n")), sample.getChildren() == null ? "" : sample.getChildren().stream() .map(child -> child.getIdentifier().getIdentifier()) - .collect(Collectors.joining("\n"))); + .collect(Collectors.joining("\n")), sample.getRegistrator().getUserId(), + DATE_FORMAT.format(sample.getRegistrationDate()), sample.getModifier().getUserId(), + DATE_FORMAT.format(sample.getModificationDate())); } @Override diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/SampleExpectations.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/SampleExpectations.java index 0edee9c4f93..882d3b87e66 100644 --- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/SampleExpectations.java +++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/SampleExpectations.java @@ -16,6 +16,8 @@ package ch.ethz.sis.openbis.generic.server.xls.export; import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.function.Function; @@ -30,6 +32,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.EntityKind; import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person; import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project; import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier; import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.DataType; @@ -106,6 +109,19 @@ class SampleExpectations extends Expectations defaultExperiment.setCode("DEFAULT"); defaultExperiment.setIdentifier(new ExperimentIdentifier("/DEFAULT/DEFAULT/DEFAULT")); + final Calendar calendar = Calendar.getInstance(); + calendar.set(2023, Calendar.MARCH, 10, 17, 23, 44); + final Date registrationDate = calendar.getTime(); + + calendar.set(2023, Calendar.MARCH, 11, 17, 23, 44); + final Date modificationDate = calendar.getTime(); + + final Person registrator = new Person(); + registrator.setUserId("system"); + + final Person modifier = new Person(); + modifier.setUserId("test"); + final Sample[] samples = new Sample[5]; samples[0] = new Sample(); @@ -119,6 +135,10 @@ class SampleExpectations extends Expectations samples[0].setExperiment(experiment); samples[0].setProperty("$NAME", "Bench"); samples[0].setProperty("$STORAGE.BOX_NUM", "9999"); + samples[0].setRegistrator(registrator); + samples[0].setModifier(modifier); + samples[0].setRegistrationDate(registrationDate); + samples[0].setModificationDate(modificationDate); samples[1] = new Sample(); samples[1].setType(sampleType); @@ -132,6 +152,10 @@ class SampleExpectations extends Expectations samples[1].setExperiment(experiment); samples[1].setProperty("$NAME", "Default Storage"); samples[1].setProperty("$STORAGE.BOX_NUM", "1111"); + samples[1].setRegistrator(registrator); + samples[1].setModifier(modifier); + samples[1].setRegistrationDate(registrationDate); + samples[1].setModificationDate(modificationDate); samples[2] = new Sample(); samples[2].setType(defaultSampleType); @@ -144,6 +168,10 @@ class SampleExpectations extends Expectations samples[2].setProject(defaultProject); samples[2].setExperiment(defaultExperiment); samples[2].setProperty("$NAME", "Default"); + samples[2].setRegistrator(registrator); + samples[2].setModifier(modifier); + samples[2].setRegistrationDate(registrationDate); + samples[2].setModificationDate(modificationDate); samples[3] = new Sample(); samples[3].setType(sampleType); @@ -157,6 +185,10 @@ class SampleExpectations extends Expectations samples[3].setExperiment(experiment); samples[3].setProperty("$NAME", "Child 1"); samples[3].setProperty("$STORAGE.BOX_NUM", "1"); + samples[3].setRegistrator(registrator); + samples[3].setModifier(modifier); + samples[3].setRegistrationDate(registrationDate); + samples[3].setModificationDate(modificationDate); samples[4] = new Sample(); samples[4].setType(sampleType); @@ -170,6 +202,10 @@ class SampleExpectations extends Expectations samples[4].setExperiment(experiment); samples[4].setProperty("$NAME", "Child 2"); samples[4].setProperty("$STORAGE.BOX_NUM", "2"); + samples[4].setRegistrator(registrator); + samples[4].setModifier(modifier); + samples[4].setRegistrationDate(registrationDate); + samples[4].setModificationDate(modificationDate); samples[0].setChildren(List.of(samples[3], samples[4])); samples[1].setChildren(List.of(samples[3], samples[4])); diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportTest.java index aab49b71d3d..39e86a4679a 100644 --- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportTest.java +++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/XLSExportTest.java @@ -90,26 +90,26 @@ public class XLSExportTest public static final Map<String, Map<String, List<Map<String, String>>>> EXPORT_FIELDS = Map.of( DATASET.toString(), Map.of( - "ATTACHMENT", List.of( - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Code"), - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Sample"), - Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "$ATTACHMENT")), - "RAW_DATA", List.of( + "ATTACHMENT", List.of( + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Code"), + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Sample"), + Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "$ATTACHMENT")), + "RAW_DATA", List.of( Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "$NAME"), Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Experiment"), Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Code"), Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), FIELD_ID_KEY, "NOTES")) ), EXPERIMENT.toString(), Map.of( - "COLLECTION", List.of( - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Identifier"), - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Project"), - Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), - FIELD_ID_KEY, "$DEFAULT_OBJECT_TYPE")), - "DEFAULT_EXPERIMENT", List.of(Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), - FIELD_ID_KEY, "FINISHED_FLAG"), - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Identifier"), - Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Code")) + "COLLECTION", List.of( + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Identifier"), + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Project"), + Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), + FIELD_ID_KEY, "$DEFAULT_OBJECT_TYPE")), + "DEFAULT_EXPERIMENT", List.of(Map.of(FIELD_TYPE_KEY, FieldType.PROPERTY.toString(), + FIELD_ID_KEY, "FINISHED_FLAG"), + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Identifier"), + Map.of(FIELD_TYPE_KEY, FieldType.ATTRIBUTE.toString(), FIELD_ID_KEY, "Code")) ), SAMPLE.toString(), Map.of( "DEFAULT", List.of( diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/resources/export-sample.xlsx b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/resources/export-sample.xlsx index 68a3239cd91e3ef2a78a60237b8d55c707bf8bb7..cb9c9457ec2a77c15e536c8cd0b40bccd9b05901 100644 GIT binary patch delta 4345 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 I_!sj30dYvwdjJ3c delta 3976 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 P1A;^Fh|`idf1~~bE_oNV -- GitLab