Implementing content moderation
This commit is contained in:
parent
e00b2010d1
commit
b31befdc8d
|
@ -255,7 +255,8 @@ public class CKANInstance {
|
|||
}
|
||||
|
||||
public boolean isModerationEnabled() {
|
||||
return moderationEnabled;
|
||||
return true;
|
||||
// return moderationEnabled;
|
||||
}
|
||||
|
||||
public String getSysAdminToken() throws Exception {
|
||||
|
|
|
@ -22,9 +22,13 @@ import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
|
|||
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.gcube.common.scope.impl.ScopeBean;
|
||||
import org.gcube.common.scope.impl.ScopeBean.Type;
|
||||
import org.gcube.gcat.api.CMItemStatus;
|
||||
import org.gcube.gcat.api.CMItemVisibility;
|
||||
import org.gcube.gcat.api.GCatConstants;
|
||||
import org.gcube.gcat.api.Role;
|
||||
import org.gcube.gcat.oldutils.Validator;
|
||||
import org.gcube.gcat.profile.MetadataUtility;
|
||||
import org.gcube.gcat.social.PortalUser;
|
||||
import org.gcube.gcat.social.SocialPost;
|
||||
import org.gcube.gcat.utils.URIResolver;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -55,6 +59,7 @@ public class CKANPackage extends CKAN {
|
|||
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.dataset_purge
|
||||
public static final String ITEM_PURGE = CKAN.CKAN_API_PATH + "dataset_purge";
|
||||
|
||||
|
||||
// limit in https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search
|
||||
protected static final String ROWS_KEY = "rows";
|
||||
// offset in https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search
|
||||
|
@ -96,7 +101,10 @@ public class CKANPackage extends CKAN {
|
|||
protected static final String SEARCHABLE_KEY = "searchable";
|
||||
protected static final String CAPACITY_KEY = "capacity";
|
||||
|
||||
// protected static final String INCLUDE_PRIVATE_KEY = "include_private";
|
||||
|
||||
protected static final String CM_STATUS_QUERY_FILTER_KEY = "extras_systemcm_item_status";
|
||||
|
||||
protected static final String INCLUDE_PRIVATE_KEY = "include_private";
|
||||
// protected static final String INCLUDE_DRAFTS_KEY = "include_drafts";
|
||||
|
||||
public static final String GROUPS_KEY = "groups";
|
||||
|
@ -338,9 +346,19 @@ public class CKANPackage extends CKAN {
|
|||
}
|
||||
|
||||
if(ckanInstance.isModerationEnabled()) {
|
||||
// TODO
|
||||
}
|
||||
String q = parameters.get(GCatConstants.Q_KEY);
|
||||
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append(CM_STATUS_QUERY_FILTER_KEY);
|
||||
stringBuffer.append(":");
|
||||
|
||||
// Default se non viene richiesto esplicitamente lo status o per i ruoli che possono solo vedere approved
|
||||
stringBuffer.append(CMItemStatus.APPROVED.getValue());
|
||||
|
||||
parameters.put(GCatConstants.Q_KEY, String.format("%s AND %s", q, stringBuffer.toString()));
|
||||
|
||||
parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true));
|
||||
}
|
||||
|
||||
return list(parameters);
|
||||
}
|
||||
|
@ -477,7 +495,7 @@ public class CKANPackage extends CKAN {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
extras = mapper.createArrayNode();
|
||||
extras = ((ObjectNode) jsonNode).putArray(EXTRAS_KEY);
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
|
@ -528,17 +546,65 @@ public class CKANPackage extends CKAN {
|
|||
}
|
||||
}
|
||||
|
||||
protected CMItemStatus getCMItemStatus() {
|
||||
|
||||
String cmItemStatusString = CMItemStatus.APPROVED.getValue();
|
||||
boolean found = false;
|
||||
if(result.has(EXTRAS_KEY)) {
|
||||
ArrayNode extras = (ArrayNode) result.get(EXTRAS_KEY);
|
||||
for(JsonNode extra : extras) {
|
||||
if(extra.has(EXTRAS_KEY_KEY) && extra.get(EXTRAS_KEY_KEY).asText().compareTo(GCatConstants.CM_ITEM_STATUS) == 0) {
|
||||
cmItemStatusString = extra.get(EXTRAS_VALUE_KEY).asText();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMItemStatus cmItemStatus = CMItemStatus.getCMItemStatusFromValue(cmItemStatusString);
|
||||
|
||||
if(!found) {
|
||||
// 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
|
||||
return cmItemStatus;
|
||||
}
|
||||
|
||||
return cmItemStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String read() {
|
||||
try {
|
||||
if(ckanInstance.isModerationEnabled()) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
String ret = super.read();
|
||||
result = mapper.readTree(ret);
|
||||
result = cleanResult(result);
|
||||
|
||||
if(ckanInstance.isModerationEnabled()) {
|
||||
|
||||
CMItemStatus cmItemStatus = getCMItemStatus();
|
||||
|
||||
if(cmItemStatus == CMItemStatus.APPROVED) {
|
||||
return getAsString(result);
|
||||
}
|
||||
|
||||
PortalUser portalUser = ckanUser.getPortalUser();
|
||||
|
||||
if(result.get(AUTHOR_EMAIL_KEY).asText().compareTo(portalUser.getEMail())==0) {
|
||||
// The author is entitled to read its own items independently from the status
|
||||
return getAsString(result);
|
||||
}
|
||||
|
||||
if(ckanUser.getRole() == Role.ADMIN || portalUser.isCatalogueModerator()) {
|
||||
// Catalogue-Admin and Catalogue-Moderator are entitled to read items with any statues
|
||||
return getAsString(result);
|
||||
}
|
||||
|
||||
throw new ForbiddenException("You are not entitled to read a " + cmItemStatus.getValue() + " item");
|
||||
|
||||
}
|
||||
|
||||
return getAsString(result);
|
||||
|
||||
} catch(WebApplicationException e) {
|
||||
throw e;
|
||||
} catch(Exception e) {
|
||||
|
@ -555,11 +621,17 @@ public class CKANPackage extends CKAN {
|
|||
|
||||
if(ckanInstance.isModerationEnabled()) {
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
|
||||
JsonNode jsonNode = validateJson(json);
|
||||
|
||||
if(ckanInstance.isModerationEnabled()) {
|
||||
addExtraField(jsonNode, GCatConstants.CM_ITEM_STATUS, CMItemStatus.APPROVED.getValue());
|
||||
addExtraField(jsonNode, GCatConstants.CM_ITEM_VISIBILITY, CMItemVisibility.PUBLIC.getValue());
|
||||
}
|
||||
|
||||
|
||||
ArrayNode resourcesToBeCreated = mapper.createArrayNode();
|
||||
if(jsonNode.has(RESOURCES_KEY)) {
|
||||
resourcesToBeCreated = (ArrayNode) jsonNode.get(RESOURCES_KEY);
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package org.gcube.gcat.persistence.ckan;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.InternalServerErrorException;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.gcube.gcat.api.Role;
|
||||
import org.gcube.gcat.social.PortalUser;
|
||||
import org.gcube.gcat.utils.ContextUtility;
|
||||
import org.gcube.gcat.utils.RandomString;
|
||||
|
@ -46,60 +45,6 @@ public class CKANUser extends CKAN {
|
|||
|
||||
private static final String API_KEY = "apikey";
|
||||
|
||||
public enum Role {
|
||||
MEMBER("Catalogue-Member", "member"), EDITOR("Catalogue-Editor", "editor"), ADMIN("Catalogue-Admin", "admin");
|
||||
|
||||
private final String portalRole;
|
||||
private final String ckanRole;
|
||||
|
||||
Role(String portalRole, String ckanRole) {
|
||||
this.portalRole = portalRole;
|
||||
this.ckanRole = ckanRole;
|
||||
}
|
||||
|
||||
public String getPortalRole() {
|
||||
return portalRole;
|
||||
}
|
||||
|
||||
public String getCkanRole() {
|
||||
return ckanRole;
|
||||
}
|
||||
|
||||
protected static final Map<String,Role> ROLE_BY_PORTAL_ROLE;
|
||||
protected static final Map<String,Role> ROLE_BY_CKAN_ROLE;
|
||||
|
||||
static {
|
||||
ROLE_BY_PORTAL_ROLE = new HashMap<String,Role>();
|
||||
|
||||
// null or empty string identify a member
|
||||
ROLE_BY_PORTAL_ROLE.put(null, MEMBER);
|
||||
ROLE_BY_PORTAL_ROLE.put("", MEMBER);
|
||||
|
||||
ROLE_BY_CKAN_ROLE = new HashMap<String,Role>();
|
||||
|
||||
for(Role role : Role.values()) {
|
||||
ROLE_BY_PORTAL_ROLE.put(role.getPortalRole(), role);
|
||||
ROLE_BY_CKAN_ROLE.put(role.getCkanRole(), role);
|
||||
}
|
||||
}
|
||||
|
||||
public static Role getRoleFromPortalRole(String portalRole) {
|
||||
return ROLE_BY_PORTAL_ROLE.get(portalRole);
|
||||
}
|
||||
|
||||
public static String getCkanRoleFromPortalRole(String portalRole) {
|
||||
return getRoleFromPortalRole(portalRole).getCkanRole();
|
||||
}
|
||||
|
||||
public static Role getRoleFromCkanRole(String ckanRole) {
|
||||
return ROLE_BY_CKAN_ROLE.get(ckanRole);
|
||||
}
|
||||
|
||||
public static String getPortalRoleFromCkanRole(String ckanRole) {
|
||||
return getRoleFromCkanRole(ckanRole).getPortalRole();
|
||||
}
|
||||
}
|
||||
|
||||
protected PortalUser portalUser;
|
||||
protected Role role;
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ import org.gcube.common.resources.gcore.GenericResource;
|
|||
import org.gcube.common.resources.gcore.Resources;
|
||||
import org.gcube.datacatalogue.metadatadiscovery.reader.MetadataFormatDiscovery;
|
||||
import org.gcube.datacatalogue.metadatadiscovery.reader.QueryForResourceUtil;
|
||||
import org.gcube.gcat.api.Role;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUser;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUser.Role;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUserCache;
|
||||
import org.gcube.gcat.utils.Constants;
|
||||
import org.gcube.informationsystem.publisher.RegistryPublisher;
|
||||
|
|
|
@ -19,8 +19,8 @@ import org.gcube.common.resources.gcore.GenericResource;
|
|||
import org.gcube.common.resources.gcore.Resources;
|
||||
import org.gcube.datacatalogue.metadatadiscovery.reader.MetadataFormatDiscovery;
|
||||
import org.gcube.datacatalogue.metadatadiscovery.reader.QueryForResourceUtil;
|
||||
import org.gcube.gcat.api.Role;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUser;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUser.Role;
|
||||
import org.gcube.gcat.persistence.ckan.CKANUserCache;
|
||||
import org.gcube.gcat.utils.Constants;
|
||||
import org.gcube.informationsystem.publisher.RegistryPublisher;
|
||||
|
|
|
@ -8,12 +8,16 @@ import java.util.List;
|
|||
import javax.ws.rs.InternalServerErrorException;
|
||||
|
||||
import org.gcube.common.gxhttp.request.GXHTTPStringRequest;
|
||||
import org.gcube.gcat.api.GCatConstants;
|
||||
import org.gcube.gcat.utils.HTTPUtility;
|
||||
|
||||
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
|
||||
/**
|
||||
* @author Luca Frosini (ISTI - CNR)
|
||||
*/
|
||||
public class PortalUser {
|
||||
|
||||
protected static final String RESPONSE_SUCCESS_KEY = "success";
|
||||
|
@ -42,6 +46,8 @@ public class PortalUser {
|
|||
|
||||
protected List<String> roles;
|
||||
|
||||
protected Boolean catalogueModerator;
|
||||
|
||||
public PortalUser() {
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
@ -120,6 +126,14 @@ public class PortalUser {
|
|||
return roles;
|
||||
}
|
||||
|
||||
|
||||
public boolean isCatalogueModerator() {
|
||||
if(catalogueModerator == null) {
|
||||
catalogueModerator = getRoles().contains(GCatConstants.CATALOGUE_MODERATOR);
|
||||
}
|
||||
return catalogueModerator;
|
||||
}
|
||||
|
||||
public String getJobTitle() {
|
||||
if(jobTitle == null) {
|
||||
jobTitle = getOAuthUserProfile().get(OAUTH_USER_PROFILE_JOB_TITLE_KEY).asText();
|
||||
|
|
|
@ -54,6 +54,7 @@ public class CKANPackageTest extends ContextTest {
|
|||
|
||||
@Test
|
||||
public void list() throws Exception {
|
||||
ContextTest.setContextByName("/gcube/devsec/devVRE");
|
||||
CKANPackage ckanPackage = new CKANPackage();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String ret = ckanPackage.list(10, 0);
|
||||
|
@ -242,7 +243,8 @@ public class CKANPackageTest extends ContextTest {
|
|||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.0.pdf
|
||||
* https://data1-d.d4science.org/shub/E_aThRa1NpWFJpTGEydEU2bEJhMXNjZy8wK3BxekJKYnpYTy81cUkwZVdicEZ0aGFRZmY4MkRnUC8xWW0zYzVoVg==
|
||||
* https://goo.gl/J8AwQW
|
||||
*
|
||||
* ContextTest.setContextByName("/gcube/devsec/devVRE");
|
||||
|
||||
*
|
||||
* Workspace(luca.frosini) > RESTful Transaction Model v 1.1.pdf
|
||||
* https://data1-d.d4science.org/shub/E_NkhrbVV4VTluT0RKVUtCRldobFZTQU5ySTZneFdpUzJ2UjJBNlZWNDlURDVHamo4WjY5RnlrcHZGTGNkT2prUg==
|
||||
|
@ -330,7 +332,6 @@ public class CKANPackageTest extends ContextTest {
|
|||
|
||||
@Test
|
||||
public void create() throws Exception {
|
||||
ContextTest.setContextByName("/gcube/devsec/devVRE");
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
createPackage(mapper);
|
||||
}
|
||||
|
@ -346,8 +347,6 @@ public class CKANPackageTest extends ContextTest {
|
|||
|
||||
@Test
|
||||
public void createReadUpdateUpdatePurge() throws Exception {
|
||||
ContextTest.setContextByName("/gcube/devsec/devVRE");
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
createPackage(mapper);
|
||||
|
||||
|
@ -420,7 +419,6 @@ public class CKANPackageTest extends ContextTest {
|
|||
@Test
|
||||
//(expected = NotFoundException.class)
|
||||
public void delete() throws Exception {
|
||||
ContextTest.setContextByName("/gcube/devNext/NextNext");
|
||||
CKANPackage ckanPackage = new CKANPackage();
|
||||
ckanPackage.setName(ITEM_NAME_VALUE);
|
||||
ckanPackage.delete(true);
|
||||
|
|
Loading…
Reference in New Issue