diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/rights/GetRightsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/rights/GetRightsExecutor.java index 9a2734fed80916da15e831b4a5470403bae71dbf..d0756a2fc6f4c046daa1b8ac2d433cc5732c9f24 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/rights/GetRightsExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/rights/GetRightsExecutor.java @@ -17,6 +17,7 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.rights; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -24,27 +25,40 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier; import ch.ethz.sis.openbis.generic.asapi.v3.dto.rights.Right; import ch.ethz.sis.openbis.generic.asapi.v3.dto.rights.Rights; import ch.ethz.sis.openbis.generic.asapi.v3.dto.rights.fetchoptions.RightsFetchOptions; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset.IDataSetAuthorizationExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset.IMapDataSetByIdExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.experiment.IExperimentAuthorizationExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.experiment.IMapExperimentByIdExecutor; +import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.project.IMapProjectByIdExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample.IMapSampleByIdExecutor; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample.ISampleAuthorizationExecutor; +import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.space.IMapSpaceByIdExecutor; +import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample.FullSampleIdentifier; +import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample.SampleIdentifierParts; import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; +import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE; /** * @author Franz-Josef Elmer @@ -52,6 +66,12 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; @Component public class GetRightsExecutor implements IGetRightsExecutor { + @Autowired + private IMapSpaceByIdExecutor mapSpaceByIdExecutor; + + @Autowired + private IMapProjectByIdExecutor mapProjectByIdExecutor; + @Autowired private IMapSampleByIdExecutor mapSampleByIdExecutor; @@ -70,42 +90,38 @@ public class GetRightsExecutor implements IGetRightsExecutor @Autowired private IDataSetAuthorizationExecutor dataSetAuthorizationExecutor; - private List<Handler> handlers; - - public GetRightsExecutor() - { - handlers = new ArrayList<>(); - handlers.add(new SampleHandler()); - handlers.add(new ExperimentHandler()); - handlers.add(new DataSetHandler()); - } - @Override public Map<IObjectId, Rights> getRights(IOperationContext context, List<? extends IObjectId> objectIds, RightsFetchOptions fetchOptions) { Map<IObjectId, Rights> result = new HashMap<>(); + List<IHandler> handlers = createHandlers(); for (IObjectId id : objectIds) { - for (Handler handler : handlers) + for (IHandler handler : handlers) { handler.handle(id); } } - for (Handler handler : handlers) + for (IHandler handler : handlers) { handler.addRights(context, result); } return result; } - private static interface Handler + private List<IHandler> createHandlers() + { + return Arrays.asList(new SampleHandler(), new ExperimentHandler(), new DataSetHandler()); + } + + private static interface IHandler { void handle(IObjectId id); void addRights(IOperationContext context, Map<IObjectId, Rights> rightsByIds); } - private class SampleHandler implements Handler + private class SampleHandler implements IHandler { private List<ISampleId> sampleIds = new ArrayList<>(); @@ -122,6 +138,7 @@ public class GetRightsExecutor implements IGetRightsExecutor public void addRights(IOperationContext context, Map<IObjectId, Rights> rightsByIds) { Map<ISampleId, SamplePE> map = mapSampleByIdExecutor.map(context, sampleIds); + Set<ISampleId> unknownSamples = new HashSet<>(sampleIds); for (Entry<ISampleId, SamplePE> entry : map.entrySet()) { Set<Right> rights = new HashSet<>(); @@ -137,11 +154,80 @@ public class GetRightsExecutor implements IGetRightsExecutor // silently ignored } rightsByIds.put(id, new Rights(rights)); + unknownSamples.remove(id); + } + for (ISampleId id : unknownSamples) + { + Set<Right> rights = new HashSet<>(); + try + { + SamplePE sample = createDummySample(context, id); + sampleAuthorizationExecutor.canCreate(context, sample); + rights.add(Right.CREATE); + } catch (AuthorizationFailureException e) + { + // silently ignored + } + rightsByIds.put(id, new Rights(rights)); + } + } + } + + private SamplePE createDummySample(IOperationContext context, ISampleId sampleId) + { + if (sampleId == null) + { + throw new UserFailureException("Unspecified sample id."); + } + if (sampleId instanceof CreationId) + { + throw new UserFailureException("Sample id '" + sampleId + "' can not be a CreationId."); + } + if (sampleId instanceof SamplePermId) + { + throw new UserFailureException("Sample id '" + sampleId + "' can not be a SamplePermId."); + } + if (sampleId instanceof SampleIdentifier == false) + { + throw new UserFailureException("Sample id '" + sampleId + "' is of unknown type " + + sampleId.getClass().getName() + "."); + } + SpacePE homeSpace = context.getSession().tryGetHomeGroup(); + FullSampleIdentifier sampleIdentifier = new FullSampleIdentifier(((SampleIdentifier) sampleId).getIdentifier(), + homeSpace == null ? null : homeSpace.getCode()); + SampleIdentifierParts parts = sampleIdentifier.getParts(); + SamplePE samplePE = new SamplePE(); + samplePE.setCode(sampleIdentifier.getSampleCode()); + String spaceCode = parts.getSpaceCodeOrNull(); + if (StringUtils.isNotBlank(spaceCode)) + { + SpacePermId spacePermId = new SpacePermId(spaceCode); + SpacePE spacePE = mapSpaceByIdExecutor.map(context, Arrays.asList(spacePermId)).get(spacePermId); + if (spacePE == null) + { + throw new UserFailureException("Unknown space in sample identifier '" + sampleId + "'."); + } + samplePE.setSpace(spacePE); + } + String projectCode = parts.getProjectCodeOrNull(); + if (StringUtils.isNotBlank(projectCode)) + { + if (StringUtils.isBlank(spaceCode)) + { + throw new UserFailureException("Unknown space in sample identifier '" + sampleId + "'."); + } + ProjectIdentifier projectIdentifier = new ProjectIdentifier(spaceCode, projectCode); + ProjectPE projectPE = mapProjectByIdExecutor.map(context, Arrays.asList(projectIdentifier)).get(projectIdentifier); + if (projectPE == null) + { + throw new UserFailureException("Unknown project in sample identifier '" + sampleId + "'."); } + samplePE.setProject(projectPE); } + return samplePE; } - private class ExperimentHandler implements Handler + private class ExperimentHandler implements IHandler { private List<IExperimentId> experimentIds = new ArrayList<>(); @@ -177,7 +263,7 @@ public class GetRightsExecutor implements IGetRightsExecutor } } - private class DataSetHandler implements Handler + private class DataSetHandler implements IHandler { private List<IDataSetId> dataSetIds = new ArrayList<>(); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/rights/Right.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/rights/Right.js index b9aa090e7d4b5675710ffeaead1525cf595bd063..b568bf526c829b54dde98a94ac073af6046ade45 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/rights/Right.js +++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/rights/Right.js @@ -1,6 +1,6 @@ define([ "stjs", "as/dto/common/Enum" ], function(stjs, Enum) { var Right = function() { - Enum.call(this, [ "UPDATE", "CREATE_SAMPLE" ]); + Enum.call(this, [ "CREATE", "UPDATE" ]); }; stjs.extend(Right, Enum, [ Enum ], function(constructor, prototype) { }, {}); diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetRightsTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetRightsTest.java index d7245ac439b160245894950d951ff4bca8168176..3d393cd59c4f56e69d781250e9551a6892315456 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetRightsTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetRightsTest.java @@ -23,12 +23,14 @@ import java.util.Map; import org.testng.annotations.Test; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier; import ch.ethz.sis.openbis.generic.asapi.v3.dto.rights.Rights; import ch.ethz.sis.openbis.generic.asapi.v3.dto.rights.fetchoptions.RightsFetchOptions; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; +import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId; /** * @author Franz-Josef Elmer @@ -42,13 +44,71 @@ public class GetRightsTest extends AbstractTest String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD); IObjectId s1 = new SampleIdentifier("/TEST-SPACE/CP-TEST-4"); IObjectId s2 = new SampleIdentifier("/CISD/CP-TEST-1"); + IObjectId s3 = new SampleIdentifier("/CISD/NEW"); + IObjectId s4 = new SampleIdentifier("/CISD/NEMO/NEW"); + IObjectId s5 = new SampleIdentifier("/TEST-SPACE/NOE/NEW"); // When - Map<IObjectId, Rights> map = v3api.getRights(sessionToken, Arrays.asList(s1, s2), new RightsFetchOptions()); + Map<IObjectId, Rights> map = v3api.getRights(sessionToken, Arrays.asList(s1, s2, s3, s4, s5), new RightsFetchOptions()); // Then assertEquals(map.get(s1).getRights().toString(), "[]"); assertEquals(map.get(s2).getRights().toString(), "[UPDATE]"); + assertEquals(map.get(s3).getRights().toString(), "[CREATE]"); + assertEquals(map.get(s4).getRights().toString(), "[CREATE]"); + assertEquals(map.get(s5).getRights().toString(), "[]"); + } + + @Test + public void testGetSampleCreationRightForSamplePermId() + { + // Given + String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD); + IObjectId s1 = new SamplePermId("123-45"); + + // When + assertUserFailureException(Void -> v3api.getRights(sessionToken, Arrays.asList(s1), new RightsFetchOptions()), + // Then + "Sample id '123-45' can not be a SamplePermId."); + } + + @Test + public void testGetSampleCreationRightForCreationId() + { + // Given + String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD); + IObjectId s1 = new CreationId("123-45"); + + // When + assertUserFailureException(Void -> v3api.getRights(sessionToken, Arrays.asList(s1), new RightsFetchOptions()), + // Then + "Sample id '123-45' can not be a CreationId."); + } + + @Test + public void testGetSampleCreationRightInMissingSpace() + { + // Given + String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD); + IObjectId s1 = new SampleIdentifier("/NO-SPACE/NEW"); + + // When + assertUserFailureException(Void -> v3api.getRights(sessionToken, Arrays.asList(s1), new RightsFetchOptions()), + // Then + "Unknown space in sample identifier '/NO-SPACE/NEW'."); + } + + @Test + public void testGetSampleCreationRightInMissingProject() + { + // Given + String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD); + IObjectId s1 = new SampleIdentifier("/TEST-SPACE/NO-PROJECT/NEW"); + + // When + assertUserFailureException(Void -> v3api.getRights(sessionToken, Arrays.asList(s1), new RightsFetchOptions()), + // Then + "Unknown project in sample identifier '/TEST-SPACE/NO-PROJECT/NEW'."); } @Test diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/rights/Right.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/rights/Right.java index 6cc6dcd9abe33f10ad25a2f69c3630da8ecb3b78..cd0bddc137ce786b3d8e9122ef91cd2c19f7866c 100644 --- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/rights/Right.java +++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/rights/Right.java @@ -24,5 +24,5 @@ import ch.systemsx.cisd.base.annotation.JsonObject; @JsonObject("as.dto.rights.Right") public enum Right { - UPDATE, CREATE_SAMPLE + CREATE, UPDATE } 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 d789dda8868bd61bd555440bc7041ccfe56a76d0..2f9aac83f7659faa35514a63f5ae5b2e83333e50 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 @@ -2329,5 +2329,5 @@ Right Rights Rights Fetch Options set Rights -CREATE_SAMPLE +CREATE diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormController.js index 8109e976e41de632e59fe3e2e4c24e0b317a4caa..b00b0a73c14c58c5086c4fc67d9d3438ca2c4cec 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormController.js +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormController.js @@ -22,15 +22,20 @@ function ExperimentFormController(mainController, mode, experiment) { this.init = function(views) { var _this = this; - require([ "as/dto/experiment/id/ExperimentPermId", "as/dto/experiment/fetchoptions/ExperimentFetchOptions" ], - function(ExperimentPermId, ExperimentFetchOptions) { + require([ "as/dto/experiment/id/ExperimentPermId", "as/dto/sample/id/SampleIdentifier", "as/dto/experiment/fetchoptions/ExperimentFetchOptions" ], + function(ExperimentPermId, SampleIdentifier, ExperimentFetchOptions) { var id = new ExperimentPermId(experiment.permId); var fetchOptions = new ExperimentFetchOptions(); fetchOptions.withProject().withSpace(); mainController.openbisV3.getExperiments([ id ], fetchOptions).done(function(map) { _this._experimentFormModel.v3_experiment = map[id]; - mainController.openbisV3.getRights([ id ], null).done(function(rightsByIds) { + var expeId = _this._experimentFormModel.v3_experiment.getIdentifier().getIdentifier(); + var spaceCode = IdentifierUtil.getSpaceCodeFromIdentifier(expeId); + var projectCode = IdentifierUtil.getProjectCodeFromExperimentIdentifier(expeId); + var dummySampleId = new SampleIdentifier("/" + spaceCode + "/" + projectCode + "/DUMMY"); + mainController.openbisV3.getRights([ id , dummySampleId], null).done(function(rightsByIds) { _this._experimentFormModel.rights = rightsByIds[id]; + _this._experimentFormModel.sampleRights = rightsByIds[dummySampleId]; _this._experimentFormView.repaint(views); }); }); diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormView.js index 99c98af8f23650988552da95068804f915140e36..faa979e236a0f6c0d24314af337c68c55ed8b90d 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormView.js +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ExperimentForm/ExperimentFormView.js @@ -570,7 +570,9 @@ function ExperimentFormView(experimentFormController, experimentFormModel) { var experiment = this._experimentFormModel.v3_experiment; var project = experiment.project; var space = project.space; - return experiment.frozenForSamples == false && project.frozenForSamples == false && space.frozenForSamples == false; + + return experiment.frozenForSamples == false && project.frozenForSamples == false && space.frozenForSamples == false + && this._experimentFormModel.sampleRights.rights.indexOf("CREATE") >= 0; } this._allowedToEdit = function() {