/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.agiletec.plugins.jpcrowdsourcing.aps.system.services.idea;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.ws.rs.core.Response;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.entando.entando.aps.system.services.api.IApiErrorCodes;
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.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.category.Category;
import com.agiletec.aps.system.services.category.ICategoryManager;
import com.agiletec.aps.system.services.lang.ILangManager;
import com.agiletec.aps.system.services.lang.Lang;
import com.agiletec.aps.system.services.role.Permission;
import com.agiletec.aps.system.services.user.UserDetails;
import com.agiletec.apsadmin.category.helper.ICategoryActionHelper;
import com.agiletec.plugins.jpcrowdsourcing.aps.system.services.common.api.CollaborationAbstractApiInterface;
import com.agiletec.plugins.jpcrowdsourcing.aps.system.services.idea.api.JAXBIdea;
import com.agiletec.plugins.jpcrowdsourcing.aps.system.services.idea.api.JAXBVote;
import com.agiletec.plugins.jpcrowdsourcing.aps.system.services.ideainstance.IIdeaInstanceManager;
import com.agiletec.plugins.jpcrowdsourcing.aps.system.services.ideainstance.IdeaInstance;
import com.agiletec.plugins.jpcrowdsourcing.apsadmin.util.SmallCategory;
public class ApiIdeaInterface extends CollaborationAbstractApiInterface {
private static final Logger _logger = LoggerFactory.getLogger(ApiIdeaInterface.class);
/**
* GET http://localhost:8080/<portal>/api/rs/en/ideaInstances?
* @param properties
* @return
* @throws Throwable
*/
public List<String> getIdeaListForApi(Properties properties) throws Throwable {
List<String> result = new ArrayList<String>();
try {
Collection<String> groupCodes = this.extractGroups(properties);
//required params
String codeParam = properties.getProperty("code");
if (StringUtils.isNotBlank(codeParam)) codeParam = URLDecoder.decode(codeParam, "UTF-8");
IdeaInstance instance = this.getIdeaInstanceManager().getIdeaInstance(codeParam);
if (null == instance) {
_logger.warn("instance {} not found", codeParam);
return null;
}
if (!CollectionUtils.containsAny(groupCodes, instance.getGroups())) {
_logger.warn("the current user is not granted to any group required by instance {}", codeParam);
return null;
}
//optional params
String textParam = properties.getProperty("text");
if (StringUtils.isNotBlank(textParam)) textParam = URLDecoder.decode(codeParam, "UTF-8");
String tagParam = properties.getProperty("tag");
String orderParam = properties.getProperty("order");
Integer order = null;
if (StringUtils.isNotBlank(orderParam) && orderParam.equalsIgnoreCase("latest")) {
order = IIdeaDAO.SORT_LATEST;
} else if (StringUtils.isNotBlank(orderParam) && orderParam.equalsIgnoreCase("rated")) {
order = IIdeaDAO.SORT_MOST_RATED;
}
result = this.getIdeaManager().searchIdeas(codeParam, IIdea.STATUS_APPROVED, textParam, tagParam, order);
} catch (Throwable t) {
_logger.error("Error loading idea list", t);
throw new ApsSystemException("Error loading idea list", t);
}
return result;
}
/**
* GET http://localhost:8080/<portal>/api/rs/en/idea?code=1
* @param properties
* @return
* @throws Throwable
*/
public JAXBIdea getIdeaForApi(Properties properties) throws Throwable {
JAXBIdea jaxbIdea = null;
try {
String codeParam = properties.getProperty("code");
if (StringUtils.isNotBlank(codeParam)) codeParam = URLDecoder.decode(codeParam, "UTF-8");
IIdea idea = this.getIdeaManager().getIdea(codeParam);
if (null == idea) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + codeParam + "' does not exist", Response.Status.CONFLICT);
}
UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER);
Collection<Integer> userStatusList = this.extractIdeaStatusListForUser(user);
IdeaInstance instance = this.getIdeaInstanceManager().getIdeaInstance(idea.getInstanceCode());
if (null == instance) {
_logger.warn("instance {} not found", idea.getInstanceCode());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + idea.getId() + "' does not exist", Response.Status.CONFLICT);
}
if (!isAuthOnInstance(user, instance)) {
_logger.warn("the current user is not granted to any group required by instance {}", idea.getId());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + idea.getId() + "' does not exist", Response.Status.CONFLICT);
}
if (!userStatusList.contains(idea.getStatus())) {
_logger.warn("the current user is not granted to access to idea {} due to the status {}", codeParam, idea.getStatus());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + codeParam + "' does not exist", Response.Status.CONFLICT);
}
jaxbIdea = new JAXBIdea(idea);
//TODO CREATE ROLE
if (null == user || !this.getAuthorizationManager().isAuthOnPermission(user, Permission.SUPERUSER)) {
if (null != jaxbIdea) {
jaxbIdea.getCommentsNotApproved().clear();
jaxbIdea.getCommentsToApprove().clear();
}
}
} catch (ApiException ae) {
throw ae;
} catch (Throwable t) {
_logger.error("Error loading idea", t);
throw new ApsSystemException("Error loading idea", t);
}
return jaxbIdea;
}
public StringApiResponse voteIdea(JAXBVote vote, Properties properties) throws ApiException, Throwable {
StringApiResponse response = new StringApiResponse();
try {
String ideaId = vote.getIdeaId();
if (StringUtils.isNotBlank(ideaId)) ideaId = URLDecoder.decode(ideaId, "UTF-8");
IIdea idea = this.getIdeaManager().getIdea(ideaId);
if (null == idea) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + ideaId + "' does not exist", Response.Status.CONFLICT);
}
UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER);
IdeaInstance instance = this.getIdeaInstanceManager().getIdeaInstance(idea.getInstanceCode());
if (null == instance) {
_logger.warn("instance {} not found", idea.getInstanceCode());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "IdeaInstance with code '" + idea.getInstanceCode() + "' does not exist", Response.Status.CONFLICT);
}
if (!isAuthOnInstance(user, instance)) {
_logger.warn("the current user is not granted to any group required by instance {}", instance.getCode());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "IdeaInstance with code '" + instance.getCode() + "' does not exist", Response.Status.CONFLICT);
}
if (idea.getStatus() != IIdea.STATUS_APPROVED) {
_logger.warn("the idea {} is not in statu approved ", idea.getId(), idea.getStatus());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + idea.getId() + "' does not exist", Response.Status.CONFLICT);
}
String voteType = vote.getType();
if (StringUtils.isBlank(voteType)) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Vote is required", Response.Status.CONFLICT);
}
if (!voteType.equals("like") && !voteType.equals("unlike")) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Vote invalid. Accepted values are 'like' and 'unlike'", Response.Status.CONFLICT);
}
if (StringUtils.isNotBlank(voteType)) voteType = URLDecoder.decode(voteType, "UTF-8");
if (voteType.equalsIgnoreCase("like")) {
((Idea)idea).setVotePositive(idea.getVotePositive() + 1);
this.getIdeaManager().updateIdea(idea);
} else if (voteType.equalsIgnoreCase("unlike")) {
((Idea)idea).setVoteNegative(idea.getVoteNegative() + 1);
this.getIdeaManager().updateIdea(idea);
}
response.setResult(IResponseBuilder.SUCCESS, null);
} catch (ApiException ae) {
response.addErrors(ae.getErrors());
response.setResult(IResponseBuilder.FAILURE, null);
} catch (Throwable t) {
_logger.error("Error on vote", t);
throw new ApsSystemException("Error on vote", t);
}
return response;
}
public StringApiResponse addIdea(JAXBIdea jaxbIdea, Properties properties) throws ApiException, Throwable {
StringApiResponse response = new StringApiResponse();
try {
UserDetails user = (UserDetails) properties.get(SystemConstants.API_USER_PARAMETER);
String langCode = (String) properties.get(SystemConstants.API_LANG_CODE_PARAMETER);
String instanceCode = jaxbIdea.getInstanceCode();
IdeaInstance instance = this.getIdeaInstanceManager().getIdeaInstance(instanceCode);
if (null == instance) {
_logger.warn("instance {} not found", instanceCode);
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "IdeaInstance with code '" + instanceCode + "' does not exist", Response.Status.CONFLICT);
}
if (!isAuthOnInstance(user, instance)) {
_logger.warn("the current user is not granted to any group required by instance {}", instance.getCode());
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "IdeaInstance with code '" + instance.getCode() + "' does not exist", Response.Status.CONFLICT);
}
if (StringUtils.isBlank(jaxbIdea.getTitle())) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Title is required", Response.Status.CONFLICT);
}
if (StringUtils.isBlank(jaxbIdea.getDescr())) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Description is required", Response.Status.CONFLICT);
}
if (null == jaxbIdea.getTags() || jaxbIdea.getTags().isEmpty()) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Tags is required", Response.Status.CONFLICT);
}
Set<String> tags = this.joinCategories(jaxbIdea, langCode);
Idea idea = jaxbIdea.getIdea();
idea.setTags(new ArrayList<String>(tags));
idea.setUsername(user.getUsername());
this.getIdeaManager().addIdea(idea);
response.setResult(IResponseBuilder.SUCCESS, null);
} catch (ApiException ae) {
response.addErrors(ae.getErrors());
response.setResult(IResponseBuilder.FAILURE, null);
} catch (Throwable t) {
_logger.error("Error on add idea", t);
throw new ApsSystemException("Error on add idea", t);
}
return response;
}
public StringApiResponse updateIdea(JAXBIdea jaxbIdea, Properties properties) throws ApiException, Throwable {
StringApiResponse response = new StringApiResponse();
try {
String langCode = (String) properties.get(SystemConstants.API_LANG_CODE_PARAMETER);
String instanceCode = jaxbIdea.getInstanceCode();
String id = jaxbIdea.getId();
IIdea clone = this.getIdeaManager().getIdea(id);
if (null == clone) {
_logger.warn("idea {} not found", id);
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + id + "' does not exist", Response.Status.CONFLICT);
}
IdeaInstance instance = this.getIdeaInstanceManager().getIdeaInstance(instanceCode);
if (null == instance) {
_logger.warn("instance {} not found", instanceCode);
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "IdeaInstance with code '" + instanceCode + "' does not exist", Response.Status.CONFLICT);
}
if (StringUtils.isBlank(jaxbIdea.getTitle())) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Title is required", Response.Status.CONFLICT);
}
if (StringUtils.isBlank(jaxbIdea.getDescr())) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Description is required", Response.Status.CONFLICT);
}
if (null == jaxbIdea.getTags() || jaxbIdea.getTags().isEmpty()) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Al least one tag is required", Response.Status.CONFLICT);
}
int status = jaxbIdea.getStatus();
if (!ArrayUtils.contains(IIdea.STATES, status)) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Invalid status specified: " + status, Response.Status.CONFLICT);
}
Set<String> tags = this.joinCategories(jaxbIdea, langCode);
Idea idea = jaxbIdea.getIdea();
idea.setTags(new ArrayList<String>(tags));
this.getIdeaManager().updateIdea(idea);
response.setResult(IResponseBuilder.SUCCESS, null);
} catch (ApiException ae) {
response.addErrors(ae.getErrors());
response.setResult(IResponseBuilder.FAILURE, null);
} catch (Throwable t) {
_logger.error("Error on update idea", t);
throw new ApsSystemException("Error on update idea", t);
}
return response;
}
public StringApiResponse deleteIdea(Properties properties) throws ApiException, Throwable {
StringApiResponse response = new StringApiResponse();
try {
String code = properties.getProperty("code");
IIdea idea = this.getIdeaManager().getIdea(code);
if (null == idea) {
throw new ApiException(IApiErrorCodes.API_VALIDATION_ERROR, "Idea with code '" + code + "' does not exist", Response.Status.CONFLICT);
}
this.getIdeaManager().deleteIdea(code);
response.setResult(IResponseBuilder.SUCCESS, null);
} catch (ApiException ae) {
response.addErrors(ae.getErrors());
response.setResult(IResponseBuilder.FAILURE, null);
} catch (Throwable t) {
_logger.error("Error on update idea", t);
throw new ApsSystemException("Error on deleteIdea idea", t);
}
return response;
}
private Set<String> joinCategories(JAXBIdea jaxbIdea, String langCode) throws Throwable {
Set<String> tags = new HashSet<String>();
List<SmallCategory> ideaTags = this.getIdeaTags(false, langCode);
Iterator<String> it = jaxbIdea.getTags().iterator();
while (it.hasNext()) {
String jaxbValue = it.next();
String code = "";
for (int i = 0; i < ideaTags.size(); i++) {
SmallCategory smallCategory = ideaTags.get(i);
if(jaxbValue.equals(smallCategory.getTitle())){
code = smallCategory.getCode();
break;
}
}
Category category = this.getCategoryManager().getCategory(code);
if (null == category) {
String categoryCode = this.getHelper().buildCode(jaxbValue, "tag", 30);
category = new Category();
category.setCode(categoryCode);
List<Lang> langs = this.getLangManager().getLangs();
for (int i = 0; i < langs.size(); i++) {
Lang lang = langs.get(i);
category.setTitle(lang.getCode(), jaxbValue);
}
category.setParentCode(this.getIdeaManager().getCategoryRoot());
this.getCategoryManager().addCategory(category);
tags.add(categoryCode);
} else {
tags.add(code);
}
}
return tags;
}
private List<SmallCategory> getIdeaTags(boolean completeTitle, String langCode) {
List<SmallCategory> categories = new ArrayList<SmallCategory>();
try {
String nodeRootCode = this.getIdeaManager().getCategoryRoot();
categories = this.getCategoryLeaf(nodeRootCode, langCode, completeTitle);
} catch (Throwable t) {
_logger.error("error in getIdeaTags", t);
throw new RuntimeException("Errore in estrazione categorie");
}
return categories;
}
private List<SmallCategory> getCategoryLeaf(String nodeRootCode, String langCode, boolean completeTitle) {
List<SmallCategory> categories = new ArrayList<SmallCategory>();
try {
Category root = (Category) this.getCategoryManager().getCategory(nodeRootCode);
this.addSmallCategory(categories, root, langCode, completeTitle, true);
} catch (Throwable t) {
_logger.error("error in methodName", t);
throw new RuntimeException("Errore in estrazione categorie");
}
return categories;
}
private void addSmallCategory(List<SmallCategory> categories, Category parentCat, String langCode, boolean completeTitle, boolean isFirst) {
for (Category cat : parentCat.getChildren()) {
if (null == cat.getChildren() || cat.getChildren().length == 0) {
SmallCategory catSmall = new SmallCategory();
catSmall.setCode(cat.getCode());
if (!completeTitle) {
catSmall.setTitle(cat.getTitles().getProperty(langCode));
} else {
catSmall.setTitle(cat.getFullTitle(langCode));
}
categories.add(catSmall);
}
this.addSmallCategory(categories, cat, langCode, completeTitle, false);
}
}
protected IIdeaInstanceManager getIdeaInstanceManager() {
return _ideaInstanceManager;
}
public void setIdeaInstanceManager(IIdeaInstanceManager ideaInstanceManager) {
this._ideaInstanceManager = ideaInstanceManager;
}
protected IIdeaManager getIdeaManager() {
return _ideaManager;
}
public void setIdeaManager(IIdeaManager ideaManager) {
this._ideaManager = ideaManager;
}
protected ICategoryManager getCategoryManager() {
return _categoryManager;
}
public void setCategoryManager(ICategoryManager categoryManager) {
this._categoryManager = categoryManager;
}
protected ILangManager getLangManager() {
return _langManager;
}
public void setLangManager(ILangManager langManager) {
this._langManager = langManager;
}
protected ICategoryActionHelper getHelper() {
return _helper;
}
public void setHelper(ICategoryActionHelper helper) {
this._helper = helper;
}
private IIdeaInstanceManager _ideaInstanceManager;
private IIdeaManager _ideaManager;
private ICategoryManager _categoryManager;
private ILangManager _langManager;
private ICategoryActionHelper _helper;
}