From 254d29d45f5f40d9b8f76b2990ce63733ae460a1 Mon Sep 17 00:00:00 2001 From: Sara Date: Wed, 11 Aug 2021 14:49:51 +0100 Subject: [PATCH] Feature/acs 1783 impl rest api for nodes (#653) * ACS-1783 Refactor Rest Api for Nodes * ACS-1783 Fix config default * ACS-1783 Updates for review * ACS-1783 Fix missing properties defaults * ACS-1783 Remove properties defaults * ACS-1783 Omit enabled default --- .../rest/api/DirectAccessUrlHelper.java | 66 +++++++++++++++++++ .../java/org/alfresco/rest/api/Nodes.java | 46 ++++++++++++- .../org/alfresco/rest/api/impl/NodesImpl.java | 17 ++++- .../api/model/DirectAccessUrlRequest.java | 46 +++++++++++++ .../rest/api/nodes/NodesEntityResource.java | 43 ++++++++++-- .../alfresco/public-rest-context.xml | 12 ++++ .../public-services-security-context.xml | 2 +- 7 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/DirectAccessUrlHelper.java create mode 100644 remote-api/src/main/java/org/alfresco/rest/api/model/DirectAccessUrlRequest.java diff --git a/remote-api/src/main/java/org/alfresco/rest/api/DirectAccessUrlHelper.java b/remote-api/src/main/java/org/alfresco/rest/api/DirectAccessUrlHelper.java new file mode 100644 index 0000000000..93d49d3c93 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/DirectAccessUrlHelper.java @@ -0,0 +1,66 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api; + +import org.alfresco.rest.api.impl.directurl.RestApiDirectUrlConfig; +import org.alfresco.rest.api.model.DirectAccessUrlRequest; +import org.alfresco.rest.framework.core.exceptions.DisabledServiceException; +import org.apache.commons.lang3.BooleanUtils; + +/** + * Helper class for retrieving direct access URLs options. + * + * @author Sara Aspery + */ +public class DirectAccessUrlHelper +{ + private RestApiDirectUrlConfig restApiDirectUrlConfig; + + public void setRestApiDirectUrlConfig(RestApiDirectUrlConfig restApiDirectUrlConfig) + { + this.restApiDirectUrlConfig = restApiDirectUrlConfig; + } + + public Long getDefaultExpiryTimeInSec() + { + if (restApiDirectUrlConfig ==null || !restApiDirectUrlConfig.isEnabled()) + { + throw new DisabledServiceException("Direct access url isn't available."); + } + + return restApiDirectUrlConfig.getDefaultExpiryTimeInSec(); + } + + public boolean getAttachment(DirectAccessUrlRequest directAccessUrlRequest) + { + boolean attachment = true; + if (directAccessUrlRequest != null ) + { + attachment = BooleanUtils.toBooleanDefaultIfNull(directAccessUrlRequest.isAttachment(), true); + } + return attachment; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/Nodes.java b/remote-api/src/main/java/org/alfresco/rest/api/Nodes.java index 48f1332d83..6fa9272e3d 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/Nodes.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/Nodes.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2017 Alfresco Software Limited + * Copyright (C) 2005 - 2021 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -44,6 +44,7 @@ import org.alfresco.rest.framework.resource.content.BinaryResource; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.DirectAccessUrl; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.QName; @@ -266,6 +267,49 @@ public interface Nodes */ Node unlock(String nodeId, Parameters parameters); + /** + * Gets a presigned URL to directly access content. + * @param nodeId The node id for which to obtain the direct access {@code URL} + * @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}. + * @return A direct access {@code URL} object for the content. + */ + default DirectAccessUrl requestContentDirectUrl(String nodeId, boolean attachment) + { + return requestContentDirectUrl(validateNode(nodeId), attachment); + } + + /** + * Gets a presigned URL to directly access content. + * @param nodeRef The node reference for which to obtain the direct access {@code URL} + * @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}. + * @return A direct access {@code URL} object for the content. + */ + default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment) + { + return requestContentDirectUrl(nodeRef, attachment, null); + } + + /** + * Gets a presigned URL to directly access content. + * @param nodeId The node id for which to obtain the direct access {@code URL} + * @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}. + * @param validFor The time at which the direct access {@code URL} will expire. + * @return A direct access {@code URL} object for the content. + */ + default DirectAccessUrl requestContentDirectUrl(String nodeId, boolean attachment, Long validFor) + { + return requestContentDirectUrl(validateNode(nodeId), attachment, validFor); + } + + /** + * Gets a presigned URL to directly access content. + * @param nodeRef The node reference for which to obtain the direct access {@code URL} + * @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}. + * @param validFor The time at which the direct access {@code URL} will expire. + * @return A direct access {@code URL} object for the content. + */ + DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor); + /** * Convert from node properties (map of QName to Serializable) retrieved from * the respository to a map of String to Object that can be formatted/expressed diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java index ed8bb25a44..1f88b43ca7 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2019 Alfresco Software Limited + * Copyright (C) 2005 - 2021 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -139,6 +139,7 @@ import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentIOException; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.DirectAccessUrl; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.MimetypeService; @@ -3413,6 +3414,20 @@ public class NodesImpl implements Nodes return getFolderOrDocument(nodeId, parameters); } + /** + * {@inheritDoc} + */ + @Override + public DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor) + { + DirectAccessUrl directAccessUrl = contentService.requestContentDirectUrl(nodeRef, attachment, validFor); + if (directAccessUrl == null) + { + throw new DisabledServiceException("Direct access url isn't available."); + } + return directAccessUrl; + } + /** * Checks if same permission is sent more than once * @param locallySetPermissions diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/DirectAccessUrlRequest.java b/remote-api/src/main/java/org/alfresco/rest/api/model/DirectAccessUrlRequest.java new file mode 100644 index 0000000000..6dde68adb2 --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/DirectAccessUrlRequest.java @@ -0,0 +1,46 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2021 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.model; + +/** + * Direct Access URL request. + * + * @author Sara Aspery + */ +public class DirectAccessUrlRequest +{ + private Boolean attachment; + + public Boolean isAttachment() + { + return attachment; + } + + public void setAttachment(Boolean attachment) + { + this.attachment = attachment; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodesEntityResource.java b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodesEntityResource.java index 7d7777aa31..c7cf7bca95 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodesEntityResource.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodesEntityResource.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2021 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -25,11 +25,13 @@ */ package org.alfresco.rest.api.nodes; +import javax.servlet.http.HttpServletResponse; import java.io.InputStream; -import javax.servlet.http.HttpServletResponse; - +import org.alfresco.repo.content.directurl.DirectAccessUrlDisabledException; +import org.alfresco.rest.api.DirectAccessUrlHelper; import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.api.model.DirectAccessUrlRequest; import org.alfresco.rest.api.model.LockInfo; import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.NodeTarget; @@ -37,6 +39,8 @@ import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.framework.Operation; import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiParam; +import org.alfresco.rest.framework.core.ResourceParameter; +import org.alfresco.rest.framework.core.exceptions.DisabledServiceException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction; @@ -45,7 +49,10 @@ import org.alfresco.rest.framework.resource.content.BasicContentInfo; import org.alfresco.rest.framework.resource.content.BinaryResource; import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.webscripts.WithResponse; +import org.alfresco.service.cmr.repository.DirectAccessUrl; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.ParameterCheck; + import org.springframework.beans.factory.InitializingBean; /** @@ -61,13 +68,19 @@ public class NodesEntityResource implements BinaryResourceAction.Read, BinaryResourceAction.Update, InitializingBean { private Nodes nodes; + private DirectAccessUrlHelper directAccessUrlHelper; public void setNodes(Nodes nodes) { this.nodes = nodes; } - @Override + public void setDirectAccessUrlHelper(DirectAccessUrlHelper directAccessUrlHelper) + { + this.directAccessUrlHelper = directAccessUrlHelper; + } + + @Override public void afterPropertiesSet() { ParameterCheck.mandatory("nodes", this.nodes); @@ -189,5 +202,27 @@ public class NodesEntityResource implements return nodes.unlock(nodeId, parameters); } + @Operation("requestNodeDirectAccessUrl") + @WebApiParam(name = "requestNodeDirectAccessUrl", title = "Request direct access url", description = "Request direct access url", kind = ResourceParameter.KIND.HTTP_BODY_OBJECT) + @WebApiDescription(title = "Request content url", + description="Generates a direct access URL.", + successStatus = HttpServletResponse.SC_OK) + public DirectAccessUrl requestContentDirectUrl(String nodeId, DirectAccessUrlRequest directAccessUrlRequest, Parameters parameters, WithResponse withResponse) + { + boolean attachment = directAccessUrlHelper.getAttachment(directAccessUrlRequest); + Long validFor = directAccessUrlHelper.getDefaultExpiryTimeInSec(); + NodeRef nodeRef = nodes.validateNode(nodeId); + + DirectAccessUrl directAccessUrl; + try + { + directAccessUrl = nodes.requestContentDirectUrl(nodeRef, attachment, validFor); + } + catch (DirectAccessUrlDisabledException ex) + { + throw new DisabledServiceException(ex.getMessage()); + } + return directAccessUrl; + } } diff --git a/remote-api/src/main/resources/alfresco/public-rest-context.xml b/remote-api/src/main/resources/alfresco/public-rest-context.xml index 9f659bc8b2..d0b9b18e7b 100644 --- a/remote-api/src/main/resources/alfresco/public-rest-context.xml +++ b/remote-api/src/main/resources/alfresco/public-rest-context.xml @@ -942,8 +942,13 @@ + + + + + @@ -1067,6 +1072,13 @@ + + + + + + + diff --git a/repository/src/main/resources/alfresco/public-services-security-context.xml b/repository/src/main/resources/alfresco/public-services-security-context.xml index d0506a5e62..c3c0aee115 100644 --- a/repository/src/main/resources/alfresco/public-services-security-context.xml +++ b/repository/src/main/resources/alfresco/public-services-security-context.xml @@ -494,7 +494,7 @@ org.alfresco.service.cmr.repository.ContentService.getRawReader=ACL_METHOD.ROLE_ADMINISTRATOR org.alfresco.service.cmr.repository.ContentService.getReader=ACL_NODE.0.sys:base.ReadContent org.alfresco.service.cmr.repository.ContentService.getWriter=ACL_NODE.0.sys:base.WriteContent - org.alfresco.service.cmr.repository.ContentService.getDirectAccessUrl=ACL_NODE.0.sys:base.ReadContent + org.alfresco.service.cmr.repository.ContentService.requestContentDirectUrl=ACL_NODE.0.sys:base.ReadContent org.alfresco.service.cmr.repository.ContentService.getTempWriter=ACL_ALLOW org.alfresco.service.cmr.repository.ContentService.isContentDirectUrlEnabled=ACL_ALLOW org.alfresco.service.cmr.repository.ContentService.*=ACL_DENY