Implementing feature

This commit is contained in:
Luca Frosini 2021-05-14 15:34:11 +02:00
parent b31befdc8d
commit 72164da170
2 changed files with 338 additions and 35 deletions

View File

@ -17,6 +17,7 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import org.apache.http.MethodNotSupportedException;
import org.gcube.com.fasterxml.jackson.databind.JsonNode; import org.gcube.com.fasterxml.jackson.databind.JsonNode;
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode; import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode; import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
@ -319,6 +320,24 @@ public class CKANPackage extends CKAN {
return count; return count;
} }
protected CMItemStatus getRequestedCMItemStatus() {
CMItemStatus cmItemStatus = null;
try {
MultivaluedMap<String,String> queryParameters = uriInfo.getQueryParameters();
if(queryParameters.containsKey(GCatConstants.CM_ITEM_STATUS_QUERY_PARAMETER)) {
String cmItemStatusString = queryParameters.getFirst(GCatConstants.CM_ITEM_STATUS_QUERY_PARAMETER);
cmItemStatus = CMItemStatus.getCMItemStatusFromValue(cmItemStatusString);
}
}catch (Exception e) {
cmItemStatus = null;
}
return cmItemStatus;
}
@Override @Override
public String list(int limit, int offset) { public String list(int limit, int offset) {
Map<String,String> parameters = new HashMap<>(); Map<String,String> parameters = new HashMap<>();
@ -349,13 +368,51 @@ public class CKANPackage extends CKAN {
String q = parameters.get(GCatConstants.Q_KEY); String q = parameters.get(GCatConstants.Q_KEY);
StringBuffer stringBuffer = new StringBuffer(); StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("(");
stringBuffer.append(CM_STATUS_QUERY_FILTER_KEY); stringBuffer.append(CM_STATUS_QUERY_FILTER_KEY);
stringBuffer.append(":"); stringBuffer.append(":");
// Default se non viene richiesto esplicitamente lo status o per i ruoli che possono solo vedere approved CMItemStatus cmItemStatus = getRequestedCMItemStatus();
stringBuffer.append(CMItemStatus.APPROVED.getValue());
parameters.put(GCatConstants.Q_KEY, String.format("%s AND %s", q, stringBuffer.toString())); if(!ckanUser.getPortalUser().isCatalogueModerator()) {
switch (ckanUser.getRole()) {
case ADMIN:
break;
case EDITOR:
if(cmItemStatus!=null && cmItemStatus!=CMItemStatus.APPROVED) {
q = String.format("%s AND %s:%s", q, AUTHOR_EMAIL_KEY, ckanUser.getPortalUser().getEMail());
}else{
cmItemStatus = CMItemStatus.APPROVED;
}
break;
case MEMBER:
if(cmItemStatus!=null && cmItemStatus!=CMItemStatus.APPROVED) {
throw new ForbiddenException("You are only authorized to list " + CMItemStatus.APPROVED.getValue() + " items");
}
cmItemStatus = CMItemStatus.APPROVED;
break;
default:
break;
}
}
if(cmItemStatus!=null) {
stringBuffer.append(cmItemStatus.getValue());
if(cmItemStatus == CMItemStatus.APPROVED) {
stringBuffer.append(" OR (*:* -");
stringBuffer.append(CM_STATUS_QUERY_FILTER_KEY);
stringBuffer.append(":[* TO *])");
}
stringBuffer.append(")");
q = String.format("%s AND %s", q, stringBuffer.toString());
parameters.put(GCatConstants.Q_KEY, q);
}
parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true)); parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true));
} }
@ -518,24 +575,24 @@ public class CKANPackage extends CKAN {
protected void sendSocialPost(String title, String catalogueItemURL) { protected void sendSocialPost(String title, String catalogueItemURL) {
try { try {
boolean socialPost = false; boolean makePost = false;
try { try {
MultivaluedMap<String,String> queryParameters = uriInfo.getQueryParameters(); MultivaluedMap<String,String> queryParameters = uriInfo.getQueryParameters();
if(queryParameters.containsKey(GCatConstants.SOCIAL_POST_PARAMETER)) { if(queryParameters.containsKey(GCatConstants.SOCIAL_POST_QUERY_PARAMETER)) {
socialPost = Boolean.parseBoolean(queryParameters.getFirst(GCatConstants.SOCIAL_POST_PARAMETER)); makePost = Boolean.parseBoolean(queryParameters.getFirst(GCatConstants.SOCIAL_POST_QUERY_PARAMETER));
} }
} catch(Exception e) { } catch(Exception e) {
socialPost = false; makePost = false;
} }
if(socialPost) { if(makePost) {
ArrayNode arrayNode = (ArrayNode) result.get(TAGS_KEY); ArrayNode arrayNode = (ArrayNode) result.get(TAGS_KEY);
SocialPost socialService = new SocialPost(); SocialPost socialPost = new SocialPost();
socialService.setItemID(itemID); socialPost.setItemID(itemID);
socialService.setItemURL(catalogueItemURL); socialPost.setItemURL(catalogueItemURL);
socialService.setTags(arrayNode); socialPost.setTags(arrayNode);
socialService.setItemTitle(title); socialPost.setItemTitle(title);
socialService.start(); socialPost.start();
} else { } else {
logger.info("The request explicitly disabled the Social Post."); logger.info("The request explicitly disabled the Social Post.");
} }
@ -553,7 +610,7 @@ public class CKANPackage extends CKAN {
if(result.has(EXTRAS_KEY)) { if(result.has(EXTRAS_KEY)) {
ArrayNode extras = (ArrayNode) result.get(EXTRAS_KEY); ArrayNode extras = (ArrayNode) result.get(EXTRAS_KEY);
for(JsonNode extra : extras) { for(JsonNode extra : extras) {
if(extra.has(EXTRAS_KEY_KEY) && extra.get(EXTRAS_KEY_KEY).asText().compareTo(GCatConstants.CM_ITEM_STATUS) == 0) { if(extra.has(EXTRAS_KEY_KEY) && extra.get(EXTRAS_KEY_KEY).asText().compareTo(GCatConstants.SYSTEM_CM_ITEM_STATUS) == 0) {
cmItemStatusString = extra.get(EXTRAS_VALUE_KEY).asText(); cmItemStatusString = extra.get(EXTRAS_VALUE_KEY).asText();
found = true; found = true;
break; break;
@ -565,13 +622,17 @@ public class CKANPackage extends CKAN {
if(!found) { if(!found) {
// TODO can be used to fix an item published before activating the moderation. // TODO can be used to fix an item published before activating the moderation.
// The item is considered ad approved and the item representation must be updateds // The item is considered ad approved and the item representation must be updated
return cmItemStatus; return cmItemStatus;
} }
return cmItemStatus; return cmItemStatus;
} }
protected boolean isModerationEnabled() {
return ckanInstance.isModerationEnabled();
}
@Override @Override
public String read() { public String read() {
try { try {
@ -579,7 +640,7 @@ public class CKANPackage extends CKAN {
result = mapper.readTree(ret); result = mapper.readTree(ret);
result = cleanResult(result); result = cleanResult(result);
if(ckanInstance.isModerationEnabled()) { if(isModerationEnabled()) {
CMItemStatus cmItemStatus = getCMItemStatus(); CMItemStatus cmItemStatus = getCMItemStatus();
@ -613,25 +674,80 @@ public class CKANPackage extends CKAN {
} }
protected void setToPending(JsonNode jsonNode) {
addExtraField(jsonNode, GCatConstants.SYSTEM_CM_ITEM_STATUS, CMItemStatus.PENDING.getValue());
CMItemVisibility cmItemVisibility = CMItemVisibility.PUBLIC;
if(jsonNode.has(PRIVATE_KEY)) {
boolean privatePackage = jsonNode.get(PRIVATE_KEY).asBoolean();
if(privatePackage) {
cmItemVisibility = CMItemVisibility.RESTRICTED;
}
}
addExtraField(jsonNode, GCatConstants.SYSTEM_CM_ITEM_VISIBILITY, cmItemVisibility.getValue());
((ObjectNode) jsonNode).put(PRIVATE_KEY, true);
((ObjectNode) jsonNode).put(SEARCHABLE_KEY, false);
}
protected void setToApproved(JsonNode jsonNode) {
ArrayNode extras = (ArrayNode) jsonNode.get(EXTRAS_KEY);
boolean approvedSet = false;
CMItemVisibility cmItemVisibility = null;
for(JsonNode extra : extras) {
if(extra.has(EXTRAS_KEY_KEY) && extra.get(EXTRAS_KEY_KEY).asText().compareTo(GCatConstants.SYSTEM_CM_ITEM_STATUS) == 0) {
((ObjectNode) extra).put(EXTRAS_VALUE_KEY, CMItemStatus.APPROVED.getValue());
approvedSet = true;
}
if(extra.has(EXTRAS_KEY_KEY) && extra.get(EXTRAS_KEY_KEY).asText().compareTo(GCatConstants.SYSTEM_CM_ITEM_VISIBILITY) == 0) {
cmItemVisibility = CMItemVisibility.getCMItemStatusFromValue(extra.get(EXTRAS_VALUE_KEY).asText());
}
}
if(!approvedSet) {
addExtraField(jsonNode, GCatConstants.SYSTEM_CM_ITEM_STATUS, CMItemStatus.APPROVED.getValue());
}
if(cmItemVisibility==null) {
cmItemVisibility = CMItemVisibility.PUBLIC;
addExtraField(jsonNode, GCatConstants.SYSTEM_CM_ITEM_VISIBILITY, cmItemVisibility.getValue());
}
((ObjectNode) jsonNode).put(PRIVATE_KEY, cmItemVisibility == CMItemVisibility.RESTRICTED ? true :false);
((ObjectNode) jsonNode).put(SEARCHABLE_KEY, true);
}
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create // see https://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create
@Override @Override
public String create(String json) { public String create(String json) {
try { try {
logger.debug("Going to create Item {}", json); logger.debug("Going to create Item {}", json);
if(ckanInstance.isModerationEnabled()) { if(ckanUser.getRole().ordinal() < Role.EDITOR.ordinal()) {
// TODO StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Only ");
stringBuffer.append(Role.EDITOR.getPortalRole());
stringBuffer.append(" and ");
stringBuffer.append(Role.ADMIN.getPortalRole());
stringBuffer.append(" are entitled to create items. ");
stringBuffer.append("Please contact the VRE Manager to request your grant.");
throw new ForbiddenException(stringBuffer.toString());
} }
JsonNode jsonNode = validateJson(json); JsonNode jsonNode = validateJson(json);
if(ckanInstance.isModerationEnabled()) { if(isModerationEnabled()) {
addExtraField(jsonNode, GCatConstants.CM_ITEM_STATUS, CMItemStatus.APPROVED.getValue()); setToPending(jsonNode);
addExtraField(jsonNode, GCatConstants.CM_ITEM_VISIBILITY, CMItemVisibility.PUBLIC.getValue());
} }
ArrayNode resourcesToBeCreated = mapper.createArrayNode(); ArrayNode resourcesToBeCreated = mapper.createArrayNode();
if(jsonNode.has(RESOURCES_KEY)) { if(jsonNode.has(RESOURCES_KEY)) {
resourcesToBeCreated = (ArrayNode) jsonNode.get(RESOURCES_KEY); resourcesToBeCreated = (ArrayNode) jsonNode.get(RESOURCES_KEY);
@ -671,19 +787,64 @@ public class CKANPackage extends CKAN {
} }
} }
protected JsonNode checkModerationUpdate(JsonNode jsonNode){
PortalUser portalUser = ckanUser.getPortalUser();
if(isModerationEnabled()) {
CMItemStatus cmItemStatus = getCMItemStatus();
boolean setToPending = true;
switch (cmItemStatus) {
case APPROVED:
if(ckanUser.getRole() != Role.ADMIN) {
throw new ForbiddenException("Only " + Role.ADMIN.getPortalRole() + "s are entitled to update an " + cmItemStatus.getValue() + " item");
}
setToPending = false;
break;
case PENDING:
if(result.get(AUTHOR_EMAIL_KEY).asText().compareTo(portalUser.getEMail())==0) {
break;
}
if(portalUser.isCatalogueModerator()) {
break;
}
throw new ForbiddenException("You are not entitled to update a " + cmItemStatus.getValue() + " item");
case REJECTED:
if(result.get(AUTHOR_EMAIL_KEY).asText().compareTo(portalUser.getEMail())==0) {
break;
}
if(ckanUser.getRole() == Role.ADMIN || portalUser.isCatalogueModerator()) {
break;
}
throw new ForbiddenException("You are not entitled to update a " + cmItemStatus.getValue() + " item");
default:
break;
}
if(setToPending) {
setToPending(jsonNode);
}
}
return jsonNode;
}
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update // see https://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update
@Override @Override
public String update(String json) { public String update(String json) {
try { try {
if(ckanInstance.isModerationEnabled()) {
// TODO
}
JsonNode jsonNode = validateJson(json); JsonNode jsonNode = validateJson(json);
read(); read();
this.itemID = result.get(ID_KEY).asText(); this.itemID = result.get(ID_KEY).asText();
jsonNode = checkModerationUpdate(jsonNode);
Map<String,CKANResource> originalResources = new HashMap<>(); Map<String,CKANResource> originalResources = new HashMap<>();
ArrayNode originalResourcesarrayNode = (ArrayNode) result.get(RESOURCES_KEY); ArrayNode originalResourcesarrayNode = (ArrayNode) result.get(RESOURCES_KEY);
if(originalResources != null) { if(originalResources != null) {
@ -748,21 +909,39 @@ public class CKANPackage extends CKAN {
} }
} }
public String approve() {
try {
read();
if(isModerationEnabled()) {
setToApproved(result);
} else {
throw new MethodNotSupportedException("The approve operation is available only in moderation mode");
}
result = cleanResult(result);
return getAsString(result);
}catch(WebApplicationException e) {
throw e;
} catch(Exception e) {
throw new InternalServerErrorException(e);
}
}
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch // see https://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch
@Override @Override
public String patch(String json) { public String patch(String json) {
try { try {
if(ckanInstance.isModerationEnabled()) { read();
// TODO
}
JsonNode jsonNode = checkBaseInformation(json, true); JsonNode jsonNode = checkBaseInformation(json, true);
read();
this.itemID = result.get(ID_KEY).asText(); this.itemID = result.get(ID_KEY).asText();
((ObjectNode)jsonNode).put(ID_KEY, this.itemID); ((ObjectNode)jsonNode).put(ID_KEY, this.itemID);
jsonNode = checkModerationUpdate(jsonNode);
Map<String,CKANResource> originalResources = new HashMap<>(); Map<String,CKANResource> originalResources = new HashMap<>();
ArrayNode originalResourcesarrayNode = (ArrayNode) result.get(RESOURCES_KEY); ArrayNode originalResourcesarrayNode = (ArrayNode) result.get(RESOURCES_KEY);
if(originalResources != null) { if(originalResources != null) {
@ -830,7 +1009,7 @@ public class CKANPackage extends CKAN {
@Override @Override
protected void delete() { protected void delete() {
if(ckanInstance.isModerationEnabled()) { if(isModerationEnabled()) {
// TODO // TODO
} }
super.delete(); super.delete();

View File

@ -1,6 +1,7 @@
package org.gcube.gcat.persistence.ckan; package org.gcube.gcat.persistence.ckan;
import java.io.StringWriter; import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -10,12 +11,16 @@ import java.util.Set;
import javax.ws.rs.ForbiddenException; import javax.ws.rs.ForbiddenException;
import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import org.gcube.common.authorization.client.exceptions.ObjectNotFound; import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
import org.gcube.common.resources.gcore.GenericResource; import org.gcube.common.resources.gcore.GenericResource;
import org.gcube.common.resources.gcore.Resources; import org.gcube.common.resources.gcore.Resources;
import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean;
import org.gcube.gcat.ContextTest; import org.gcube.gcat.ContextTest;
import org.gcube.gcat.api.CMItemStatus;
import org.gcube.gcat.api.GCatConstants; import org.gcube.gcat.api.GCatConstants;
import org.gcube.gcat.utils.ContextUtility; import org.gcube.gcat.utils.ContextUtility;
import org.gcube.informationsystem.publisher.RegistryPublisher; import org.gcube.informationsystem.publisher.RegistryPublisher;
@ -56,11 +61,130 @@ public class CKANPackageTest extends ContextTest {
public void list() throws Exception { public void list() throws Exception {
ContextTest.setContextByName("/gcube/devsec/devVRE"); ContextTest.setContextByName("/gcube/devsec/devVRE");
CKANPackage ckanPackage = new CKANPackage(); CKANPackage ckanPackage = new CKANPackage();
UriInfo uriInfo = new UriInfo() {
@Override
public URI resolve(URI uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public URI relativize(URI uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public UriBuilder getRequestUriBuilder() {
// TODO Auto-generated method stub
return null;
}
@Override
public URI getRequestUri() {
// TODO Auto-generated method stub
return null;
}
@Override
public MultivaluedMap<String, String> getQueryParameters(boolean decode) {
return null;
}
@Override
public MultivaluedMap<String, String> getQueryParameters() {
MultivaluedMap<String, String> mvm = new MultivaluedHashMap<String,String>();
mvm.add(GCatConstants.CM_ITEM_STATUS_QUERY_PARAMETER, CMItemStatus.PENDING.getValue());
return mvm;
}
@Override
public List<PathSegment> getPathSegments(boolean decode) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<PathSegment> getPathSegments() {
// TODO Auto-generated method stub
return null;
}
@Override
public MultivaluedMap<String, String> getPathParameters(boolean decode) {
// TODO Auto-generated method stub
return null;
}
@Override
public MultivaluedMap<String, String> getPathParameters() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getPath(boolean decode) {
// TODO Auto-generated method stub
return null;
}
@Override
public String getPath() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<String> getMatchedURIs(boolean decode) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<String> getMatchedURIs() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Object> getMatchedResources() {
// TODO Auto-generated method stub
return null;
}
@Override
public UriBuilder getBaseUriBuilder() {
// TODO Auto-generated method stub
return null;
}
@Override
public URI getBaseUri() {
// TODO Auto-generated method stub
return null;
}
@Override
public UriBuilder getAbsolutePathBuilder() {
// TODO Auto-generated method stub
return null;
}
@Override
public URI getAbsolutePath() {
// TODO Auto-generated method stub
return null;
}
};
ckanPackage.setUriInfo(uriInfo);
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
String ret = ckanPackage.list(10, 0); String ret = ckanPackage.list(10, 0);
JsonNode gotList = mapper.readTree(ret); JsonNode gotList = mapper.readTree(ret);
Assert.assertTrue(gotList instanceof ArrayNode); Assert.assertTrue(gotList instanceof ArrayNode);
logger.debug("List :\n{}", mapper.writeValueAsString(gotList)); logger.debug("List:\n{}", mapper.writeValueAsString(gotList));
} }
@Test @Test