From 6b19fab08f5e48f71b091dcb1671ba6f2eec1a6f Mon Sep 17 00:00:00 2001
From: vkovtun <viktor.kovtun@id.ethz.ch>
Date: Fri, 31 Mar 2023 12:38:59 +0200
Subject: [PATCH] SSDM-13256: Added missing columns for vocabulary type.

---
 .../helper/XLSVocabularyExportHelper.java     |  22 ++++++++++++++----
 .../xls/export/VocabularyExpectations.java    |  17 ++++++++++++++
 .../export/resources/export-vocabulary.xlsx   | Bin 5385 -> 5562 bytes
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSVocabularyExportHelper.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSVocabularyExportHelper.java
index 457a39ad488..39cc75f1741 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSVocabularyExportHelper.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/xls/export/helper/XLSVocabularyExportHelper.java
@@ -15,6 +15,8 @@
  */
 package ch.ethz.sis.openbis.generic.server.xls.export.helper;
 
+import static ch.ethz.sis.openbis.generic.server.xls.export.Attribute.*;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -115,7 +117,7 @@ public class XLSVocabularyExportHelper extends AbstractXLSExportHelper<IEntityTy
                         {
                             if (FieldType.valueOf(attribute.get(FIELD_TYPE_KEY)) == FieldType.ATTRIBUTE)
                             {
-                                return Attribute.valueOf(attribute.get(FIELD_ID_KEY)).getName();
+                                return valueOf(attribute.get(FIELD_ID_KEY)).getName();
                             } else
                             {
                                 throw new IllegalArgumentException();
@@ -126,7 +128,7 @@ public class XLSVocabularyExportHelper extends AbstractXLSExportHelper<IEntityTy
                         .toArray(Attribute[]::new);
                 final Set<Attribute> selectedAttributes = selectedExportAttributes.stream()
                         .filter(map -> map.get(FIELD_TYPE_KEY).equals(FieldType.ATTRIBUTE.toString()))
-                        .map(map -> Attribute.valueOf(map.get(FIELD_ID_KEY)))
+                        .map(map -> valueOf(map.get(FIELD_ID_KEY)))
                         .collect(Collectors.toCollection(() -> EnumSet.noneOf(Attribute.class)));
                 final Stream<String> requiredForImportAttributeNameStream = compatibleWithImport
                         ? Arrays.stream(requiredForImportAttributes)
@@ -152,7 +154,7 @@ public class XLSVocabularyExportHelper extends AbstractXLSExportHelper<IEntityTy
                         {
                             if (FieldType.valueOf(field.get(FIELD_TYPE_KEY)) == FieldType.ATTRIBUTE)
                             {
-                                return getAttributeValue(vocabulary, Attribute.valueOf(field.get(FIELD_ID_KEY)));
+                                return getAttributeValue(vocabulary, valueOf(field.get(FIELD_ID_KEY)));
                             } else
                             {
                                 throw new IllegalArgumentException();
@@ -188,7 +190,7 @@ public class XLSVocabularyExportHelper extends AbstractXLSExportHelper<IEntityTy
 
     protected Attribute[] getAttributes()
     {
-        return new Attribute[] { Attribute.VERSION, Attribute.CODE, Attribute.DESCRIPTION };
+        return new Attribute[] { VERSION, CODE, DESCRIPTION, REGISTRATOR, REGISTRATION_DATE, MODIFICATION_DATE };
     }
 
     protected String getAttributeValue(final Vocabulary vocabulary, final Attribute attribute)
@@ -207,6 +209,18 @@ public class XLSVocabularyExportHelper extends AbstractXLSExportHelper<IEntityTy
             {
                 return vocabulary.getDescription();
             }
+            case REGISTRATOR:
+            {
+                return vocabulary.getRegistrator().getUserId();
+            }
+            case REGISTRATION_DATE:
+            {
+                return DATE_FORMAT.format(vocabulary.getRegistrationDate());
+            }
+            case MODIFICATION_DATE:
+            {
+                return DATE_FORMAT.format(vocabulary.getModificationDate());
+            }
             default:
             {
                 return null;
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/VocabularyExpectations.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/VocabularyExpectations.java
index c3bd23e763d..2d0130a5b2d 100644
--- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/VocabularyExpectations.java
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/VocabularyExpectations.java
@@ -16,7 +16,9 @@
 package ch.ethz.sis.openbis.generic.server.xls.export;
 
 import java.util.Arrays;
+import java.util.Calendar;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 import org.jmock.Expectations;
@@ -25,6 +27,7 @@ import org.jmock.lib.action.CustomAction;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyFetchOptions;
@@ -37,6 +40,16 @@ class VocabularyExpectations extends Expectations
 
     public VocabularyExpectations(final IApplicationServerApi api, final boolean exportReferred)
     {
+        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");
+
         allowing(api).getVocabularies(with(XLSExportTest.SESSION_TOKEN), with(new CollectionMatcher<>(
                         Collections.singletonList(new VocabularyPermId("ANTIBODY.DETECTION")))),
                 with(any(VocabularyFetchOptions.class)));
@@ -48,11 +61,15 @@ class VocabularyExpectations extends Expectations
             public Object invoke(final Invocation invocation) throws Throwable
             {
                 final VocabularyFetchOptions fetchOptions = (VocabularyFetchOptions) invocation.getParameter(2);
+                fetchOptions.withRegistrator();
 
                 final Vocabulary vocabulary = new Vocabulary();
                 vocabulary.setFetchOptions(fetchOptions);
                 vocabulary.setCode("ANTIBODY.DETECTION");
                 vocabulary.setDescription("Protein detection system");
+                vocabulary.setRegistrator(registrator);
+                vocabulary.setRegistrationDate(registrationDate);
+                vocabulary.setModificationDate(modificationDate);
 
                 vocabulary.setTerms(getVocabularyTerms(fetchOptions));
 
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/resources/export-vocabulary.xlsx b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/generic/server/xls/export/resources/export-vocabulary.xlsx
index fc3e697b1d6025a5f1cc80308b333a37aee525f6..59b389334173acaf4b8db18f10be6908c067c6f9 100644
GIT binary patch
delta 3260
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

delta 3111
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
R12Y1_q_7H5-D5u8{SUV>bYcJi

-- 
GitLab