diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPAuthenticationService.java b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPAuthenticationService.java index 9652cd18ec44e30daefa0f139253835c055742cb..a2df7d8aff09f3292cbde80229de4a47327f8d13 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPAuthenticationService.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPAuthenticationService.java @@ -207,4 +207,8 @@ public class LDAPAuthenticationService implements IAuthenticationService return configured; } + public List<Principal> listPrincipalsByKeyValue(String key, String value) + { + return query.listPrincipalsByKeyValue(key, value); + } } diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java index 1522ba4a397dd667d951aabb541e4600730bdbaa..13729994ed398288ac3019a62ce70c8fa05a9e62 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfiguration.java @@ -78,6 +78,8 @@ public final class LDAPDirectoryConfiguration private String securityPrincipalPassword; + private String searchBase = ""; + /** * Returns <code>true</code> if this configuration is complete. */ @@ -322,6 +324,19 @@ public final class LDAPDirectoryConfiguration this.queryTemplate = queryTemplate; } } + + public String getSearchBase() + { + return searchBase; + } + + public void setSearchBase(String searchBase) + { + if (isResolved(searchBase)) + { + this.searchBase = searchBase; + } + } /** * The read timeout (in s). Default value: <code>10s</code> diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPPrincipalQuery.java b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPPrincipalQuery.java index c756ce12df881ddaf6345194c84920197fe18686..381c490751aeaefee04daffd08597f70dc3a07fb 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPPrincipalQuery.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/ldap/LDAPPrincipalQuery.java @@ -284,7 +284,7 @@ public final class LDAPPrincipalQuery implements ISelfTestable { try { - return primListPrincipalsByKeyValue(key, value, additionalAttributesOrNull, limit); + return primListPrincipalsByKeyValue(config.getSearchBase(), key, value, additionalAttributesOrNull, limit); } catch (RuntimeException ex) { contextHolder.set(null); @@ -307,7 +307,7 @@ public final class LDAPPrincipalQuery implements ISelfTestable throw firstException; } - private List<Principal> primListPrincipalsByKeyValue(String key, String value, + private List<Principal> primListPrincipalsByKeyValue(String searchBase, String key, String value, Collection<String> additionalAttributesOrNull, int limit) { final List<Principal> principals = new ArrayList<Principal>(); @@ -318,7 +318,7 @@ public final class LDAPPrincipalQuery implements ISelfTestable final DirContext context = createContext(false); final SearchControls ctrl = new SearchControls(); ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE); - final NamingEnumeration<SearchResult> enumeration = context.search("", query, ctrl); + final NamingEnumeration<SearchResult> enumeration = context.search(searchBase, query, ctrl); int count = 0; while (count++ < limit && enumeration.hasMore()) { diff --git a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfigurationTest.java b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfigurationTest.java index b9a518f92d94e81ff64d7b03a8709e48c16ff3e4..eb6fb42f845a32c9a2a4d8c70b0c81cd0da1e540 100644 --- a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfigurationTest.java +++ b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/ldap/LDAPDirectoryConfigurationTest.java @@ -28,6 +28,25 @@ import org.testng.annotations.Test; public class LDAPDirectoryConfigurationTest { + @Test + public void testLDAPDirectoryConfigurationUnresolvedVariableSearchBase() + { + final LDAPDirectoryConfiguration config = new LDAPDirectoryConfiguration(); + config.setSearchBase(" "); + assertEquals("", config.getSearchBase()); + config.setQueryTemplate("${ldap.searchBase}"); + assertEquals("", config.getSearchBase()); + } + + @Test + public void testLDAPDirectoryConfigurationResolvedVariableSearchBase() + { + final LDAPDirectoryConfiguration config = new LDAPDirectoryConfiguration(); + final String searchBase = "ou=a,o=b,c=c"; + config.setSearchBase(searchBase); + assertEquals(searchBase, config.getSearchBase()); + } + @Test public void testLDAPDirectoryConfigurationUnresolvedVariableQueryTemplate() { @@ -37,7 +56,7 @@ public class LDAPDirectoryConfigurationTest config.setQueryTemplate("${ldap.queryTemplate}"); assertEquals(LDAPDirectoryConfiguration.DEFAULT_QUERY_TEMPLATE, config.getQueryTemplate()); } - + @Test public void testLDAPDirectoryConfigurationResolvedVariableQueryTemplate() { diff --git a/common/source/java/genericCommonContext.xml b/common/source/java/genericCommonContext.xml index f943fb1d092bc736a288bb46c5478cc02efa08f6..f9fac048565cc93e290b77f24248b70b8412a32d 100644 --- a/common/source/java/genericCommonContext.xml +++ b/common/source/java/genericCommonContext.xml @@ -66,6 +66,7 @@ <property name="securityPrincipalDistinguishedName" value="${ldap.security.principal.distinguished.name}" /> <property name="securityPrincipalPassword" value="${ldap.security.principal.password}" /> <property name="referral" value="${ldap.referral}" /> + <property name="searchBase" value="${ldap.searchBase}" /> <property name="userIdAttributeName" value="${ldap.attributenames.user.id}" /> <property name="emailAttributeName" value="${ldap.attributenames.email}" /> <property name="firstNameAttributeName" value="${ldap.attributenames.first.name}" /> diff --git a/commonbase/sourceTest/java/ch/systemsx/cisd/common/test/ToStringMatcher.java b/commonbase/sourceTest/java/ch/systemsx/cisd/common/test/ToStringMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..328b82754304b6d0677f941a3e251d100238ee60 --- /dev/null +++ b/commonbase/sourceTest/java/ch/systemsx/cisd/common/test/ToStringMatcher.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.common.test; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; + +/** + * @author Franz-Josef Elmer + */ +public class ToStringMatcher<T> extends BaseMatcher<T> +{ + private String expectedToStringString; + + public ToStringMatcher(T expectedItem) + { + this(String.valueOf(expectedItem)); + } + + public ToStringMatcher(String expectedToStringString) + { + this.expectedToStringString = expectedToStringString; + } + + @Override + public boolean matches(Object item) + { + return String.valueOf(item).equals(expectedToStringString); + } + + @Override + public void describeTo(Description description) + { + description.appendText(expectedToStringString); + } + +} diff --git a/datastore_server/etc/service.properties b/datastore_server/etc/service.properties index 21d6021e6f979dcdab9110ac5f4fab9771912758..6da5a9c9691228400a045aab28bf866a60731178 100644 --- a/datastore_server/etc/service.properties +++ b/datastore_server/etc/service.properties @@ -212,6 +212,8 @@ validator.site.value-range = [0,Infinity) # E.g. 'code-extractor' property for the thread 'my-etl' should be specified as 'my-etl.code-extractor' inputs=main-thread, tsv-thread, csv-thread, simple-thread, hdf5-thread, dss-system-test-thread +dss-rpc.put.CUSTOM-IMPORT = test-custom-import + # True if incoming directories should be created on server startup if they don't exist. # Default - false (server will fail at startup if one of incoming directories doesn't exist). incoming-dir-create = true diff --git a/datastore_server/source/core-plugins/core-plugins.properties b/datastore_server/source/core-plugins/core-plugins.properties index ad076de30cf2a46969625829ac64e57daf8d3a76..36cf1a47b4385a3b705c054d2d457a8e7f259776 100644 --- a/datastore_server/source/core-plugins/core-plugins.properties +++ b/datastore_server/source/core-plugins/core-plugins.properties @@ -6,7 +6,7 @@ # List of comma-separated regular expressions. If a technology (i.e. module) from the core plugins # folder is matching one of these regular expressions it is enabled. # -#enabled-modules = +enabled-modules = import-test # # List of comma-separated full core plugin names (or prefixes) of core plugins to be disabled diff --git a/datastore_server/source/core-plugins/import-test/1/as/custom-imports/test-custom-import/plugin.properties b/datastore_server/source/core-plugins/import-test/1/as/custom-imports/test-custom-import/plugin.properties new file mode 100644 index 0000000000000000000000000000000000000000..fcbdb19ef13cab01d292b9a91fddadf0fea36323 --- /dev/null +++ b/datastore_server/source/core-plugins/import-test/1/as/custom-imports/test-custom-import/plugin.properties @@ -0,0 +1,4 @@ +name = Test custom import +dss-code = STANDARD +dropbox-name = test-custom-import +description = This is a test custom import \ No newline at end of file diff --git a/datastore_server/source/core-plugins/import-test/1/as/services/import-test/import-test.py b/datastore_server/source/core-plugins/import-test/1/as/services/import-test/import-test.py new file mode 100644 index 0000000000000000000000000000000000000000..ddf1d71e354693600f1cf287d2cfa83379490ae2 --- /dev/null +++ b/datastore_server/source/core-plugins/import-test/1/as/services/import-test/import-test.py @@ -0,0 +1,36 @@ +def process(context, parameters): + print(">>> import-test <<<"); + + sessionToken = context.getSessionToken() + operation = parameters.get("operation"); + uploadKey = parameters.get("uploadKey"); + typeCode = parameters.get("typeCode"); + asynchrounous = parameters.get("async"); + userEmail = parameters.get("userEmail"); + defaultSpaceIdentifier = parameters.get("defaultSpaceIdentifier"); + spaceIdentifierOverride = parameters.get("spaceIdentifierOverride"); + experimentIdentifierOverride = parameters.get("experimentIdentifierOverride"); + updateExisting = parameters.get("updateExisting"); + ignoreUnregistered = parameters.get("ignoreUnregistered"); + customImportCode = parameters.get("customImportCode"); + + if operation == "createExperiments": + return context.getImportService().createExperiments(sessionToken, uploadKey, typeCode, asynchrounous, userEmail); + elif operation == "updateExperiments": + return context.getImportService().updateExperiments(sessionToken, uploadKey, typeCode, asynchrounous, userEmail); + elif operation == "createSamples": + return context.getImportService().createSamples(sessionToken, uploadKey, typeCode, defaultSpaceIdentifier, spaceIdentifierOverride, experimentIdentifierOverride, updateExisting, asynchrounous, userEmail); + elif operation == "updateSamples": + return context.getImportService().updateSamples(sessionToken, uploadKey, typeCode, defaultSpaceIdentifier, spaceIdentifierOverride, experimentIdentifierOverride, asynchrounous, userEmail); + elif operation == "updateDataSets": + return context.getImportService().updateDataSets(sessionToken, uploadKey, typeCode, asynchrounous, userEmail); + elif operation == "createMaterials": + return context.getImportService().createMaterials(sessionToken, uploadKey, typeCode, updateExisting, asynchrounous, userEmail); + elif operation == "updateMaterials": + return context.getImportService().updateMaterials(sessionToken, uploadKey, typeCode, ignoreUnregistered, asynchrounous, userEmail); + elif operation == "generalImport": + return context.getImportService().generalImport(sessionToken, uploadKey, defaultSpaceIdentifier, updateExisting, asynchrounous, userEmail); + elif operation == "customImport": + return context.getImportService().customImport(sessionToken, uploadKey, customImportCode, asynchrounous, userEmail); + + return None; diff --git a/datastore_server/source/core-plugins/import-test/1/as/services/import-test/plugin.properties b/datastore_server/source/core-plugins/import-test/1/as/services/import-test/plugin.properties new file mode 100644 index 0000000000000000000000000000000000000000..edcd58fc8199dc34bc0c90b0b5a273911b65b24f --- /dev/null +++ b/datastore_server/source/core-plugins/import-test/1/as/services/import-test/plugin.properties @@ -0,0 +1,2 @@ +class = ch.ethz.sis.openbis.generic.server.asapi.v3.helper.service.JythonBasedCustomASServiceExecutor +script-path = import-test.py \ No newline at end of file diff --git a/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/plugin.properties b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/plugin.properties new file mode 100644 index 0000000000000000000000000000000000000000..f71fcdefe5dd50af4ba8f82b6b7ebf51fedbadc1 --- /dev/null +++ b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/plugin.properties @@ -0,0 +1,6 @@ +incoming-dir = ${root-dir}/incoming-test-custom-import +incoming-dir-create = true +incoming-data-completeness-condition = auto-detection +top-level-data-set-handler = ch.systemsx.cisd.etlserver.registrator.api.v2.JythonTopLevelDataSetHandlerV2 +script-path = script.py +storage-processor = ch.systemsx.cisd.etlserver.DefaultStorageProcessor \ No newline at end of file diff --git a/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/script.py b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/script.py new file mode 100644 index 0000000000000000000000000000000000000000..7fc3d060f7dbc447824223fc6530384862c0d6ec --- /dev/null +++ b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test-custom-import/script.py @@ -0,0 +1,5 @@ +def process(transaction): + data = transaction.createNewDataSet("HCS_IMAGE", transaction.getIncoming().getName()) + data.setExperiment(transaction.getExperiment("/CISD/NEMO/EXP1")) + data.setPropertyValue("COMMENT", "test comment " + transaction.getIncoming().getName()) + transaction.moveFile(transaction.getIncoming().getPath(), data) \ No newline at end of file diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java index 08aa2477a357531cb2b13b031478f46bf5889111..208c4ab48e4bdf6e83a310ec5d5cd33d6199439c 100644 --- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/AbstractFileTest.java @@ -27,15 +27,17 @@ public class AbstractFileTest extends SystemTestCase { public static final String TEST_USER = "test"; - + public static final String TEST_SPACE_USER = "test_space"; + public static final String ETL_SERVER_USER = "etlserver"; + public static final String PASSWORD = "password"; protected IGeneralInformationService gis; protected IApplicationServerApi as; - + protected IDataStoreServerApi dss; protected String dataSetCode; diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateExperimentsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateExperimentsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8c5d208d9315b38a73e7ae4070d706f722305d35 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateExperimentsImportTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.delete.ExperimentDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; + +/** + * @author pkupczyk + */ +public class CreateExperimentsImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testCreate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String experimentCode = "TEST-IMPORT-" + UUID.randomUUID().toString(); + ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("/TEST-SPACE/TEST-PROJECT/" + experimentCode); + + try + { + ImportFile file = new ImportFile("identifier", "DESCRIPTION"); + file.addLine(experimentIdentifier.getIdentifier(), "imported description"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Experiment experiment = getObject(sessionToken, experimentIdentifier); + assertNull(experiment); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, "SIRNA_HCS"); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "createExperiments", parameters); + + experiment = getObject(sessionToken, experimentIdentifier, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description", experiment.getProperty("DESCRIPTION")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Experiment Batch Registration successfully performed"); + } else + { + assertEquals("1 experiment(s) found and registered.", message); + assertNoEmails(timestamp); + } + } finally + { + ExperimentDeletionOptions options = new ExperimentDeletionOptions(); + options.setReason("cleanup"); + as.deleteExperiments(sessionToken, Arrays.asList(experimentIdentifier), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateMaterialsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateMaterialsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c507327c7ba2d5ee66cb616ce2d6995a4adb54e0 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateMaterialsImportTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.delete.MaterialDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.MaterialPermId; + +/** + * @author pkupczyk + */ +public class CreateMaterialsImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testCreate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + MaterialPermId materialPermId = new MaterialPermId("TEST-IMPORT-" + UUID.randomUUID().toString(), "VIRUS"); + + try + { + ImportFile file = new ImportFile("code", "DESCRIPTION"); + file.addLine(materialPermId.getCode(), "imported description"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Material material = getObject(sessionToken, materialPermId); + assertNull(material); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, materialPermId.getTypeCode()); + parameters.put(PARAM_UPDATE_EXISTING, false); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "createMaterials", parameters); + + material = getObject(sessionToken, materialPermId, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description", material.getProperty("DESCRIPTION")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Material Batch Registration successfully performed"); + } else + { + assertEquals("Registration/update of 1 material(s) is complete.", message); + assertNoEmails(timestamp); + } + } finally + { + MaterialDeletionOptions options = new MaterialDeletionOptions(); + options.setReason("cleanup"); + as.deleteMaterials(sessionToken, Arrays.asList(materialPermId), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateSamplesImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateSamplesImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..83f7a31f810f3ed06dbb1bc185b63938514e760b --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CreateSamplesImportTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.delete.SampleDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; + +/** + * @author pkupczyk + */ +public class CreateSamplesImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testCreate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String sampleCode = "TEST-IMPORT-" + UUID.randomUUID().toString(); + SampleIdentifier sampleIdentifier = new SampleIdentifier("/TEST-SPACE/" + sampleCode); + + try + { + ImportFile file = new ImportFile("identifier", "COMMENT"); + file.addLine(sampleIdentifier.getIdentifier(), "imported comment"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Sample sample = getObject(sessionToken, sampleIdentifier); + assertNull(sample); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, "CELL_PLATE"); + parameters.put(PARAM_UPDATE_EXISTING, false); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "createSamples", parameters); + + sample = getObject(sessionToken, sampleIdentifier, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported comment", sample.getProperty("COMMENT")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Sample Batch Registration successfully performed"); + } else + { + assertEquals("Registration of 1 sample(s) is complete.", message); + assertNoEmails(timestamp); + } + } finally + { + SampleDeletionOptions options = new SampleDeletionOptions(); + options.setReason("cleanup"); + as.deleteSamples(sessionToken, Arrays.asList(sampleIdentifier), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CustomImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CustomImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce545c8b938569d0ae08b3810deda520d9bea72e --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/CustomImportTest.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.eclipse.jetty.client.api.ContentProvider; +import org.eclipse.jetty.client.util.MultiPartContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.delete.DataSetDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; + +/** + * @author pkupczyk + */ +public class CustomImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testImport(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + DataSetPermId dataSetPermId = new DataSetPermId("TEST-IMPORT-" + UUID.randomUUID().toString()); + + try + { + MultiPartContentProvider multiPart = new MultiPartContentProvider(); + ContentProvider contentProvider = new StringContentProvider("test-file-content"); + multiPart.addFilePart(TEST_UPLOAD_KEY, dataSetPermId.getPermId(), contentProvider, null); + multiPart.close(); + + uploadFiles(sessionToken, TEST_UPLOAD_KEY, multiPart); + + DataSet dataSet = getObject(sessionToken, dataSetPermId); + assertNull(dataSet); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_CUSTOM_IMPORT_CODE, "test-custom-import"); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "customImport", parameters); + + dataSet = getObject(sessionToken, dataSetPermId, timestamp, DEFAULT_TIMEOUT); + assertEquals("test comment " + dataSetPermId.getPermId(), dataSet.getProperty("COMMENT")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Custom import successfully performed"); + } else + { + assertEquals("Import successfully completed.", message); + assertNoEmails(timestamp); + } + } finally + { + DataSetDeletionOptions options = new DataSetDeletionOptions(); + options.setReason("cleanup"); + as.deleteDataSets(sessionToken, Arrays.asList(dataSetPermId), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..262d1f3c5f886cd138e8cb63535cd635992b7ed1 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.eclipse.jetty.client.api.ContentProvider; +import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.client.util.MultiPartContentProvider; +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.delete.MaterialDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.IMaterialId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.MaterialPermId; +import ch.systemsx.cisd.common.utilities.TestResources; + +/** + * @author pkupczyk + */ +public class GeneralImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testImport(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + MaterialPermId materialPermId1 = new MaterialPermId("TEST-IMPORT-1", "VIRUS"); + MaterialPermId materialPermId2 = new MaterialPermId("TEST-IMPORT-2", "VIRUS"); + + deleteMaterials(sessionToken, materialPermId1, materialPermId2); + + try + { + Material material1 = getObject(sessionToken, materialPermId1); + assertNull(material1); + + Material material2 = getObject(sessionToken, materialPermId2); + assertNull(material2); + + TestResources resources = new TestResources(getClass()); + File materialsFile = resources.getResourceFile("materials_excel_97_2003.xls"); + + MultiPartContentProvider multiPart = new MultiPartContentProvider(); + ContentProvider contentProvider = new BytesContentProvider(FileUtils.readFileToByteArray(materialsFile)); + multiPart.addFilePart(TEST_UPLOAD_KEY, materialsFile.getName(), contentProvider, null); + multiPart.close(); + + uploadFiles(sessionToken, TEST_UPLOAD_KEY, multiPart); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_UPDATE_EXISTING, false); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "generalImport", parameters); + + material1 = getObject(sessionToken, materialPermId1, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description 1", material1.getProperty("DESCRIPTION")); + + material2 = getObject(sessionToken, materialPermId2, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description 2", material2.getProperty("DESCRIPTION")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "General Batch Import successfully performed"); + } else + { + assertEquals("Registration/update of 2 material(s) is complete.\nRegistration of 0 sample(s) is complete.", message); + assertNoEmails(timestamp); + } + } finally + { + deleteMaterials(sessionToken, materialPermId1, materialPermId2); + } + } + + private void deleteMaterials(String sessionToken, IMaterialId... materialIds) + { + MaterialDeletionOptions options = new MaterialDeletionOptions(); + options.setReason("cleanup"); + as.deleteMaterials(sessionToken, Arrays.asList(materialIds), options); + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTestResources/materials_excel_97_2003.xls b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTestResources/materials_excel_97_2003.xls new file mode 100644 index 0000000000000000000000000000000000000000..3e18171654156d191bf5dd8f036f415cb1a003d4 Binary files /dev/null and b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/GeneralImportTestResources/materials_excel_97_2003.xls differ diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ObjectsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ObjectsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b41d7e9b67760a962e23299bd4b5fa35e374b9dd --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ObjectsImportTest.java @@ -0,0 +1,261 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentProvider; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.MultiPartContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; + +import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IModificationDateHolder; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.fetchoptions.MaterialFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.IMaterialId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.CustomASServiceExecutionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id.CustomASServiceCode; +import ch.ethz.sis.openbis.systemtest.asapi.v3.util.EmailUtil; +import ch.ethz.sis.openbis.systemtest.asapi.v3.util.EmailUtil.Email; +import ch.systemsx.cisd.common.http.JettyHttpClientFactory; +import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; +import ch.systemsx.cisd.openbis.generic.shared.util.TestInstanceHostUtils; + +/** + * @author pkupczyk + */ +public class ObjectsImportTest extends AbstractFileTest +{ + + protected static final String SERVICE_URL = TestInstanceHostUtils.getOpenBISUrl() + "/openbis/upload"; + + protected static final String TEST_UPLOAD_KEY = "test-import"; + + protected static final String TEST_EMAIL = "test@email.com"; + + protected static final long DEFAULT_TIMEOUT = 30000; + + protected static final String FALSE_TRUE_PROVIDER = "sync-async"; + + protected static final String PARAM_UPLOAD_KEY = "uploadKey"; + + protected static final String PARAM_TYPE_CODE = "typeCode"; + + protected static final String PARAM_ASYNC = "async"; + + protected static final String PARAM_USER_EMAIL = "userEmail"; + + protected static final String PARAM_DEFAULT_SPACE_IDENTIFIER = "defaultSpaceIdentifier"; + + protected static final String PARAM_SPACE_IDENTIFIER_OVERRIDE = "spaceIdentifierOverride"; + + protected static final String PARAM_EXPERIMENT_IDENTIFIER_OVERRIDE = "experimentIdentifierOverride"; + + protected static final String PARAM_UPDATE_EXISTING = "updateExisting"; + + protected static final String PARAM_IGNORE_UNREGISTERED = "ignoreUnregistered"; + + protected static final String PARAM_CUSTOM_IMPORT_CODE = "customImportCode"; + + protected IApplicationServerApi as; + + @BeforeClass + protected void beforeClass() throws Exception + { + super.beforeClass(); + as = ServiceProvider.getV3ApplicationService(); + } + + protected ContentResponse uploadFiles(String sessionToken, String uploadSessionKey, MultiPartContentProvider multiPart) + throws InterruptedException, TimeoutException, ExecutionException + { + HttpClient client = JettyHttpClientFactory.getHttpClient(); + Request request = client.newRequest(SERVICE_URL).method(HttpMethod.POST); + request.param("sessionID", sessionToken); + request.param("sessionKeysNumber", "1"); + request.param("sessionKey_0", uploadSessionKey); + request.content(multiPart); + + return request.send(); + } + + protected ContentResponse uploadFiles(String sessionToken, String uploadSessionKey, String... filesContent) + throws InterruptedException, TimeoutException, ExecutionException + { + MultiPartContentProvider multiPart = new MultiPartContentProvider(); + + for (int i = 0; i < filesContent.length; i++) + { + ContentProvider contentProvider = new StringContentProvider(filesContent[i]); + + String fieldName = uploadSessionKey + "_" + i; + String fileName = "fileName_" + i; + multiPart.addFilePart(fieldName, fileName, contentProvider, null); + } + + multiPart.close(); + + return uploadFiles(sessionToken, uploadSessionKey, multiPart); + } + + protected String executeImport(String sessionToken, String operation, Map<String, Object> parameters) + { + CustomASServiceCode serviceId = new CustomASServiceCode("import-test"); + CustomASServiceExecutionOptions options = new CustomASServiceExecutionOptions(); + options.withParameter("operation", operation); + for (String name : parameters.keySet()) + { + options.withParameter(name, parameters.get(name)); + } + return (String) as.executeCustomASService(sessionToken, serviceId, options); + } + + protected <T extends IModificationDateHolder> T getObject(String sessionToken, IObjectId objectId) + { + return getObject(sessionToken, objectId, 0, 0); + } + + protected <T extends IModificationDateHolder> T getObject(String sessionToken, IObjectId objectId, long modifiedAfterTimestamp, + long timeoutAfterMillis) + { + long startMillis = System.currentTimeMillis(); + + while (true) + { + Map<IObjectId, T> objects = getObjects(sessionToken, objectId); + T object = objects.get(objectId); + + if (object != null && object.getModificationDate() != null && object.getModificationDate().getTime() >= modifiedAfterTimestamp) + { + return object; + } + + if (timeoutAfterMillis > 0 && System.currentTimeMillis() < startMillis + timeoutAfterMillis) + { + try + { + Thread.sleep(100); + } catch (InterruptedException e) + { + throw new RuntimeException(e); + } + } else + { + return null; + } + } + } + + @SuppressWarnings("unchecked") + private <K, V> Map<K, V> getObjects(String sessionToken, IObjectId objectId) + { + if (objectId instanceof IExperimentId) + { + ExperimentFetchOptions fo = new ExperimentFetchOptions(); + fo.withProperties(); + return (Map<K, V>) as.getExperiments(sessionToken, Arrays.asList((IExperimentId) objectId), (ExperimentFetchOptions) fo); + } else if (objectId instanceof ISampleId) + { + SampleFetchOptions fo = new SampleFetchOptions(); + fo.withProperties(); + return (Map<K, V>) as.getSamples(sessionToken, Arrays.asList((ISampleId) objectId), (SampleFetchOptions) fo); + } else if (objectId instanceof IDataSetId) + { + DataSetFetchOptions fo = new DataSetFetchOptions(); + fo.withProperties(); + return (Map<K, V>) as.getDataSets(sessionToken, Arrays.asList((IDataSetId) objectId), (DataSetFetchOptions) fo); + } else if (objectId instanceof IMaterialId) + { + MaterialFetchOptions fo = new MaterialFetchOptions(); + fo.withProperties(); + return (Map<K, V>) as.getMaterials(sessionToken, Arrays.asList((IMaterialId) objectId), (MaterialFetchOptions) fo); + } else + { + throw new IllegalArgumentException("Unsupported object id " + objectId); + } + } + + protected void assertNoEmails(long timestamp) + { + Email latestEmail = EmailUtil.findLatestEmail(); + assertTrue("Timestamp: " + timestamp + ", Latest email: " + latestEmail, latestEmail == null || latestEmail.timestamp < timestamp); + } + + protected void assertEmail(long timestamp, String expectedEmail, String expectedSubject) + { + Email latestEmail = EmailUtil.findLatestEmail(); + assertTrue("Timestamp: " + timestamp + ", Latest email: " + latestEmail, latestEmail != null && latestEmail.timestamp >= timestamp); + assertEquals(expectedEmail, latestEmail.to); + assertTrue(latestEmail.subject, latestEmail.subject.contains(expectedSubject)); + } + + public static class ImportFile + { + + private List<String> columns; + + private List<List<String>> lines = new ArrayList<List<String>>(); + + public ImportFile(String... columns) + { + this.columns = Arrays.asList(columns); + } + + public void addLine(String... values) + { + lines.add(Arrays.asList(values)); + } + + @Override + public String toString() + { + StringBuilder content = new StringBuilder(); + content.append(String.join("\t", columns) + "\n"); + + for (List<String> line : lines) + { + content.append(String.join("\t", line) + "\n"); + } + + return content.toString(); + } + } + + @DataProvider(name = FALSE_TRUE_PROVIDER) + public static Object[][] provideFalseTrue() + { + return new Object[][] { { false }, { true } }; + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateDataSetsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateDataSetsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a18bb9e0d9a33481bfe57cdab1ec9b3b05c2f3e2 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateDataSetsImportTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.PhysicalDataCreation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.delete.DataSetDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.FileFormatTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.ProprietaryStorageFormatPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.RelativeLocationLocatorTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.datastore.id.DataStorePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; + +/** + * @author pkupczyk + */ +public class UpdateDataSetsImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testUpdate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + String etlServerSessionToken = as.login(ETL_SERVER_USER, PASSWORD); + + DataSetPermId dataSetPermId = new DataSetPermId("TEST-IMPORT-" + UUID.randomUUID().toString()); + + try + { + PhysicalDataCreation physicalCreation = new PhysicalDataCreation(); + physicalCreation.setLocation("test/location/" + dataSetPermId.getPermId()); + physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF")); + physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId()); + physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId()); + + DataSetCreation creation = new DataSetCreation(); + creation.setCode(dataSetPermId.getPermId()); + creation.setDataSetKind(DataSetKind.PHYSICAL); + creation.setTypeId(new EntityTypePermId("HCS_IMAGE")); + creation.setExperimentId(new ExperimentIdentifier("/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST")); + creation.setDataStoreId(new DataStorePermId("STANDARD")); + creation.setPhysicalData(physicalCreation); + creation.setProperty("COMMENT", "initial comment"); + + DataSet dataSet = getObject(sessionToken, dataSetPermId); + assertNull(dataSet); + + as.createDataSets(etlServerSessionToken, Arrays.asList(creation)); + + dataSet = getObject(sessionToken, dataSetPermId); + assertEquals("initial comment", dataSet.getProperty("COMMENT")); + + ImportFile file = new ImportFile("code", "COMMENT"); + file.addLine(dataSetPermId.getPermId(), "imported comment"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, "HCS_IMAGE"); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "updateDataSets", parameters); + + dataSet = getObject(sessionToken, dataSetPermId, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported comment", dataSet.getProperty("COMMENT")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Data Set Batch Update successfully performed"); + } else + { + assertEquals("1 data set(s) found and registered.", message); + assertNoEmails(timestamp); + } + } finally + { + DataSetDeletionOptions options = new DataSetDeletionOptions(); + options.setReason("cleanup"); + as.deleteDataSets(sessionToken, Arrays.asList(dataSetPermId), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateExperimentsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateExperimentsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..094fb142295cb166a518c6c46e84675cc41e9b2f --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateExperimentsImportTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +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.delete.ExperimentDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier; + +/** + * @author pkupczyk + */ +public class UpdateExperimentsImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testUpdate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String experimentCode = "TEST-IMPORT-" + UUID.randomUUID().toString(); + ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("/TEST-SPACE/TEST-PROJECT/" + experimentCode); + + try + { + ExperimentCreation creation = new ExperimentCreation(); + creation.setCode(experimentCode); + creation.setTypeId(new EntityTypePermId("SIRNA_HCS")); + creation.setProjectId(new ProjectIdentifier("/TEST-SPACE/TEST-PROJECT")); + creation.setProperty("DESCRIPTION", "initial value"); + + Experiment experiment = getObject(sessionToken, experimentIdentifier); + assertNull(experiment); + + as.createExperiments(sessionToken, Arrays.asList(creation)); + + experiment = getObject(sessionToken, experimentIdentifier); + assertEquals("initial value", experiment.getProperty("DESCRIPTION")); + + ImportFile file = new ImportFile("identifier", "DESCRIPTION"); + file.addLine(experimentIdentifier.getIdentifier(), "imported description"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, "SIRNA_HCS"); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "updateExperiments", parameters); + + experiment = getObject(sessionToken, experimentIdentifier, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description", experiment.getProperty("DESCRIPTION")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Experiment Batch Update successfully performed"); + } else + { + assertEquals("Update of 1 experiment(s) is complete.", message); + assertNoEmails(timestamp); + } + } finally + { + ExperimentDeletionOptions options = new ExperimentDeletionOptions(); + options.setReason("cleanup"); + as.deleteExperiments(sessionToken, Arrays.asList(experimentIdentifier), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateMaterialsImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateMaterialsImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d3a8e817b86e00a179ef5b34b786fd0f4906ae87 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateMaterialsImportTest.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.create.MaterialCreation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.delete.MaterialDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.MaterialPermId; + +/** + * @author pkupczyk + */ +public class UpdateMaterialsImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testUpdate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + MaterialPermId materialPermId = new MaterialPermId("TEST-IMPORT-" + UUID.randomUUID().toString(), "VIRUS"); + + try + { + MaterialCreation creation = new MaterialCreation(); + creation.setCode(materialPermId.getCode()); + creation.setTypeId(new EntityTypePermId(materialPermId.getTypeCode())); + creation.setProperty("DESCRIPTION", "initial description"); + + Material material = getObject(sessionToken, materialPermId); + assertNull(material); + + as.createMaterials(sessionToken, Arrays.asList(creation)); + + material = getObject(sessionToken, materialPermId); + assertEquals("initial description", material.getProperty("DESCRIPTION")); + + ImportFile file = new ImportFile("code", "DESCRIPTION"); + file.addLine(materialPermId.getCode(), "imported description"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, materialPermId.getTypeCode()); + parameters.put(PARAM_IGNORE_UNREGISTERED, false); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "updateMaterials", parameters); + + material = getObject(sessionToken, materialPermId, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported description", material.getProperty("DESCRIPTION")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Material Batch Update successfully performed"); + } else + { + assertEquals("1 material(s) updated.", message); + assertNoEmails(timestamp); + } + } finally + { + MaterialDeletionOptions options = new MaterialDeletionOptions(); + options.setReason("cleanup"); + as.deleteMaterials(sessionToken, Arrays.asList(materialPermId), options); + } + } + +} diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateSamplesImportTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateSamplesImportTest.java new file mode 100644 index 0000000000000000000000000000000000000000..01effa654c52b8463219e950b899f07bffea1540 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UpdateSamplesImportTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.dss.systemtest.api.v3; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleCreation; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.delete.SampleDeletionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId; + +/** + * @author pkupczyk + */ +public class UpdateSamplesImportTest extends ObjectsImportTest +{ + + @Test(dataProvider = FALSE_TRUE_PROVIDER) + public void testUpdate(boolean async) throws Exception + { + String sessionToken = as.login(TEST_USER, PASSWORD); + + String sampleCode = "TEST-IMPORT-" + UUID.randomUUID().toString(); + SampleIdentifier sampleIdentifier = new SampleIdentifier("/TEST-SPACE/" + sampleCode); + + try + { + SampleCreation creation = new SampleCreation(); + creation.setCode(sampleCode); + creation.setSpaceId(new SpacePermId("TEST-SPACE")); + creation.setTypeId(new EntityTypePermId("CELL_PLATE")); + creation.setProperty("COMMENT", "initial comment"); + + Sample sample = getObject(sessionToken, sampleIdentifier); + assertNull(sample); + + as.createSamples(sessionToken, Arrays.asList(creation)); + + sample = getObject(sessionToken, sampleIdentifier); + assertEquals("initial comment", sample.getProperty("COMMENT")); + + ImportFile file = new ImportFile("identifier", "COMMENT"); + file.addLine(sampleIdentifier.getIdentifier(), "imported comment"); + uploadFiles(sessionToken, TEST_UPLOAD_KEY, file.toString()); + + Map<String, Object> parameters = new HashMap<String, Object>(); + parameters.put(PARAM_UPLOAD_KEY, TEST_UPLOAD_KEY); + parameters.put(PARAM_TYPE_CODE, "CELL_PLATE"); + parameters.put(PARAM_UPDATE_EXISTING, false); + parameters.put(PARAM_ASYNC, async); + + if (async) + { + parameters.put(PARAM_USER_EMAIL, TEST_EMAIL); + } + + long timestamp = System.currentTimeMillis(); + String message = executeImport(sessionToken, "updateSamples", parameters); + + sample = getObject(sessionToken, sampleIdentifier, timestamp, DEFAULT_TIMEOUT); + assertEquals("imported comment", sample.getProperty("COMMENT")); + + if (async) + { + assertEquals("When the import is complete the confirmation or failure report will be sent by email.", message); + assertEmail(timestamp, TEST_EMAIL, "Sample Batch Update successfully performed"); + } else + { + assertEquals("Update of 1 sample(s) is complete.", message); + assertNoEmails(timestamp); + } + } finally + { + SampleDeletionOptions options = new SampleDeletionOptions(); + options.setReason("cleanup"); + as.deleteSamples(sessionToken, Arrays.asList(sampleIdentifier), options); + } + } + +} diff --git a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js index 468337974d49bee608a4cde96ae611340e84bea1..568fa4d5fc6ed3047e8ba81a4241e8dd6923ac4c 100644 --- a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js +++ b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/dtos.js @@ -349,6 +349,7 @@ var sources = [ 'as/dto/history/HistoryEntry', 'as/dto/history/PropertyHistoryEntry', 'as/dto/history/RelationHistoryEntry', + 'as/dto/history/ContentCopyHistoryEntry', 'as/dto/material/create/MaterialCreation', 'as/dto/material/create/CreateMaterialsOperation', diff --git a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-jsVSjava.js b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-jsVSjava.js index a5105c839c8b2c5c5491db15e98e4de7ebda270b..97a41b586970fce665d87ba54f786d11024124b2 100644 --- a/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-jsVSjava.js +++ b/js-test/servers/common/core-plugins/tests/1/as/webapps/openbis-v3-api-test/html/test/test-jsVSjava.js @@ -14,7 +14,6 @@ define([ 'jquery', 'underscore', 'openbis', 'test/common' ], function($, _, open }; var ignoreMessages = { - "ICustomASServiceExecutor" : "Java class ignored: ", "ServiceContext" : "Java class ignored: ", "CustomASServiceContext" : "Java class ignored: ", "AbstractCollectionView" : "Java class ignored: ", diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/ApplicationServerApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/ApplicationServerApi.java index 6065148dce5d454bbf4d69b34f294bb95830b09e..0c06dc4de6ca79de8788d1f9da0941bda6368ac6 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/ApplicationServerApi.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/ApplicationServerApi.java @@ -453,7 +453,7 @@ import ch.systemsx.cisd.openbis.generic.shared.managed_property.IManagedProperty */ @Component(ApplicationServerApi.INTERNAL_SERVICE_NAME) public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> implements - IApplicationServerApi + IApplicationServerInternalApi { /** * Name of this service for which it is registered as Spring bean @@ -486,6 +486,12 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> return session == null ? null : session.getSessionToken(); } + @Override + public String loginAsSystem() + { + return tryToAuthenticateAsSystem().getSessionToken(); + } + @Override @Transactional public String loginAsAnonymousUser() @@ -1525,7 +1531,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi> @Override public int getMinorVersion() { - return 3; + return 4; } @Override diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/IApplicationServerInternalApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/IApplicationServerInternalApi.java new file mode 100644 index 0000000000000000000000000000000000000000..6e623105fb4aad9348231d0af71b37e2bcb57004 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/IApplicationServerInternalApi.java @@ -0,0 +1,33 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.server.asapi.v3; + +import org.springframework.transaction.annotation.Transactional; + +import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; + +/** + * Extension of {@link IApplicationServerApi} which are only for internal use. These methods are not accessible remotely. + * + * @author Franz-Josef Elmer + */ +public interface IApplicationServerInternalApi extends IApplicationServerApi +{ + @Transactional + public String loginAsSystem(); + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/CustomASServiceScriptRunnerFactory.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/CustomASServiceScriptRunnerFactory.java index 7837c8e87a79da7faa2a7028d3326d21e73df1f8..0954144dde8b831564941cfc1cfb904b9238fcc0 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/CustomASServiceScriptRunnerFactory.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/CustomASServiceScriptRunnerFactory.java @@ -20,6 +20,7 @@ import java.io.Serializable; import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.CustomASServiceExecutionOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.IImportService; import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.context.ServiceContext; import ch.systemsx.cisd.common.jython.JythonUtils; import ch.systemsx.cisd.common.jython.evaluator.Evaluator; @@ -35,10 +36,14 @@ class CustomASServiceScriptRunnerFactory implements IScriptRunnerFactory private final IApplicationServerApi applicationService; - public CustomASServiceScriptRunnerFactory(String scriptPath, IApplicationServerApi applicationService) + private final IImportService importService; + + public CustomASServiceScriptRunnerFactory(String scriptPath, IApplicationServerApi applicationService, + IImportService importService) { this.scriptPath = scriptPath; this.applicationService = applicationService; + this.importService = importService; Evaluator.getFactory().initialize(); } @@ -58,7 +63,7 @@ class CustomASServiceScriptRunnerFactory implements IScriptRunnerFactory { IJythonEvaluator evaluator = Evaluator.getFactory().create("", pythonPath, scriptPath, null, scriptString, false); String sessionToken = context.getSessionToken(); - ExecutionContext executionContext = new ExecutionContext(sessionToken, applicationService); + ExecutionContext executionContext = new ExecutionContext(sessionToken, applicationService, importService); return new ServiceScriptRunner(evaluator, executionContext); } catch (EvaluatorException ex) { @@ -105,10 +110,13 @@ class CustomASServiceScriptRunnerFactory implements IScriptRunnerFactory private final IApplicationServerApi applicationService; - ExecutionContext(String sessionToken, IApplicationServerApi applicationService) + private final IImportService importService; + + ExecutionContext(String sessionToken, IApplicationServerApi applicationService, IImportService importService) { this.sessionToken = sessionToken; this.applicationService = applicationService; + this.importService = importService; } public String getSessionToken() @@ -120,5 +128,10 @@ class CustomASServiceScriptRunnerFactory implements IScriptRunnerFactory { return applicationService; } + + public IImportService getImportService() + { + return importService; + } } } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/ImportService.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/ImportService.java new file mode 100644 index 0000000000000000000000000000000000000000..1371cd7537fb9de1f72a806340fe76c2b907492c --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/ImportService.java @@ -0,0 +1,212 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.server.asapi.v3.helper.service; + +import java.util.Iterator; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.IImportService; +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.generic.shared.ICustomImportService; +import ch.systemsx.cisd.openbis.generic.shared.IEntityImportService; +import ch.systemsx.cisd.openbis.generic.shared.ResourceNames; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchRegistrationResult; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType; + +/** + * @author pkupczyk + */ +@Component(value = ResourceNames.IMPORT_SERVICE) +public class ImportService implements IImportService +{ + + @Autowired + private IEntityImportService entityImportService; + + @Autowired + private ICustomImportService customImportService; + + @Override + public String createExperiments(String sessionToken, String uploadKey, String experimentTypeCode, boolean async, String userEmail) + { + check(sessionToken, uploadKey, experimentTypeCode, async, userEmail); + + ExperimentType experimentType = new ExperimentType(); + experimentType.setCode(experimentTypeCode); + + List<BatchRegistrationResult> results = entityImportService.registerExperiments(experimentType, uploadKey, async, userEmail); + return translateResults(results); + } + + @Override + public String updateExperiments(String sessionToken, String uploadKey, String experimentTypeCode, boolean async, String userEmail) + { + check(sessionToken, uploadKey, experimentTypeCode, async, userEmail); + + ExperimentType experimentType = new ExperimentType(); + experimentType.setCode(experimentTypeCode); + + List<BatchRegistrationResult> results = entityImportService.updateExperiments(experimentType, uploadKey, async, userEmail); + return translateResults(results); + } + + @Override + public String createSamples(String sessionToken, String uploadKey, String sampleTypeCode, String defaultSpaceIdentifier, + String spaceIdentifierOverride, String experimentIdentifierOverride, boolean updateExisting, boolean async, String userEmail) + { + check(sessionToken, uploadKey, sampleTypeCode, async, userEmail); + + SampleType sampleType = new SampleType(); + sampleType.setCode(sampleTypeCode); + + List<BatchRegistrationResult> results = entityImportService.registerSamplesWithSilentOverrides(sampleType, spaceIdentifierOverride, + experimentIdentifierOverride, uploadKey, async, userEmail, defaultSpaceIdentifier, updateExisting); + return translateResults(results); + } + + @Override + public String updateSamples(String sessionToken, String uploadKey, String sampleTypeCode, String defaultSpaceIdentifier, + String spaceIdentifierOverride, String experimentIdentifierOverride, boolean async, String userEmail) + { + check(sessionToken, uploadKey, sampleTypeCode, async, userEmail); + + SampleType sampleType = new SampleType(); + sampleType.setCode(sampleTypeCode); + + List<BatchRegistrationResult> results = entityImportService.updateSamplesWithSilentOverrides(sampleType, spaceIdentifierOverride, + experimentIdentifierOverride, uploadKey, async, userEmail, defaultSpaceIdentifier); + return translateResults(results); + } + + @Override + public String updateDataSets(String sessionToken, String uploadKey, String dataSetTypeCode, boolean async, String userEmail) + { + check(sessionToken, uploadKey, dataSetTypeCode, async, userEmail); + + DataSetType dataSetType = new DataSetType(); + dataSetType.setCode(dataSetTypeCode); + + List<BatchRegistrationResult> results = entityImportService.updateDataSets(dataSetType, uploadKey, async, userEmail); + return translateResults(results); + } + + @Override + public String createMaterials(String sessionToken, String uploadKey, String materialTypeCode, boolean updateExisting, boolean async, + String userEmail) + { + check(sessionToken, uploadKey, materialTypeCode, async, userEmail); + + MaterialType materialType = new MaterialType(); + materialType.setCode(materialTypeCode); + + List<BatchRegistrationResult> results = entityImportService.registerMaterials(materialType, updateExisting, uploadKey, async, userEmail); + return translateResults(results); + } + + @Override + public String updateMaterials(String sessionToken, String uploadKey, String materialTypeCode, boolean ignoreUnregistered, boolean async, + String userEmail) + { + check(sessionToken, uploadKey, materialTypeCode, async, userEmail); + + MaterialType materialType = new MaterialType(); + materialType.setCode(materialTypeCode); + + List<BatchRegistrationResult> results = entityImportService.updateMaterials(materialType, uploadKey, ignoreUnregistered, async, userEmail); + return translateResults(results); + } + + @Override + public String generalImport(String sessionToken, String uploadKey, String defaultSpaceIdentifier, boolean updateExisting, boolean async, + String userEmail) + { + check(sessionToken, uploadKey, async, userEmail); + + List<BatchRegistrationResult> results = + entityImportService.registerOrUpdateSamplesAndMaterials(uploadKey, defaultSpaceIdentifier, updateExisting, async, userEmail); + return translateResults(results); + } + + @Override + public String customImport(String sessionToken, String uploadKey, String customImportCode, boolean async, String userEmail) + { + check(sessionToken, uploadKey, async, userEmail); + + if (customImportCode == null) + { + throw new UserFailureException("Custom import code cannot be null"); + } + + List<BatchRegistrationResult> results = + customImportService.performCustomImport(uploadKey, customImportCode, async, userEmail); + return translateResults(results); + } + + protected void check(String sessionToken, String uploadKey, String typeCode, boolean async, String userEmail) + { + check(sessionToken, uploadKey, async, userEmail); + + if (typeCode == null) + { + throw new UserFailureException("Type code cannot be null"); + } + } + + protected void check(String sessionToken, String uploadKey, boolean async, String userEmail) + { + if (sessionToken == null) + { + throw new UserFailureException("Session token cannot be null"); + } + if (uploadKey == null) + { + throw new UserFailureException("Upload key cannot be null"); + } + if (async && userEmail == null) + { + throw new UserFailureException("User email cannot be null for an asynchronous import"); + } + } + + protected String translateResults(List<BatchRegistrationResult> results) + { + StringBuilder message = new StringBuilder(); + Iterator<BatchRegistrationResult> iter = results.iterator(); + + while (iter.hasNext()) + { + BatchRegistrationResult result = iter.next(); + if (result != null) + { + message.append(result.getMessage()); + if (iter.hasNext()) + { + message.append("\n"); + } + } + } + + return message.toString(); + } + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/JythonBasedCustomASServiceExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/JythonBasedCustomASServiceExecutor.java index 08cbd921a0568ed1eb12b28883650f8d90e1b91d..3c56376af5a853328785a2115bd823b005d20b14 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/JythonBasedCustomASServiceExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/helper/service/JythonBasedCustomASServiceExecutor.java @@ -51,7 +51,8 @@ public class JythonBasedCustomASServiceExecutor implements ICustomASServiceExecu { if (factory == null) { - factory = new CustomASServiceScriptRunnerFactory(scriptPath, CommonServiceProvider.getApplicationServerApi()); + factory = new CustomASServiceScriptRunnerFactory(scriptPath, CommonServiceProvider.getApplicationServerApi(), + CommonServiceProvider.getImportService()); } return factory; } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetHistoryTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetHistoryTranslator.java index 53992330fa3424e89ac521dfd4c3da47288ac56c..e4e78d4c8c5cb6e657d15bdaa6d1735e43a23fd0 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetHistoryTranslator.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetHistoryTranslator.java @@ -19,6 +19,7 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.dataset; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -29,13 +30,17 @@ import org.springframework.stereotype.Component; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.history.DataSetRelationType; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.history.ContentCopyHistoryEntry; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.history.HistoryEntry; import ch.ethz.sis.openbis.generic.asapi.v3.dto.history.RelationHistoryEntry; import ch.ethz.sis.openbis.generic.asapi.v3.dto.history.fetchoptions.HistoryEntryFetchOptions; import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.TranslationContext; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.experiment.IExperimentAuthorizationValidator; +import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryContentCopyRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryPropertyRecord; +import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryRelationshipRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryTranslator; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.sample.ISampleAuthorizationValidator; @@ -44,6 +49,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.RelationType; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.lemnik.eodsql.QueryTool; + /** * @author pkupczyk */ @@ -174,4 +180,49 @@ public class DataSetHistoryTranslator extends HistoryTranslator implements IData return entry; } + @Override + protected List<? extends HistoryRecord> loadAbritraryHistory(TranslationContext context, Collection<Long> entityIds) + { + DataSetQuery query = QueryTool.getManagedQuery(DataSetQuery.class); + return query.getContentCopyHistory(new LongOpenHashSet(entityIds)); + } + + @Override + protected void createArbitraryEntries(Map<Long, List<HistoryEntry>> entriesMap, List<? extends HistoryRecord> records, + Map<Long, Person> authorMap, HistoryEntryFetchOptions fetchOptions) + { + for (HistoryRecord record : records) + { + HistoryContentCopyRecord contentCopyRecord = (HistoryContentCopyRecord) record; + List<HistoryEntry> entries = entriesMap.get(contentCopyRecord.dataSetId); + + if (entries == null) + { + entries = new LinkedList<HistoryEntry>(); + entriesMap.put(contentCopyRecord.dataSetId, entries); + } + + entries.add(createContentCopyEntry(record, authorMap, fetchOptions)); + } + } + + private HistoryEntry createContentCopyEntry(HistoryRecord record, Map<Long, Person> authorMap, HistoryEntryFetchOptions fetchOptions) + { + HistoryContentCopyRecord contentCopyRecord = (HistoryContentCopyRecord) record; + ContentCopyHistoryEntry entry = new ContentCopyHistoryEntry(); + entry.setExternalCode(contentCopyRecord.externalCode); + entry.setPath(contentCopyRecord.path); + entry.setGitCommitHash(contentCopyRecord.gitCommitHash); + entry.setGitRepositoryId(contentCopyRecord.gitRepositoryId); + entry.setExternalDmsId(contentCopyRecord.externalDmsId); + entry.setValidFrom(contentCopyRecord.validFrom); + entry.setValidTo(contentCopyRecord.validTo); + if (fetchOptions.hasAuthor()) + { + entry.setAuthor(authorMap.get(record.authorId)); + entry.getFetchOptions().withAuthorUsing(fetchOptions.withAuthor()); + } + return entry; + } + } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java index 0d4cbfe3e58293903618e1cc160356b5882b7d63..958e8f222170f0384dc5d0a28dc1abf2b12b90b5 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/dataset/DataSetQuery.java @@ -20,6 +20,7 @@ import java.util.List; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.common.ObjectQuery; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.common.ObjectRelationRecord; +import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryContentCopyRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history.HistoryPropertyRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.MaterialPropertyRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.property.PropertyAssignmentRecord; @@ -122,6 +123,16 @@ public interface DataSetQuery extends ObjectQuery LongSetMapper.class }, fetchSize = FETCH_SIZE) public List<DataSetRelationshipRecord> getRelationshipsHistory(LongSet dataSetIds); + @Select(sql = "select dsch.id as id, dsch.data_id as dataSetId, dsch.external_code as externalCode, dsch.path as path, dsch.git_commit_hash as gitCommitHash, dsch.git_repository_id as gitRepositoryId, " + + "dsch.edms_id as externalDmsId, dsch.pers_id_author as authorId, dsch.valid_from_timestamp as validFrom, dsch.valid_until_timestamp as validTo " + + "from data_set_copies_history dsch " + + "where dsch.valid_until_timestamp is not null and dsch.data_id = any(?{1})", + parameterBindings = { + LongSetMapper.class + }, + fetchSize = FETCH_SIZE) + public List<HistoryContentCopyRecord> getContentCopyHistory(LongSet dataSetIds); + @Select(sql = "select ds_id from post_registration_dataset_queue where ds_id = any(?{1})", parameterBindings = { LongSetMapper.class }, fetchSize = FETCH_SIZE) public List<Long> getNotPostRegisteredDataSets(LongSet dataSetIds); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryContentCopyRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryContentCopyRecord.java new file mode 100644 index 0000000000000000000000000000000000000000..e1f0a0380307c03afd1771bdb1e58da3d6df454d --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryContentCopyRecord.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history; + +public class HistoryContentCopyRecord extends HistoryRecord +{ + + public Long dataSetId; + + public String externalCode; + + public String path; + + public String gitCommitHash; + + public String gitRepositoryId; + + public Long externalDmsId; + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java index 81ff60e28ac5204810d4d0ba99df0c24ab50df79..2e487675c3565a603db89cfdb9c0a322a32a6bee 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryPropertyRecord.java @@ -16,20 +16,14 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history; -import java.util.Date; - -import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.common.ObjectBaseRecord; - /** * @author pkupczyk */ -public class HistoryPropertyRecord extends ObjectBaseRecord +public class HistoryPropertyRecord extends HistoryRecord { public Long objectId; - public Long authorId; - public String propertyCode; public String propertyValue; @@ -38,8 +32,4 @@ public class HistoryPropertyRecord extends ObjectBaseRecord public String vocabularyPropertyValue; - public Date validFrom; - - public Date validTo; - } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRecord.java new file mode 100644 index 0000000000000000000000000000000000000000..e41af4d08174f3feb4f456906268623a73adadd8 --- /dev/null +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRecord.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history; + +import java.util.Date; +import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.common.ObjectBaseRecord; + +public class HistoryRecord extends ObjectBaseRecord +{ + + public Date validFrom; + + public Date validTo; + + public Long authorId; + +} diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRelationshipRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRelationshipRecord.java index 77e5cd732a697a039ee3961fb319b87f0b31c15e..5935e436612bd0319c9f96ba61fc77dc200d762f 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRelationshipRecord.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryRelationshipRecord.java @@ -16,26 +16,16 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history; -import java.util.Date; - -import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.common.ObjectBaseRecord; - /** * @author pkupczyk */ -public class HistoryRelationshipRecord extends ObjectBaseRecord +public class HistoryRelationshipRecord extends HistoryRecord { public Long objectId; - public Long authorId; - public String relationType; public String relatedObjectId; - public Date validFrom; - - public Date validTo; - } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryTranslator.java index 65476e0c953b7a99b33de354f085314e16dc8b32..6769db7b11a59d650587d235431d1e2ae8ff7ff3 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryTranslator.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/history/HistoryTranslator.java @@ -16,6 +16,7 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.translator.history; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -51,6 +52,10 @@ public abstract class HistoryTranslator extends AbstractCachingTranslator<Long, protected abstract List<? extends HistoryRelationshipRecord> loadRelationshipHistory(TranslationContext context, Collection<Long> entityIds); + protected List<? extends HistoryRecord> loadAbritraryHistory(TranslationContext context, Collection<Long> entityIds) { + return null; + } + @Override protected ObjectHolder<List<HistoryEntry>> createObject(TranslationContext context, Long entityId, HistoryEntryFetchOptions fetchOptions) { @@ -62,30 +67,34 @@ public abstract class HistoryTranslator extends AbstractCachingTranslator<Long, { List<? extends HistoryPropertyRecord> properties = loadPropertyHistory(entityIds); List<? extends HistoryRelationshipRecord> relationships = loadRelationshipHistory(context, entityIds); + List<? extends HistoryRecord> arbitraryRecords = loadAbritraryHistory(context, entityIds); Map<Long, Person> authorMap = new HashMap<>(); if (fetchOptions.hasAuthor()) { + Set<Long> authorIds = new HashSet<Long>(); + + List<HistoryRecord> completeHistory = new ArrayList<>(); if (properties != null) { - for (HistoryPropertyRecord property : properties) - { - if (property.authorId != null) - { - authorIds.add(property.authorId); - } - } + completeHistory.addAll(properties); } if (relationships != null) { - for (HistoryRelationshipRecord relationship : relationships) + completeHistory.addAll(relationships); + } + if (arbitraryRecords != null) + { + completeHistory.addAll(arbitraryRecords); + } + + for (HistoryRecord record : completeHistory) + { + if (record.authorId != null) { - if (relationship.authorId != null) - { - authorIds.add(relationship.authorId); - } + authorIds.add(record.authorId); } } authorMap = personTranslator.translate(context, authorIds, fetchOptions.withAuthor()); @@ -101,6 +110,10 @@ public abstract class HistoryTranslator extends AbstractCachingTranslator<Long, { createRelationshipEntries(entriesMap, relationships, authorMap, fetchOptions); } + if (arbitraryRecords != null) + { + createArbitraryEntries(entriesMap, arbitraryRecords, authorMap, fetchOptions); + } for (Long entityId : entityIds) { @@ -171,6 +184,11 @@ public abstract class HistoryTranslator extends AbstractCachingTranslator<Long, return entry; } + protected void createArbitraryEntries(Map<Long, List<HistoryEntry>> entriesMap, List<? extends HistoryRecord> records, + Map<Long, Person> authorMap, HistoryEntryFetchOptions fetchOptions) + { + } + private void createRelationshipEntries(Map<Long, List<HistoryEntry>> entriesMap, List<? extends HistoryRelationshipRecord> records, Map<Long, Person> authorMap, HistoryEntryFetchOptions fetchOptions) { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java index 2616f00df8bfc246220b71e9081815eb76ed75ec..5e40a49e48f729c1639f27939625f2d6ecc7bf2a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java @@ -124,6 +124,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.server.translator.SearchableS import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailureExceptionTranslator; import ch.systemsx.cisd.openbis.generic.client.web.server.util.TSVRenderer; import ch.systemsx.cisd.openbis.generic.shared.ICommonServer; +import ch.systemsx.cisd.openbis.generic.shared.ICustomImportService; import ch.systemsx.cisd.openbis.generic.shared.IServer; import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchDomain; import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchDomainSearchOption; @@ -241,7 +242,7 @@ import ch.systemsx.cisd.openbis.generic.shared.util.WebClientConfigUtils; * @author Franz-Josef Elmer */ public final class CommonClientService extends AbstractClientService implements - ICommonClientService + ICommonClientService, ICustomImportService { @Resource(name = "registration-queue") private ConsumerQueue asyncRegistrationQueue; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java index d17c567bd75ed5b73d867adb9b616f1f5c367042..0c8be1bc0d4ff0ca450ad880f2a0e0454fa8c139 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java @@ -465,6 +465,22 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp return getDAOFactory().getPersonDAO().countActivePersons(); } + public SessionContextDTO tryToAuthenticateAsSystem() + { + final PersonPE systemUser = getSystemUser(); + HibernateUtils.initialize(systemUser.getAllPersonRoles()); + RoleAssignmentPE role = new RoleAssignmentPE(); + role.setRole(RoleCode.ADMIN); + systemUser.addRoleAssignment(role); + String sessionToken = + sessionManager.tryToOpenSession(systemUser.getUserId(), + new AuthenticatedPersonBasedPrincipalProvider(systemUser)); + Session session = sessionManager.getSession(sessionToken); + session.setPerson(systemUser); + session.setCreatorPerson(systemUser); + return tryGetSession(sessionToken); + } + @Override public SessionContextDTO tryAuthenticateAnonymously() { diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java index b3bbb5e222a37fc108d5ff524695a3425b167fcc..585e93d97d65573b195fb37c12ec1f4035bd242a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java @@ -211,7 +211,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO; import ch.systemsx.cisd.openbis.generic.shared.dto.ScriptPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SearchableEntity; import ch.systemsx.cisd.openbis.generic.shared.dto.Session; -import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO; import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE; import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE; import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermWithStats; @@ -323,27 +322,6 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt return new CommonServerLogger(getSessionManager(), context); } - // - // ISystemAuthenticator - // - - @Override - public SessionContextDTO tryToAuthenticateAsSystem() - { - final PersonPE systemUser = getSystemUser(); - HibernateUtils.initialize(systemUser.getAllPersonRoles()); - RoleAssignmentPE role = new RoleAssignmentPE(); - role.setRole(RoleCode.ADMIN); - systemUser.addRoleAssignment(role); - String sessionToken = - sessionManager.tryToOpenSession(systemUser.getUserId(), - new AuthenticatedPersonBasedPrincipalProvider(systemUser)); - Session session = sessionManager.getSession(sessionToken); - session.setPerson(systemUser); - session.setCreatorPerson(systemUser); - return tryGetSession(sessionToken); - } - // // IGenericServer // diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java index b311ae93581827d73962be8973c7ee904c168b4a..8f31613e613dfb92e2ed794b50a36c2db7e830be 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServiceProvider.java @@ -18,8 +18,9 @@ package ch.systemsx.cisd.openbis.generic.server; import org.springframework.context.ApplicationContext; -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; +import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.IImportService; import ch.ethz.sis.openbis.generic.server.asapi.v3.ApplicationServerApi; +import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi; import ch.systemsx.cisd.common.mail.IMailClient; import ch.systemsx.cisd.common.mail.MailClient; import ch.systemsx.cisd.common.mail.MailClientParameters; @@ -47,6 +48,11 @@ public class CommonServiceProvider .getBean(ResourceNames.COMMON_SERVER); } + public static IImportService getImportService() + { + return (IImportService) applicationContext.getBean(ResourceNames.IMPORT_SERVICE); + } + public static IDAOFactory getDAOFactory() { return (IDAOFactory) applicationContext.getBean("dao-factory"); @@ -66,9 +72,9 @@ public class CommonServiceProvider return new MailClient(mailClientParameters); } - public static IApplicationServerApi getApplicationServerApi() + public static IApplicationServerInternalApi getApplicationServerApi() { - return (IApplicationServerApi) applicationContext.getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME); + return (IApplicationServerInternalApi) applicationContext.getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME); } public static Object tryToGetBean(String beanName) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java index 2432d8f1e8f2d48d248e0c6d9131de54d8072f82..abb8ceb92a739faf722973bcd6621aaf609e19a6 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SampleTable.java @@ -316,6 +316,8 @@ public final class SampleTable extends AbstractSampleBusinessObject implements I { relationshipService.assignSampleToSpace(session, sample, sample.getSpace()); } + + RelationshipUtils.updateModificationDateAndModifier(sample, session, getTransactionTimeStamp()); } /** diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/Group.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/Group.java new file mode 100644 index 0000000000000000000000000000000000000000..db1fe91cf09dea6233ac680df34b6779da3e2bc1 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/Group.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.server.task; + +import java.util.List; + +class Group +{ + private String name; + + private List<String> ldapGroupKeys; + + private List<String> admins; + + private List<String> usersBlackList; + + public String getName() + { + return name; + } + + public List<String> getAdmins() + { + return admins; + } + + public List<String> getLdapGroupKeys() + { + return ldapGroupKeys; + } + + public List<String> getUsersBlackList() + { + return usersBlackList; + } + +} \ No newline at end of file diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagementMaintenanceTask.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagementMaintenanceTask.java new file mode 100644 index 0000000000000000000000000000000000000000..42b697b343c84f13e1d0604c754fcf19cd58c2c1 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagementMaintenanceTask.java @@ -0,0 +1,143 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.server.task; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.TreeMap; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import ch.systemsx.cisd.authentication.Principal; +import ch.systemsx.cisd.authentication.ldap.LDAPAuthenticationService; +import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.Log4jSimpleLogger; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.common.maintenance.IMaintenanceTask; +import ch.systemsx.cisd.openbis.generic.server.CommonServiceProvider; + +/** + * @author Franz-Josef Elmer + */ +public class UserManagementMaintenanceTask implements IMaintenanceTask +{ + private static final String CONFIGURATION_FILE_PATH_PROPERTY = "configuration-file-path"; + + private static final String DEFAULT_CONFIGURATION_FILE_PATH = "etc/user-management-maintenance-config.json"; + + private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + UserManagementMaintenanceTask.class); + + private File configurationFile; + + private LDAPAuthenticationService ldapService; + + @Override + public void setUp(String pluginName, Properties properties) + { + operationLog.info("Setup plugin " + pluginName); + configurationFile = new File(properties.getProperty(CONFIGURATION_FILE_PATH_PROPERTY, DEFAULT_CONFIGURATION_FILE_PATH)); + if (configurationFile.isFile() == false) + { + throw new ConfigurationFailureException("Configuration file '" + configurationFile.getAbsolutePath() + + "' doesn't exist or is a directory."); + } + ldapService = (LDAPAuthenticationService) CommonServiceProvider.getApplicationContext().getBean("ldap-authentication-service"); + operationLog.info("Plugin '" + pluginName + "' initialized. Configuration file: " + configurationFile.getAbsolutePath()); + + } + + @Override + public void execute() + { + Map<String, Group> groups = readGroupDefinitions(); + if (groups == null) + { + return; + } + Log4jSimpleLogger logger = new Log4jSimpleLogger(operationLog); + UserManager userManager = new UserManager(CommonServiceProvider.getApplicationServerApi(), logger); + for (Entry<String, Group> entry : groups.entrySet()) + { + String key = entry.getKey(); + Group group = entry.getValue(); + List<String> ldapGroupKeys = group.getLdapGroupKeys(); + if (ldapGroupKeys == null || ldapGroupKeys.isEmpty()) + { + operationLog.error("No ldapGroupKeys specified for group '" + key + "'. Task aborted."); + return; + } + Map<String, Principal> principalsByUserId = new TreeMap<>(); + for (String ldapGroupKey : ldapGroupKeys) + { + if (StringUtils.isBlank(ldapGroupKey)) + { + operationLog.error("Empty ldapGroupKey for group '" + key + "'. Task aborted."); + return; + + } + List<Principal> principals = ldapService.listPrincipalsByKeyValue("ou", ldapGroupKey); + if (principals.isEmpty()) + { + operationLog.error("No users found for ldapGroupKey '" + ldapGroupKey + "' for group '" + key + "'. Task aborted."); + return; + } + for (Principal principal : principals) + { + principalsByUserId.put(principal.getUserId(), principal); + } + } + userManager.addGroup(key, group, principalsByUserId); + } + userManager.manageUsers(); + operationLog.info("finished"); + } + + private Map<String, Group> readGroupDefinitions() + { + if (configurationFile.isFile() == false) + { + operationLog.error("Configuration file '" + configurationFile.getAbsolutePath() + "' doesn't exist or is a directory."); + return null; + } + String serializedConfig = FileUtilities.loadToString(configurationFile); + try + { + return deserialize(serializedConfig); + } catch (Exception e) + { + operationLog.error("Invalid content of configuration file '" + configurationFile.getAbsolutePath() + "': " + e, e); + return null; + } + } + + private Map<String, Group> deserialize(String serializedConfig) throws Exception + { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(serializedConfig, new TypeReference<Map<String, Group>>(){}); + } + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManager.java new file mode 100644 index 0000000000000000000000000000000000000000..12effa23e0a731ec0140264e0f36beb0c51fb1c0 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/task/UserManager.java @@ -0,0 +1,188 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.server.task; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.function.Function; +import java.util.stream.Collectors; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.AuthorizationGroup; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.fetchoptions.AuthorizationGroupFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.id.AuthorizationGroupPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.id.IAuthorizationGroupId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.fetchoptions.PersonFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.id.IPersonId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.id.PersonPermId; +import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi; +import ch.systemsx.cisd.authentication.Principal; +import ch.systemsx.cisd.common.logging.ISimpleLogger; +import ch.systemsx.cisd.common.logging.LogLevel; + +/** + * @author Franz-Josef Elmer + */ +class UserManager +{ + private final IApplicationServerInternalApi service; + + private final ISimpleLogger logger; + + private final Map<String, UserInfo> userInfosByUserId = new TreeMap<>(); + + private final List<String> groupCodes = new ArrayList<>(); + + UserManager(IApplicationServerInternalApi service, ISimpleLogger logger) + { + this.service = service; + this.logger = logger; + } + + public void addGroup(String key, Group group, Map<String, Principal> principalsByUserId) + { + groupCodes.add(key); + Set<String> admins = asSet(group.getAdmins()); + Set<String> blackListedUsers = asSet(group.getUsersBlackList()); + for (Principal principal : principalsByUserId.values()) + { + String userId = principal.getUserId(); + UserInfo userInfo = userInfosByUserId.get(userId); + if (userInfo == null) + { + userInfo = new UserInfo(principal); + userInfosByUserId.put(userId, userInfo); + } + userInfo.addGroupInfo(new GroupInfo(key, admins.contains(userId), blackListedUsers.contains(userId))); + } + logger.log(LogLevel.INFO, principalsByUserId.size() + " users for group " + key); + } + + public void manageUsers() + { + String sessionToken = service.loginAsSystem(); + Map<IPersonId, Person> users = getUsersWithRoleAssigments(sessionToken); + Map<IAuthorizationGroupId, AuthorizationGroup> authorizationGroups = getAuthorizationGroups(sessionToken); + for (UserInfo userInfo : userInfosByUserId.values()) + { + manageUser(userInfo, users, authorizationGroups); + } + service.logout(sessionToken); + } + + private void manageUser(UserInfo userInfo, Map<IPersonId, Person> knownUsers, + Map<IAuthorizationGroupId, AuthorizationGroup> knownAuthorizationGroups) + { + + } + + private Map<IPersonId, Person> getUsersWithRoleAssigments(String sessionToken) + { + Function<String, PersonPermId> mapper = userId -> new PersonPermId(userId); + List<PersonPermId> userIds = userInfosByUserId.keySet().stream().map(mapper).collect(Collectors.toList()); + PersonFetchOptions fetchOptions = new PersonFetchOptions(); + fetchOptions.withRoleAssignments().withSpace(); + Map<IPersonId, Person> users = service.getPersons(sessionToken, userIds, fetchOptions); + return users; + } + + private Map<IAuthorizationGroupId, AuthorizationGroup> getAuthorizationGroups(String sessionToken) + { + Function<String, AuthorizationGroupPermId> mapper = key -> new AuthorizationGroupPermId(key); + List<AuthorizationGroupPermId> groupPermIds = groupCodes.stream().map(mapper).collect(Collectors.toList()); + AuthorizationGroupFetchOptions fetchOptions = new AuthorizationGroupFetchOptions(); + fetchOptions.withUsers(); + return service.getAuthorizationGroups(sessionToken, groupPermIds, fetchOptions); + } + + private Set<String> asSet(List<String> users) + { + return users == null ? Collections.emptySet() : new TreeSet<>(users); + } + + private static class UserInfo + { + private Principal principal; + + private Map<String, GroupInfo> groupInfosByGroupKey = new TreeMap<>(); + + public UserInfo(Principal principal) + { + this.principal = principal; + } + + public Principal getPrincipal() + { + return principal; + } + + public void addGroupInfo(GroupInfo groupInfo) + { + groupInfosByGroupKey.put(groupInfo.getKey(), groupInfo); + } + + @Override + public String toString() + { + return principal.getUserId() + " " + groupInfosByGroupKey.values(); + } + } + + private static class GroupInfo + { + private String key; + + private boolean admin; + + private boolean onBlackList; + + GroupInfo(String key, boolean admin, boolean onBlackList) + { + this.key = key; + this.admin = admin; + this.onBlackList = onBlackList; + } + + public String getKey() + { + return key; + } + + public boolean isAdmin() + { + return admin; + } + + public boolean isOnBlackList() + { + return onBlackList; + } + + @Override + public String toString() + { + return (onBlackList ? "." : "") + key + (admin ? "*" : ""); + } + + } + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICustomImportService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICustomImportService.java new file mode 100644 index 0000000000000000000000000000000000000000..9a36b36f53a60fd32379bd3b9bdaef665ed32a45 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICustomImportService.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.shared; + +import java.util.List; + +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchRegistrationResult; + +/** + * @author pkupczyk + */ +public interface ICustomImportService +{ + + public List<BatchRegistrationResult> performCustomImport(String sessionKey, String customImportCode, boolean async, String userEmail); + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IEntityImportService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IEntityImportService.java new file mode 100644 index 0000000000000000000000000000000000000000..effab330fc838ad57e0c91e370c7b50b97dff566 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IEntityImportService.java @@ -0,0 +1,55 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.shared; + +import java.util.List; + +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BatchRegistrationResult; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType; + +/** + * @author pkupczyk + */ +public interface IEntityImportService +{ + + public List<BatchRegistrationResult> registerExperiments(ExperimentType experimentType, String sessionKey, boolean async, String userEmail); + + public List<BatchRegistrationResult> updateExperiments(ExperimentType experimentType, String sessionKey, boolean async, String userEmail); + + public List<BatchRegistrationResult> registerSamplesWithSilentOverrides(SampleType sampleType, String spaceIdentifierSilentOverrideOrNull, + String experimentIdentifierSilentOverrideOrNull, String sessionKey, boolean async, String userEmail, String defaultGroupIdentifier, + boolean updateExisting); + + public List<BatchRegistrationResult> updateSamplesWithSilentOverrides(SampleType sampleType, String spaceIdentifierSilentOverrideOrNull, + String experimentIdentifierSilentOverrideOrNull, String sessionKey, boolean async, String userEmail, String defaultGroupIdentifier); + + public List<BatchRegistrationResult> updateDataSets(DataSetType dataSetType, String sessionKey, boolean async, String userEmail); + + public List<BatchRegistrationResult> registerMaterials(MaterialType materialType, boolean updateExisting, final String sessionKey, boolean async, + String userEmail); + + public List<BatchRegistrationResult> updateMaterials(MaterialType materialType, String sessionKey, boolean ignoreUnregistered, + boolean async, String userEmail); + + public List<BatchRegistrationResult> registerOrUpdateSamplesAndMaterials(String sessionKey, String defaultGroupIdentifier, boolean updateExisting, + boolean async, String userEmail); + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ResourceNames.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ResourceNames.java index 03492b312079b84558098fe65c3523c72c1577a5..afb075c8cdeca7e570fc0280390f871633ec9530 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ResourceNames.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ResourceNames.java @@ -60,6 +60,8 @@ public final class ResourceNames public final static String COMMON_SERVICE = "common-service"; public final static String COMMON_SERVER = "common-server"; + + public final static String IMPORT_SERVICE = "import-service"; public final static String TRACKING_SERVER = "tracking-server"; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java index d04c1aa2a9abb73875dd14e4d0615d9c7775629b..2e25dc082109cf4207591bd308e4b9ef9527b6fe 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java @@ -52,6 +52,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.server.translator.UserFailure import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.exception.SampleUniqueCodeViolationException; import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.exception.SampleUniqueCodeViolationExceptionAbstract; import ch.systemsx.cisd.openbis.generic.shared.Constants; +import ch.systemsx.cisd.openbis.generic.shared.IEntityImportService; import ch.systemsx.cisd.openbis.generic.shared.IServer; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData; @@ -110,7 +111,7 @@ import ch.systemsx.cisd.openbis.plugin.generic.shared.ResourceNames; * @author Franz-Josef Elmer */ @Component(value = ResourceNames.GENERIC_PLUGIN_SERVICE) -public class GenericClientService extends AbstractClientService implements IGenericClientService +public class GenericClientService extends AbstractClientService implements IGenericClientService, IEntityImportService { @Resource(name = ResourceNames.GENERIC_PLUGIN_SERVER) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/history/ContentCopyHistoryEntry.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/history/ContentCopyHistoryEntry.js new file mode 100644 index 0000000000000000000000000000000000000000..62e47f831fca980b4aec1a6aec08968cb74dc7cf --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/history/ContentCopyHistoryEntry.js @@ -0,0 +1,46 @@ +define([ "stjs", "util/Exceptions", "as/dto/history/HistoryEntry" ], function(stjs, exceptions, HistoryEntry) { + var ContentCopyHistoryEntry = function() { + HistoryEntry.call(this); + }; + stjs.extend(ContentCopyHistoryEntry, HistoryEntry, [ HistoryEntry ], function(constructor, prototype) { + prototype['@type'] = 'as.dto.history.ContentCopyHistoryEntry'; + constructor.serialVersionUID = 1; + prototype.externalCode = null; + prototype.path = null; + prototype.gitCommitHash = null; + prototype.gitRepositoryId = null; + prototype.externalDmsId = null; + + prototype.getExternalCode = function() { + return this.externalCode; + }; + prototype.setExternalCode = function(externalCode) { + this.externalCode = externalCode; + }; + prototype.getPath = function() { + return this.path; + }; + prototype.setPath = function(path) { + this.path = path; + }; + prototype.getGitCommitHash = function() { + return this.gitCommitHash; + }; + prototype.setGitCommitHash = function(gitCommitHash) { + this.gitCommitHash = gitCommitHash; + }; + prototype.getGitRepositoryId = function() { + return this.gitRepositoryId; + }; + prototype.setGitRepositoryId = function(gitRepositoryId) { + this.gitRepositoryId = gitRepositoryId; + }; + prototype.getExternalDmsId = function() { + return this.externalDmsId; + }; + prototype.setExternalDmsId = function(externalDmsId) { + this.externalDmsId = externalDmsId; + }; +}, {}); + return ContentCopyHistoryEntry; +}) \ No newline at end of file diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteOperationsTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteOperationsTest.java index 73e604568179991bd24386f1b0de10c43fe504ba..034b5a18038fab6423f3da7256452c031893a5ad 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteOperationsTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteOperationsTest.java @@ -23,19 +23,13 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; -import java.io.File; -import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang.time.DateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; @@ -92,6 +86,8 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.update.SpaceUpdate; import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.update.UpdateSpacesOperation; import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.update.UpdateSpacesOperationResult; +import ch.ethz.sis.openbis.systemtest.asapi.v3.util.EmailUtil; +import ch.ethz.sis.openbis.systemtest.asapi.v3.util.EmailUtil.Email; import ch.systemsx.cisd.common.action.IDelegatedAction; import ch.systemsx.cisd.common.test.AssertionUtil; import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO; @@ -106,10 +102,6 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * 24; - private static final String EMAIL_DIR = "targets/email"; - - private static final String EMAIL_PATTERN = "Date: (.*)\nFrom: (.*)\nTo: (.*)\nSubject: (.*)\nContent:\n(.*)"; - private static final String EMAIL_FROM = "application_server@localhost"; private static final String EMAIL_TO_1 = "test1@email.com"; @@ -412,7 +404,7 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest assertEquals(historyEntry.getPropertyName(), "COMMENT"); assertEquals(historyEntry.getPropertyValue(), "created"); } - + @Test public void testUpdateDataSetAndRelatedSample() { @@ -842,7 +834,7 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest CreateSpacesOperationResult result = (CreateSpacesOperationResult) results.getResults().get(0); assertEquals(result.getObjectIds(), Arrays.asList(new SpacePermId(creation.getCode()))); - Email email = findLatestEmail(); + Email email = EmailUtil.findLatestEmail(); assertEquals(email.from, EMAIL_FROM); assertEquals(email.to, EMAIL_TO_1 + ", " + EMAIL_TO_2); assertEquals(email.subject, String.format("Operation execution %s finished", options.getExecutionId())); @@ -872,7 +864,7 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest } }, "Code cannot be empty"); - Email email = findLatestEmail(); + Email email = EmailUtil.findLatestEmail(); assertEquals(email.from, EMAIL_FROM); assertEquals(email.to, EMAIL_TO_1 + ", " + EMAIL_TO_2); assertEquals(email.subject, String.format("Operation execution %s failed", options.getExecutionId())); @@ -897,61 +889,6 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest return getExecution(sessionToken, options.getExecutionId(), fullOperationExecutionFetchOptions()); } - private Email findLatestEmail() - { - File emailDir = new File(EMAIL_DIR); - - if (emailDir.exists()) - { - File[] emails = emailDir.listFiles(); - - if (emails != null && emails.length > 0) - { - Arrays.sort(emails, new Comparator<File>() - { - @Override - public int compare(File f1, File f2) - { - return -f1.getName().compareTo(f2.getName()); - } - }); - - File latestEmail = emails[0]; - try - { - String latestEmailContent = FileUtils.readFileToString(latestEmail); - Pattern pattern = Pattern.compile(EMAIL_PATTERN, Pattern.DOTALL); - - Matcher m = pattern.matcher(latestEmailContent); - if (m.find()) - { - Email email = new Email(); - email.from = m.group(2); - email.to = m.group(3); - email.subject = m.group(4); - email.content = m.group(5); - return email; - } else - { - throw new RuntimeException("Latest email content does not match the expected email pattern. The latest email content was:\n" - + latestEmailContent + "\nThe expected email pattern was:\n" + EMAIL_PATTERN); - } - - } catch (IOException e) - { - throw new RuntimeException("Could not read the latest email " + latestEmail.getAbsolutePath(), e); - } - - } else - { - throw new RuntimeException("No emails found in " + emailDir.getAbsolutePath() + " directory"); - } - } else - { - throw new RuntimeException("Email directory " + emailDir.getAbsolutePath() + " does not exist"); - } - } - private Set<String> getAllSpaceCodes() { // do it in a separate transaction to get only spaces that won't be rolled back @@ -992,15 +929,4 @@ public class ExecuteOperationsTest extends AbstractOperationExecutionTest } } - private class Email - { - private String from; - - private String to; - - private String subject; - - private String content; - } - } \ No newline at end of file diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/util/EmailUtil.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/util/EmailUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..ccf9b78fbefe860c61a3fcbb19a3bbac84060dd1 --- /dev/null +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/util/EmailUtil.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.systemtest.asapi.v3.util; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.builder.ReflectionToStringBuilder; + +/** + * @author pkupczyk + */ +public class EmailUtil +{ + + private static final String EMAIL_DIR = "targets/email"; + + private static final String EMAIL_PATTERN = "Date: (.*)\nFrom: (.*)\nTo: (.*)\nSubject: (.*)\nContent:\n(.*)"; + + public static Email findLatestEmail() + { + File emailDir = new File(EMAIL_DIR); + + if (emailDir.exists()) + { + File[] emails = emailDir.listFiles(); + + if (emails != null && emails.length > 0) + { + Arrays.sort(emails, new Comparator<File>() + { + @Override + public int compare(File f1, File f2) + { + return -f1.getName().compareTo(f2.getName()); + } + }); + + File latestEmail = emails[0]; + try + { + String latestEmailContent = FileUtils.readFileToString(latestEmail); + Pattern pattern = Pattern.compile(EMAIL_PATTERN, Pattern.DOTALL); + + Matcher m = pattern.matcher(latestEmailContent); + if (m.find()) + { + Email email = new Email(); + email.timestamp = latestEmail.lastModified(); + email.from = m.group(2); + email.to = m.group(3); + email.subject = m.group(4); + email.content = m.group(5); + return email; + } else + { + throw new RuntimeException("Latest email content does not match the expected email pattern. The latest email content was:\n" + + latestEmailContent + "\nThe expected email pattern was:\n" + EMAIL_PATTERN); + } + + } catch (IOException e) + { + throw new RuntimeException("Could not read the latest email " + latestEmail.getAbsolutePath(), e); + } + + } else + { + return null; + } + } else + { + throw new RuntimeException("Email directory " + emailDir.getAbsolutePath() + " does not exist"); + } + } + + public static class Email + { + + public long timestamp; + + public String from; + + public String to; + + public String subject; + + public String content; + + @Override + public String toString() + { + return new ReflectionToStringBuilder(this).toString(); + } + } + +} diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e0fe3386b39b0cfb6e9051eacd946116f932c381 --- /dev/null +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/task/UserManagerTest.java @@ -0,0 +1,295 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.systemsx.cisd.openbis.generic.server.task; + +import static org.testng.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.AuthorizationGroup; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.fetchoptions.AuthorizationGroupFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.id.AuthorizationGroupPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.authorizationgroup.id.IAuthorizationGroupId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.fetchoptions.PersonFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.id.IPersonId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.id.PersonPermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.Role; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.RoleAssignment; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.RoleLevel; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.fetchoptions.RoleAssignmentFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.fetchoptions.SpaceFetchOptions; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId; +import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi; +import ch.systemsx.cisd.authentication.Principal; +import ch.systemsx.cisd.common.logging.MockLogger; +import ch.systemsx.cisd.common.test.RecordingMatcher; +import ch.systemsx.cisd.common.test.ToStringMatcher; + +/** + * @author Franz-Josef Elmer + */ +public class UserManagerTest +{ + private static final String SESSION_TOKEN = "session-123"; + + private static final Principal U1 = new Principal("u1", "Albert", "Einstein", "a.e@abc.de"); + + private static final Principal U2 = new Principal("u2", "Isaac", "Newton", "i.n@abc.de"); + + private static final Principal U3 = new Principal("u3", "Alan", "Turing", "a.t@abc.de"); + + private Mockery context; + + private IApplicationServerInternalApi service; + + private UserManager userManager; + + private MockLogger logger; + + @BeforeMethod + public void setUp() + { + context = new Mockery(); + service = context.mock(IApplicationServerInternalApi.class); + context.checking(new Expectations() + { + { + one(service).loginAsSystem(); + will(returnValue(SESSION_TOKEN)); + + one(service).logout(SESSION_TOKEN); + } + }); + logger = new MockLogger(); + userManager = new UserManager(service, logger); + } + + @AfterMethod + public void tearDown() + { + // To following line of code should also be called at the end of each test method. + // Otherwise one does not known which test failed. + context.assertIsSatisfied(); + } + + @Test + public void testAddNewNormalUser() + { + // Given + RecordingMatcher<List<IPersonId>> personsMatcher = prepareGetUsersWithRoleAssigments(new PersonBuilder(U1).get()); + RecordingMatcher<List<AuthorizationGroupPermId>> groupsMatcher = prepareGetAuthorizationGroups(); + + userManager.addGroup("G1", new Group(), principals(U2, U1)); + + // When + userManager.manageUsers(); + + // Then + assertEquals(personsMatcher.recordedObject().toString(), "[u1, u2]"); + assertEquals(groupsMatcher.recordedObject().toString(), "[G1]"); + context.assertIsSatisfied(); + } + + // @Test + public void test2() + { + // Given + + // When + userManager.manageUsers(); + + // Then + context.assertIsSatisfied(); + } + + // @Test + public void test3() + { + // Given + + // When + userManager.manageUsers(); + + // Then + context.assertIsSatisfied(); + } + + private RecordingMatcher<List<IPersonId>> prepareGetUsersWithRoleAssigments(Person... persons) + { + Map<IPersonId, Person> result = new LinkedHashMap<>(); + for (Person person : persons) + { + result.put(person.getPermId(), person); + } + RecordingMatcher<List<IPersonId>> matcher = new RecordingMatcher<>(); + context.checking(new Expectations() + { + { + PersonFetchOptions fetchOptions = new PersonFetchOptions(); + fetchOptions.withRoleAssignments().withSpace(); + one(service).getPersons(with(SESSION_TOKEN), with(matcher), with(new ToStringMatcher<>(fetchOptions))); + will(returnValue(result)); + } + }); + return matcher; + } + + private RecordingMatcher<List<AuthorizationGroupPermId>> prepareGetAuthorizationGroups(AuthorizationGroup... authorizationGroups) + { + Map<IAuthorizationGroupId, AuthorizationGroup> result = new LinkedHashMap<>(); + for (AuthorizationGroup authorizationGroup : authorizationGroups) + { + result.put(authorizationGroup.getPermId(), authorizationGroup); + } + RecordingMatcher<List<AuthorizationGroupPermId>> matcher = new RecordingMatcher<>(); + context.checking(new Expectations() + { + { + AuthorizationGroupFetchOptions fetchOptions = new AuthorizationGroupFetchOptions(); + fetchOptions.withUsers(); + one(service).getAuthorizationGroups(with(SESSION_TOKEN), with(matcher), with(new ToStringMatcher<>(fetchOptions))); + will(returnValue(result)); + } + }); + return matcher; + } + + private Map<String, Principal> principals(Principal... principals) + { + Map<String, Principal> map = new TreeMap<>(); + for (Principal principal : principals) + { + map.put(principal.getUserId(), principal); + } + return map; + } + + private RoleAssignment ra(Role role) + { + return ra(role, null); + } + + private RoleAssignment ra(Role role, String spaceCodeOrNull) + { + RoleAssignment roleAssignment = new RoleAssignment(); + RoleAssignmentFetchOptions fetchOptions = new RoleAssignmentFetchOptions(); + fetchOptions.withSpace(); + roleAssignment.setFetchOptions(fetchOptions); + roleAssignment.setRole(role); + roleAssignment.setRoleLevel(RoleLevel.INSTANCE); + if (spaceCodeOrNull != null) + { + Space space = new Space(); + space.setCode(spaceCodeOrNull); + space.setPermId(new SpacePermId(spaceCodeOrNull)); + space.setFetchOptions(new SpaceFetchOptions()); + roleAssignment.setSpace(space); + roleAssignment.setRoleLevel(RoleLevel.SPACE); + } + return roleAssignment; + } + + private static Person createPerson(Principal principal, PersonFetchOptions fetchOptions) + { + Person person = new Person(); + person.setFetchOptions(fetchOptions); + person.setUserId(principal.getUserId()); + person.setPermId(new PersonPermId(principal.getUserId())); + person.setEmail(principal.getEmail()); + person.setFirstName(principal.getFirstName()); + person.setLastName(principal.getLastName()); + person.setRoleAssignments(new ArrayList<RoleAssignment>()); + person.setActive(true); + return person; + } + + private static final class PersonBuilder + { + private Person person; + + PersonBuilder(Principal principal) + { + PersonFetchOptions fetchOptions = new PersonFetchOptions(); + fetchOptions.withRoleAssignments().withSpace(); + person = createPerson(principal, fetchOptions); + } + + Person get() + { + return person; + } + + PersonBuilder roleAssignments(RoleAssignment... roleAssignments) + { + for (RoleAssignment roleAssignment : roleAssignments) + { + person.getRoleAssignments().add(roleAssignment); + } + return this; + } + + PersonBuilder deactive() + { + person.setActive(false); + return this; + } + } + + private static final class AuthorizationGroupBuilder + { + private AuthorizationGroup authorizationGroup; + + AuthorizationGroupBuilder(String code) + { + authorizationGroup = new AuthorizationGroup(); + AuthorizationGroupFetchOptions fetchOptions = new AuthorizationGroupFetchOptions(); + fetchOptions.withUsers(); + authorizationGroup.setFetchOptions(fetchOptions); + authorizationGroup.setCode(code); + authorizationGroup.setPermId(new AuthorizationGroupPermId(code)); + authorizationGroup.setUsers(new ArrayList<>()); + } + + public AuthorizationGroupBuilder users(Principal... principals) + { + PersonFetchOptions personFetchOptions = new PersonFetchOptions(); + Function<Principal, Person> mapper = p -> createPerson(p, personFetchOptions); + authorizationGroup.getUsers().addAll(Arrays.asList(principals).stream().map(mapper).collect(Collectors.toList())); + return this; + } + + AuthorizationGroup get() + { + return authorizationGroup; + } + } +} diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/history/ContentCopyHistoryEntry.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/history/ContentCopyHistoryEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..6fa5665e3af68fec44f57c026f301170909249de --- /dev/null +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/history/ContentCopyHistoryEntry.java @@ -0,0 +1,112 @@ +/* + * Copyright 2015 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.asapi.v3.dto.history; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import ch.systemsx.cisd.base.annotation.JsonObject; + +@JsonObject("as.dto.history.ContentCopyHistoryEntry") +public class ContentCopyHistoryEntry extends HistoryEntry +{ + + private static final long serialVersionUID = 1L; + + @JsonProperty + private String externalCode; + + @JsonProperty + private String path; + + @JsonProperty + private String gitCommitHash; + + @JsonProperty + private String gitRepositoryId; + + @JsonProperty + private Long externalDmsId; + + + @JsonIgnore + public String getExternalCode() + { + return externalCode; + } + + @JsonIgnore + public void setExternalCode(String externalCode) + { + this.externalCode = externalCode; + } + + @JsonIgnore + public String getPath() + { + return path; + } + + @JsonIgnore + public void setPath(String path) + { + this.path = path; + } + + @JsonIgnore + public String getGitCommitHash() + { + return gitCommitHash; + } + + @JsonIgnore + public void setGitCommitHash(String gitCommitHash) + { + this.gitCommitHash = gitCommitHash; + } + + @JsonIgnore + public String getGitRepositoryId() + { + return gitRepositoryId; + } + + @JsonIgnore + public void setGitRepositoryId(String gitRepositoryId) + { + this.gitRepositoryId = gitRepositoryId; + } + + @JsonIgnore + public Long getExternalDmsId() + { + return externalDmsId; + } + + @JsonIgnore + public void setExternalDmsId(Long externalDmsId) + { + this.externalDmsId = externalDmsId; + } + + @JsonIgnore + public static long getSerialversionuid() + { + return serialVersionUID; + } + +} diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/ICustomASServiceExecutor.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/ICustomASServiceExecutor.java index 2746d4af4ec37cd7a8115d0c6a34952eb369af09..b9c32d6ebf546b0b043371d9f75655fe30edc618 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/ICustomASServiceExecutor.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/ICustomASServiceExecutor.java @@ -16,6 +16,8 @@ package ch.ethz.sis.openbis.generic.asapi.v3.plugin.service; +import com.fasterxml.jackson.annotation.JsonIgnoreType; + import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.CustomASService; import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.CustomASServiceExecutionOptions; import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.context.CustomASServiceContext; @@ -25,6 +27,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.plugin.service.context.CustomASServi * * @author Franz-Josef Elmer */ +@JsonIgnoreType public interface ICustomASServiceExecutor { public Object executeService(CustomASServiceContext context, CustomASServiceExecutionOptions options); diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/IImportService.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/IImportService.java new file mode 100644 index 0000000000000000000000000000000000000000..11cff71a171dcdf760ca0beb5a5ae01cd32eb4c6 --- /dev/null +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/plugin/service/IImportService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2018 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 ch.ethz.sis.openbis.generic.asapi.v3.plugin.service; + +import com.fasterxml.jackson.annotation.JsonIgnoreType; + +/** + * @author pkupczyk + */ +@JsonIgnoreType +public interface IImportService +{ + + public String createExperiments(String sessionToken, String uploadKey, String experimentTypeCode, boolean async, String userEmail); + + public String updateExperiments(String sessionToken, String uploadKey, String experimentTypeCode, boolean async, String userEmail); + + public String createSamples(String sessionToken, String uploadKey, String sampleTypeCode, String defaultSpaceIdentifier, + String spaceIdentifierOverride, String experimentIdentifierOverride, boolean updateExisting, boolean async, String userEmail); + + public String updateSamples(String sessionToken, String uploadKey, String sampleTypeCode, String defaultSpaceIdentifier, + String spaceIdentifierOverride, String experimentIdentifierOverride, boolean async, String userEmail); + + public String updateDataSets(String sessionToken, String uploadKey, String dataSetTypeCode, boolean async, String userEmail); + + public String createMaterials(String sessionToken, String uploadKey, String materialTypeCode, boolean updateExisting, boolean async, + String userEmail); + + public String updateMaterials(String sessionToken, String uploadKey, String materialTypeCode, boolean ignoreUnregistered, boolean async, + String userEmail); + + public String generalImport(String sessionToken, String uploadKey, String defaultSpaceIdentifier, boolean updateExisting, boolean async, + String userEmail); + + public String customImport(String sessionToken, String uploadKey, String customImportCode, boolean async, String userEmail); + +} diff --git a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt index 62b71a076b04313c444a657fd7e8caf8af9d37e9..a2cab867610a17f5fc260e385fa827ce599e150e 100644 --- a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt +++ b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt @@ -79,6 +79,7 @@ COMPONENT CONTAINER contains containsAll +ContentCopyHistoryEntry count createDataSets createExperiments @@ -2122,3 +2123,7 @@ Person Fetch Options All WebApp Settings Handler Person Fetch Options WebApp Settings Handler WebApp Settings Fetch Options All Settings Handler WebApp Settings Fetch Options Settings Handler + +custom Import +general Import +I Import Service \ No newline at end of file diff --git a/openbis_standard_technologies/dist/server/service.properties b/openbis_standard_technologies/dist/server/service.properties index 865cac6396424b6a9b52bd1fa36ab186612808e9..8665d1c2cf2c86ca76f3fc7fe0c129a7767e5a5d 100644 --- a/openbis_standard_technologies/dist/server/service.properties +++ b/openbis_standard_technologies/dist/server/service.properties @@ -81,6 +81,8 @@ ldap.security.authentication-method = # "ignore" - ignore referrals # "throw" - throw ReferralException when a referral is encountered ldap.referral = +# The search base. +ldap.searchBase = # The attribute name for the user id, defaults to "uid" ldap.attributenames.user.id = # The attribute name for the email, defaults to "mail"