From ed3a13109499a6b9aa4de3dd313f5f096e1a09b7 Mon Sep 17 00:00:00 2001
From: juanf <juanf@ethz.ch>
Date: Mon, 27 Nov 2023 16:15:18 +0100
Subject: [PATCH] SSDM-14137: make storage positions be inside a collection

---
 .../generic/server/hotfix/ELNFixes.java       | 140 ++++++++++++++++++
 .../1/as/master-data/common-data-model.xls    | Bin 75776 -> 75776 bytes
 .../SampleForm/widgets/StorageListView.js     |   6 +
 3 files changed, 146 insertions(+)

diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/hotfix/ELNFixes.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/hotfix/ELNFixes.java
index 72a91ed2c67..b9ba0f449a6 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/hotfix/ELNFixes.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/hotfix/ELNFixes.java
@@ -18,8 +18,25 @@ package ch.systemsx.cisd.openbis.generic.server.hotfix;
 import static ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer.PROPERTY_CONFIGURER_BEAN_NAME;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
+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.create.ExperimentCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.create.ProjectCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.IProjectId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import org.apache.log4j.Logger;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult;
@@ -43,6 +60,7 @@ public class ELNFixes {
     public static void beforeUpgrade(String sessionToken) throws Exception {
         operationLog.info("ELNFixes beforeUpgrade START");
         IApplicationServerInternalApi api = CommonServiceProvider.getApplicationServerApi();
+        storageCollectionIntroduction(sessionToken, api);
         storageValidationLevelFix(sessionToken, api);
         nameNoRTFFix(sessionToken, api);
         // TODO(alaskowski): SSDM-13831: Do migration here!!!
@@ -155,4 +173,126 @@ public class ELNFixes {
         operationLog.info(String.format("ELNFixes fixProperties for propertiesTable %s", propertiesTable));
     }
 
+    private static void storageCollectionIntroduction(String sessionToken,
+            IApplicationServerInternalApi api)
+    {
+        SampleSearchCriteria criteria = new SampleSearchCriteria();
+        criteria.withType().withCode().thatEquals("STORAGE_POSITION");
+
+        SampleFetchOptions options = new SampleFetchOptions();
+        options.withSpace();
+        options.withExperiment();
+        options.withProject();
+
+        SearchResult<Sample> storagePositionResults = api.searchSamples(sessionToken, criteria, options);
+
+        Set<ProjectIdentifier> createdProjects = new HashSet<>();
+        Set<ExperimentIdentifier> createdExperiments = new HashSet<>();
+
+        List<SampleUpdate> storagePositionUpdates = new ArrayList<>();
+
+        for (Sample storagePosition:storagePositionResults.getObjects()) {
+            Space space = storagePosition.getSpace();
+            String spaceCode = space.getCode();
+            String postFix = "";
+
+            if (spaceCode.startsWith("STORAGE") && spaceCode.length() > "STORAGE".length())
+            {
+                int start = spaceCode.indexOf("_");
+                postFix = spaceCode.substring(start + 1);
+            }
+
+            ProjectIdentifier projectIdentifier = null;
+
+            if (storagePosition.getProject() == null)
+            {
+                String projectCode = "STORAGE_POSITIONS";
+                if (!postFix.isBlank()) {
+                    projectCode += "_" + postFix;
+                }
+                projectIdentifier = new ProjectIdentifier(spaceCode, projectCode);
+
+                if (createdProjects.contains(projectIdentifier) == false)
+                {
+                    Map<IProjectId, Project> projects =
+                            api.getProjects(sessionToken, Arrays.asList(projectIdentifier),
+                                    new ProjectFetchOptions());
+
+                    System.out.println("PROJECT [FETCH]: " + projectIdentifier + " " + projects.size() + " " + Thread.currentThread().getName());
+
+                    if (projects.size() == 1) {
+                        createdProjects.add(projectIdentifier);
+                    }
+                }
+
+                if (createdProjects.contains(projectIdentifier) == false)
+                {
+                    ProjectCreation creation = new ProjectCreation();
+                    creation.setSpaceId(space.getPermId());
+                    creation.setCode(projectCode);
+                    System.out.println("PROJECT [CREATION]: " + creation.getSpaceId() + " " + projectCode + " " + Thread.currentThread().getName());
+                    api.createProjects(sessionToken, Arrays.asList(creation));
+                    createdProjects.add(projectIdentifier);
+                }
+            } else {
+                projectIdentifier = storagePosition.getProject().getIdentifier();
+            }
+
+            ExperimentIdentifier experimentIdentifier;
+
+            if (storagePosition.getExperiment() == null)
+            {
+                String experimentCode = "STORAGE_POSITIONS_COLLECTION";
+                if (!postFix.isBlank()) {
+                    experimentCode += "_" + postFix;
+                }
+                String experimentType = "COLLECTION";
+
+                experimentIdentifier = new ExperimentIdentifier(spaceCode, projectIdentifier.getIdentifier().substring(projectIdentifier.getIdentifier().lastIndexOf('/') + 1), experimentCode);
+
+                if (createdExperiments.contains(experimentIdentifier) == false)
+                {
+                    Map<IExperimentId, Experiment> experiments =
+                            api.getExperiments(sessionToken, Arrays.asList(experimentIdentifier),
+                                    new ExperimentFetchOptions());
+
+                    System.out.println("EXPERIMENT [FETCH]: " + experimentIdentifier + " " + experiments.size() + " " + Thread.currentThread().getName());
+
+                    if (experiments.size() == 1) {
+                        createdExperiments.add(experimentIdentifier);
+                    }
+                }
+
+                if (createdExperiments.contains(experimentIdentifier) == false)
+                {
+                    ExperimentCreation creation = new ExperimentCreation();
+                    creation.setProjectId(projectIdentifier);
+                    creation.setCode(experimentCode);
+                    creation.setTypeId(new EntityTypePermId(experimentType, EntityKind.EXPERIMENT));
+                    System.out.println("EXPERIMENT [CREATION]: " + creation.getProjectId() + " " + experimentCode + " " + Thread.currentThread().getName());
+                    api.createExperiments(sessionToken, Arrays.asList(creation));
+                    createdExperiments.add(experimentIdentifier);
+                }
+            } else {
+                experimentIdentifier = storagePosition.getExperiment().getIdentifier();
+            }
+
+            SampleUpdate sampleUpdate = new SampleUpdate();
+            sampleUpdate.setSampleId(storagePosition.getPermId());
+            sampleUpdate.setExperimentId(experimentIdentifier);
+
+            storagePositionUpdates.add(sampleUpdate);
+
+            if (storagePositionUpdates.size() > 1000) {
+                api.updateSamples(sessionToken, storagePositionUpdates);
+                storagePositionUpdates.clear();
+            }
+        }
+
+        if (storagePositionUpdates.isEmpty() == false) {
+            api.updateSamples(sessionToken, storagePositionUpdates);
+            storagePositionUpdates.clear();
+        }
+    }
+
 }
diff --git a/ui-eln-lims/src/core-plugins/eln-lims/1/as/master-data/common-data-model.xls b/ui-eln-lims/src/core-plugins/eln-lims/1/as/master-data/common-data-model.xls
index 86a4612971080b10dfbf33ebaa8b30de2430e281..d00993ab3e5d6e2edf97a7eb5d7f79cab09d8828 100644
GIT binary patch
delta 2132
zcmaJ@U1%It6#nk)>`!8vNg{>P#F`Y_TCiBPKT&JVZnn{A%%)9jlD2kdNOm`Ag28Mb
zDhQK4=!+u4h~SIhgAWP?$zlYHdGe{E^u-2(iXc7|>kn*$B8q<J&g@J#S=@oU`<-*{
zIp6)xxsxniH<zxPAJ3b~rNYXa>7I43Y`$s?{^I>*&b1!cQ&``%u9oh;U%tI^d~uVh
zQjIUF&9-uKtF4;)QKkNMZ!27C8LWKYTs&-Sx4nVB+2p&Om*aq4S?Rm6)7=R?I69U)
zm450(?K?k`8yy@Q%ngsW1A#BHb<lQkVbLiS%H1Oi<=Km~3on+B{$G}@dGr0bp`jD~
ztnuV<SA!anU%UNsQMK;=h57lylvJ*~arWnJM`jf8vIG1y3;gjCu>Ue};4R?8_ka(s
z0Pa;Fc@6mL8=(3FaP=mzcB^t__8w&(vXJn;zR(%}sLO)k{d(a`HB<R)?mO3Q!voCA
zkFt<5+HjI+v+Yy^+nBb=8tr|)f$emIz2i}w8y22u5IEVucBX;tT$C`(_ky;)!Zjjz
ze#_pbHst-l%JQxEW9~m_h8)*|)bWubIvXN`Nb32%7&4e*0YM^07HO`^NDwLd#4fUA
zk>R?kkwT7-p?xBc1(O-XciPpPGJ#Wc%A%92q#390X>1RQjVpsbJ47-1IPgKFi4hzR
zkO-T>;ULR|uFxMMgT5mna${tZ4WUWr-XM+i!XgR3#3a*L5cWcCl4LA>P9I4YQA3dE
zXhFK+BiSc?@R97RDSbx8TtexGI7Q?v9^oo-p3}VjU#UP?Nt(sOTvyS`627oG3{z0a
zAZ0Aw9@%$ZnRrgyr9u`Dah0e%_tjK(1sZqAoL4bA4~C&8ksT<KS8<{zLSF*?I2NKL
z(c>XX5j_^7CJcqm%ByCgf}eAU<?kXah9z2vW<s=$h}S>h-AXhUB8zCAXbs2kS_<g$
z{;u{6_F@OR_zdvr<+B^zw8%}jNvA`%iJOAk?`T{78)3?i^JZ@EbL%}t?Ww<FrA=8y
zVO#fZm>wU=%sm<+xk65G3Y$HO=Fz6W{^Z7u6tg7u68bmAR!OAsEK)(rCN{d4DL==3
zu)ST?eXh+TSvVQSx8WH+?K<AkgmM7|M^Eq35Zy`0sUzgn5pq;Q^N~Y2N*Ejp7&xlg
z`=YwXbwUmjBSJ<4J*7FwU{0ypKu_z4+CWb;Lf#b7Ko{t@@QL(``wHPeOCzFzE^?n9
z=-v9T#kzqmh6BCIsVI5}H|}*yn#u^12+b1XGrEY6YI4XOD``10TKc3WQR2L&dH-7I
zv$Vt_@){@WTLZX+WxNy2+yssr9au>WuudP3ARqqi#p~X+jUBD>65z4;GLT>1?;AIk
V|Gc?Bk$-!d{~~<)TaRi_{0E`wW5xgg

delta 1825
zcmZuyTWAzl82--e?CxYWnIvsRyr72G8zS}+HL;brE~1Gw>m??{>`r2Km)Z?@dx;=S
zUixIAg?TR2cOS%U6%+%44~ihZR4JuJ5NtyfDXA9((eFPqd$t>Q4tv<|zn$;DoSCV6
z_S8N5;)I?2aoJ4w%)h?}r|s`7_et>DF1NUkMWRmJ{U_AKPt6lm=HjQ+eA(&b`?5Lb
zk#Z)ttZaVe|1wbdD^=>W2EAZc&#~kmOU}fB;mYNn`%5alBeTt$OA5F)3amK>be#ms
zQ^4^bfZ3mbzb^nct^#{*1MY7?=R;s_1~@-kDSx|M*=t=`!T05*aV&C?2riWGs8VHe
z;!odi#|Fmbqg*&vEA|u3mmO#zJE&!c>U;&Yqh2=9!1r*?&Nl}SHZUA&ARDeZ8{Z>Z
zc9wfBk&y<zx%cdrw<52F^{l<nxia$fe9Tu?0tZwKX}m!Sl6VF?xQqOtQjuH&WRT`Q
zO{+tc_j6g=M~dLWCOOd!XrFYXlVW7Bl)FSfOx<pLM9UCa$oLpFFh(WEB2wDOVta(7
zd}(w>VFvXPI}Ng^+iXybWHJWX)UA%9NWoo5EIEFNQC#@KFoYJN<PstYBUuZQu4M2z
zcd5#-K0f^CMD>v#W$+pIX|&)7Eu=pE*vGm^1nHNHaS{=~5oP0REzkMd@l)<%mZM{>
zTsdX^uUt7cDT7VM(k2>>GRvtr(N{*7z)pN=P?BhyK@L&3L4FhVnxf}ail}IUE+8ry
zw2<f<gPMtWS0majL}i0qqKOFQb+z_I2j-bl8eIm(vV>#CRJv8|WS%*NJ&#)s=Qu$W
zj#yqLu>*Z@^x=8c#L{kM$m{qR`QY_`Yy3R#yNmtCz7@S(ZQ9<`g!&^29tpYFVvt;f
zDj$z+s`2sa_;?W?>6)h*d=WA5R4VxS`6nNEhQkBS@!2L|Q*d)`RbL8=v5adM*H(03
zCGkUC((k7+#+d((IjUv#*MD5gHUt})Ywd0e7l}|C)iIr`jNF*2j;h3~jp|Wa)Q_sf
zcJV7~Cw}8*R14a#I;jQv=}GO-MJ?2gYQc=^G!rcZr57vwqNb8%5TRMrb0CL=s9JWp
zJw;viv~F=ylPIbMMAKMEovT|Z&3r)H3C7DtMI6F*s~wjUGU`2yEKeJM=bToY3!Il9
nw#eyB3t7bv!P{W{%llVOtXAFX(yN(u3EYzJ-IZsnR9oU5BR42m

diff --git a/ui-eln-lims/src/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js b/ui-eln-lims/src/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
index d1100528832..820132f2e90 100644
--- a/ui-eln-lims/src/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
+++ b/ui-eln-lims/src/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/widgets/StorageListView.js
@@ -166,6 +166,7 @@ function StorageListView(storageListController, storageListModel) {
 					code : uuid,
 					identifier : null,
 					sampleTypeCode : "STORAGE_POSITION",
+					experimentIdentifier: null,
 					properties : {}
 			};
 			_this._storageListModel.sample.children.push(newChildSample);
@@ -244,6 +245,11 @@ function StorageListView(storageListController, storageListModel) {
                         if(sampleChild.newSampleJustCreated) {
                             sampleChild.identifier = IdentifierUtil.getSampleIdentifier(storageSpaceCode, null, sampleChild.code);
                             delete sampleChild.newSampleJustCreated;
+                            var postFix = "";
+                            if(storageSpaceCode.length > "STORAGE".length) {
+                                postFix = storageSpaceCode.substring("STORAGE".length + 1);
+                            }
+                            sampleChild.experimentIdentifier = "/" + storageSpaceCode + "/STORAGE_POSITIONS" + postFix + "/STORAGE_POSITIONS_COLLECTION" + postFix;
                         } else {
                             // On update the identifier should be set, fail if not
                         }
-- 
GitLab