/* * Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved. * * This library 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 2.1 of the License, or (at your option) * any later version. * * This library 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. */ package org.entando.entando.plugins.jacms.aps.system.services.api; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.ws.rs.core.Response; import org.entando.entando.aps.system.services.api.IApiErrorCodes; import org.entando.entando.aps.system.services.api.model.ApiError; import org.entando.entando.aps.system.services.api.model.ApiException; import org.entando.entando.aps.system.services.api.model.StringApiResponse; import org.entando.entando.aps.system.services.api.server.IResponseBuilder; import org.entando.entando.plugins.jacms.aps.system.services.api.model.JAXBResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.agiletec.aps.system.SystemConstants; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.authorization.IAuthorizationManager; import com.agiletec.aps.system.services.category.ICategoryManager; import com.agiletec.aps.system.services.group.Group; import com.agiletec.aps.system.services.group.IGroupManager; import com.agiletec.aps.system.services.user.IUserManager; import com.agiletec.aps.system.services.user.UserDetails; import com.agiletec.plugins.jacms.aps.system.JacmsSystemConstants; import com.agiletec.plugins.jacms.aps.system.services.content.IContentManager; import com.agiletec.plugins.jacms.aps.system.services.content.model.ContentRecordVO; import com.agiletec.plugins.jacms.aps.system.services.resource.IResourceManager; import com.agiletec.plugins.jacms.aps.system.services.resource.ResourceUtilizer; import com.agiletec.plugins.jacms.aps.system.services.resource.model.BaseResourceDataBean; import com.agiletec.plugins.jacms.aps.system.services.resource.model.ResourceInterface; /** * @author E.Santoboni */ public class ApiResourceInterface { private static final Logger _logger = LoggerFactory.getLogger(ApiResourceInterface.class); public List<String> getImages(Properties properties) throws Throwable { properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_IMAGE_CODE); return this.getResources(properties); } public List<String> getAttachments(Properties properties) throws Throwable { properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_ATTACH_CODE); return this.getResources(properties); } public List<String> getResources(Properties properties) throws Throwable { List<String> resources = null; try { String resourceTypeCode = properties.getProperty(RESOURCE_TYPE_CODE_PARAM); String description = properties.getProperty("description"); String filename = properties.getProperty("filename"); String category = properties.getProperty("category"); UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER); if (null == user) { user = this.getUserManager().getGuestUser(); } List<String> groupsCodes = this.getAllowedGroupCodes(user); resources = this.getResourceManager().searchResourcesId(resourceTypeCode, description, filename, category, groupsCodes); } catch (Throwable t) { _logger.error("error in getResources", t); throw t; } return resources; } private List<String> getAllowedGroupCodes(UserDetails user) { List<Group> groups = new ArrayList<Group>(); List<Group> groupsOfUser = this.getAuthorizationManager().getUserGroups(user); if (this.getAuthorizationManager().isAuthOnGroup(user, Group.ADMINS_GROUP_NAME)) { groups.addAll(this.getGroupManager().getGroups()); } else { groups.addAll(groupsOfUser); } List<String> codes = new ArrayList<String>(); for (int i = 0; i < groups.size(); i++) { Group group = groups.get(i); if (null != group) { codes.add(group.getName()); } } if (!codes.contains(Group.FREE_GROUP_NAME)) { codes.add(Group.FREE_GROUP_NAME); } return codes; } public JAXBResource getImage(Properties properties) throws Throwable { properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_IMAGE_CODE); return this.getResource(properties); } public JAXBResource getAttachment(Properties properties) throws Throwable { properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_ATTACH_CODE); return this.getResource(properties); } public JAXBResource getResource(Properties properties) throws Throwable { JAXBResource jaxbResource = null; String id = properties.getProperty("id"); String resourceTypeCode = properties.getProperty(RESOURCE_TYPE_CODE_PARAM); try { ResourceInterface resource = this.getResourceManager().loadResource(id); if (null == resource || !resource.getType().equalsIgnoreCase(resourceTypeCode)) { throw new ApiException(IApiErrorCodes.API_PARAMETER_VALIDATION_ERROR, "Null resource by id '" + id + "'", Response.Status.CONFLICT); } UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER); if (null == user) { user = this.getUserManager().getGuestUser(); } String groupName = resource.getMainGroup(); if (!Group.FREE_GROUP_NAME.equals(groupName) && !this.getAuthorizationManager().isAuthOnGroup(user, groupName)) { throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Required resource '" + id + "' does not allowed", Response.Status.FORBIDDEN); } jaxbResource = new JAXBResource(resource); } catch (ApiException ae) { throw ae; } catch (Throwable t) { _logger.error("error in getResource", t); throw new ApsSystemException("Error into API method", t); } return jaxbResource; } public StringApiResponse addImage(JAXBResource jaxbResource, Properties properties) throws Throwable { this.checkType(jaxbResource, JacmsSystemConstants.RESOURE_IMAGE_CODE); properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_IMAGE_CODE); return this.addResource(jaxbResource, properties); } public StringApiResponse addAttachment(JAXBResource jaxbResource, Properties properties) throws Throwable { this.checkType(jaxbResource, JacmsSystemConstants.RESOURE_ATTACH_CODE); properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_ATTACH_CODE); return this.addResource(jaxbResource, properties); } public StringApiResponse addResource(JAXBResource jaxbResource, Properties properties) throws ApiException, Throwable { StringApiResponse response = new StringApiResponse(); BaseResourceDataBean bean = null; try { UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER); this.check(jaxbResource, user, response, true); if (null != response.getErrors() && !response.getErrors().isEmpty()) { return response; } bean = jaxbResource.createBataBean(this.getCategoryManager()); String id = bean.getResourceId(); if (null != id && id.trim().length() > 0) { Pattern pattern = Pattern.compile("^[a-zA-Z]+$"); Matcher matcher = pattern.matcher(id); if (!matcher.matches()) { throw new ApiException(IApiErrorCodes.API_PARAMETER_VALIDATION_ERROR, "The resourceId can contain only alphabetic characters", Response.Status.CONFLICT); } } this.getResourceManager().addResource(bean); response.setResult(IResponseBuilder.SUCCESS); } catch (ApiException ae) { throw ae; } catch (Throwable t) { _logger.error("error in addResource", t); throw new ApsSystemException("Error into API method", t); } finally { if (null != bean && null != bean.getFile()) { bean.getFile().delete(); } } return response; } public StringApiResponse updateImage(JAXBResource jaxbResource, Properties properties) throws Throwable { this.checkType(jaxbResource, JacmsSystemConstants.RESOURE_IMAGE_CODE); properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_IMAGE_CODE); return this.updateResource(jaxbResource, properties); } public StringApiResponse updateAttachment(JAXBResource jaxbResource, Properties properties) throws Throwable { this.checkType(jaxbResource, JacmsSystemConstants.RESOURE_ATTACH_CODE); properties.setProperty(RESOURCE_TYPE_CODE_PARAM, JacmsSystemConstants.RESOURE_ATTACH_CODE); return this.updateResource(jaxbResource, properties); } private void checkType(JAXBResource jaxbResource, String expectedTypeCode) throws Throwable { if (!jaxbResource.getTypeCode().equals(expectedTypeCode)) { throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Invalid resource type - '" + jaxbResource.getTypeCode() + "'", Response.Status.CONFLICT); } } public StringApiResponse updateResource(JAXBResource jaxbResource, Properties properties) throws Throwable { StringApiResponse response = new StringApiResponse(); BaseResourceDataBean bean = null; try { UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER); this.check(jaxbResource, user, response, false); if (null != response.getErrors() && !response.getErrors().isEmpty()) { return response; } bean = jaxbResource.createBataBean(this.getCategoryManager()); this.getResourceManager().updateResource(bean); response.setResult(IResponseBuilder.SUCCESS); } catch (Throwable t) { _logger.error("error in updateResource", t); throw new ApsSystemException("Error into API method", t); } finally { if (null != bean && null != bean.getFile()) { bean.getFile().delete(); } } return response; } private void check(JAXBResource jaxbResource, UserDetails user, StringApiResponse response, boolean add) throws Throwable { ResourceInterface resourcePrototype = this.getResourceManager().createResourceType(jaxbResource.getTypeCode()); if (null == resourcePrototype) { this.addValidationError("Invalid resource type - '" + jaxbResource.getTypeCode() + "'", response); } if (null == user) { user = this.getUserManager().getGuestUser(); } String groupName = jaxbResource.getMainGroup(); if (null == groupName || groupName.trim().length() == 0) { this.addValidationError("Group required", response); } else { if (null == this.getGroupManager().getGroup(groupName)) { //this.addValidationError("Group '" + groupName + "' does not exist", response); } else if (!this.getAuthorizationManager().isAuthOnGroup(user, groupName)) { //this.addValidationError("Group '" + groupName + "' not allowed", response); } } if (add) { if (null == jaxbResource.getBase64()) { this.addValidationError("Binary Image required", response); } if (null == jaxbResource.getFileName() || jaxbResource.getFileName().trim().length() == 0) { this.addValidationError("FileName required", response); } } else { ResourceInterface oldResource = this.getResourceManager().loadResource(jaxbResource.getId()); if (null == oldResource) { this.addValidationError("Resource with id '" + jaxbResource.getId() + "' does not exist", response); } else if (!oldResource.getMainGroup().equals(jaxbResource.getMainGroup())) { this.addValidationError("Resource group has to be '" + oldResource.getMainGroup() + "'", response); } } /* if (this.isDuplicateFile(jaxbResource, resourcePrototype, add)) { this.addValidationError("File '" + jaxbResource.getFileName() + "' is already present on Archive", response); } */ if (null == jaxbResource.getDescription() || jaxbResource.getDescription().trim().length() == 0) { this.addValidationError("Description required", response); } if (null == jaxbResource.getTypeCode() || jaxbResource.getTypeCode().trim().length() == 0) { this.addValidationError("TypeCode required", response); } } /* private boolean isDuplicateFile(JAXBResource jaxbResource, ResourceInterface resourcePrototype, boolean add) { if (null == jaxbResource.getBase64()) return false; boolean addError = true; String formFileName = jaxbResource.getFileName(); try { resourcePrototype.setMainGroup(jaxbResource.getMainGroup()); if (resourcePrototype.exists(formFileName)) { if (!add) { ResourceInterface masterResource = this.getResourceManager().loadResource(jaxbResource.getId()); String masterFileName = (null != masterResource) ? masterResource.getMasterFileName() : null; if (null != masterFileName && masterFileName.equalsIgnoreCase(formFileName)) { addError = false; } } } else { addError = false; } } catch (Throwable t) { _logger.error("Error while check duplicate file - master file name '{}'", formFileName, t); } return addError; } */ private void addValidationError(String message, StringApiResponse response) { ApiError error = new ApiError(IApiErrorCodes.API_VALIDATION_ERROR, message, Response.Status.FORBIDDEN); response.addError(error); } /** * Delete an Image Resource. The method can be called by Entando API Engine. * @param properties The properties of the DELETE method call. * @return The response of the deleting * @throws Throwable Il case of error. */ public StringApiResponse deleteImage(Properties properties) throws Throwable { return this.deleteResource(properties, JacmsSystemConstants.RESOURE_IMAGE_CODE); } /** * Delete an Attach Resource. The method can be called by Entando API Engine. * @param properties The properties of the DELETE method call. * @return The response of the deleting * @throws Throwable Il case of error. */ public StringApiResponse deleteAttachment(Properties properties) throws Throwable { return this.deleteResource(properties, JacmsSystemConstants.RESOURE_ATTACH_CODE); } private StringApiResponse deleteResource(Properties properties, String expectedTypeCode) throws ApiException, Throwable { StringApiResponse response = null; try { String id = properties.getProperty("id"); ResourceInterface resource = this.getResourceManager().loadResource(id); if (null != resource && !resource.getType().equals(expectedTypeCode)) { throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Invalid resource type - '" + resource.getType() + "'", Response.Status.CONFLICT); } properties.setProperty(RESOURCE_TYPE_CODE_PARAM, expectedTypeCode); response = this.deleteResource(properties, resource); } catch (ApiException ae) { throw ae; } catch (Throwable t) { _logger.error("Error deleting resource", t); //ApsSystemUtils.logThrowable(t, this, "deleteResource"); throw new ApsSystemException("Error deleting resource", t); } return response; } /** * Delete a Resource. The method can be called by Entando API Engine. * @param properties The properties of the DELETE method call. * @throws Throwable Il case of error. */ public StringApiResponse deleteResource(Properties properties) throws Throwable { StringApiResponse response = null; try { String id = properties.getProperty("id"); ResourceInterface resource = this.getResourceManager().loadResource(id); response = this.deleteResource(properties, resource); } catch (Throwable t) { _logger.error("Error deleting resource", t); //ApsSystemUtils.logThrowable(t, this, "deleteResource"); throw new ApsSystemException("Error deleting resource", t); } return response; } private StringApiResponse deleteResource(Properties properties, ResourceInterface resource) throws ApiException, Throwable { StringApiResponse response = new StringApiResponse(); try { String id = properties.getProperty("id"); if (null == resource) { throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Resource with code '" + id + "' does not exist", Response.Status.CONFLICT); } UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER); if (null == user) { user = this.getUserManager().getGuestUser(); } if (!this.getAuthorizationManager().isAuthOnGroup(user, resource.getMainGroup())) { throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Resource not allowed for user '" + user.getUsername() + "' - resource group '" + resource.getMainGroup() + "'", Response.Status.FORBIDDEN); } List<String> references = ((ResourceUtilizer) this.getContentManager()).getResourceUtilizers(id); if (references != null && references.size() > 0) { boolean found = false; for (int i = 0; i < references.size(); i++) { String reference = references.get(i); ContentRecordVO record = this.getContentManager().loadContentVO(reference); if (null != record) { found = true; response.addError(new ApiError(IApiErrorCodes.API_VALIDATION_ERROR, "Resource " + id + " referenced to content " + record.getId() + " - '" + record.getDescr() + "'", Response.Status.CONFLICT)); } } if (found) { response.setResult(IResponseBuilder.FAILURE, null); return response; } } this.getResourceManager().deleteResource(resource); response.setResult(IResponseBuilder.SUCCESS, null); } catch (ApiException ae) { response.addErrors(ae.getErrors()); response.setResult(IResponseBuilder.FAILURE, null); } catch (Throwable t) { _logger.error("Error deleting resource", t); //ApsSystemUtils.logThrowable(t, this, "deleteResource"); throw new ApsSystemException("Error deleting resource", t); } return response; } protected IResourceManager getResourceManager() { return _resourceManager; } public void setResourceManager(IResourceManager resourceManager) { this._resourceManager = resourceManager; } protected IContentManager getContentManager() { return _contentManager; } public void setContentManager(IContentManager contentManager) { this._contentManager = contentManager; } protected IUserManager getUserManager() { return _userManager; } public void setUserManager(IUserManager userManager) { this._userManager = userManager; } protected IGroupManager getGroupManager() { return groupManager; } public void setGroupManager(IGroupManager groupManager) { this.groupManager = groupManager; } protected IAuthorizationManager getAuthorizationManager() { return _authorizationManager; } public void setAuthorizationManager(IAuthorizationManager authorizationManager) { this._authorizationManager = authorizationManager; } protected ICategoryManager getCategoryManager() { return _categoryManager; } public void setCategoryManager(ICategoryManager categoryManager) { this._categoryManager = categoryManager; } private IResourceManager _resourceManager; private IContentManager _contentManager; private IUserManager _userManager; private IGroupManager groupManager; private IAuthorizationManager _authorizationManager; private ICategoryManager _categoryManager; private static final String RESOURCE_TYPE_CODE_PARAM = "resourceTypeCode"; }