The moderation thread has been generalised form the implementation

This commit is contained in:
Luca Frosini 2021-11-26 12:27:31 +01:00
parent 06c4e5f539
commit c9b2a3b6f7
4 changed files with 154 additions and 80 deletions

View File

@ -0,0 +1,32 @@
package org.gcube.gcat.moderation.thread;
import org.gcube.gcat.api.CMItemStatus;
import org.gcube.gcat.utils.ContextUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class FakeModerationThread extends ModerationThread {
private static final Logger logger = LoggerFactory.getLogger(FakeModerationThread.class);
@Override
protected void postMessage(CMItemStatus cmItemStatus, String message) throws Exception {
logger.debug("gCat is sending a message to the {} for item '{}' (id={}). ItemStatus={}, Message=\"{}\"",
ModerationThread.class.getSimpleName(), itemName, itemID, cmItemStatus, message);
}
@Override
public void postUserMessage(CMItemStatus cmItemStatus, String userMessage) throws Exception {
logger.debug("{} is sending a message to the {} for item '{}' (id={}). ItemStatus={}, Message=\"{}\"",
ContextUtility.getUsername(), ModerationThread.class.getSimpleName(), itemName, itemID, cmItemStatus, userMessage);
}
@Override
protected void createModerationThread() throws Exception {
logger.debug("Creating {} for item '{}' (id={})", ModerationThread.class.getSimpleName(), itemName, itemID);
}
}

View File

@ -0,0 +1,87 @@
package org.gcube.gcat.moderation.thread;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.gcat.api.CMItemStatus;
import org.gcube.gcat.persistence.ckan.CKANUser;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public abstract class ModerationThread {
protected String itemID;
protected String itemName;
protected CKANUser ckanUser;
protected ObjectMapper objectMapper;
public static ModerationThread getDefaultInstance() {
return new FakeModerationThread();
}
public ModerationThread() {
this.objectMapper = new ObjectMapper();
}
public void setItemCoordinates(String itemID, String itemName) {
this.itemID = itemID;
this.itemName = itemName;
}
public void setCKANUser(CKANUser ckanUser) {
this.ckanUser = ckanUser;
}
/**
* The message is sent as gCat
* @param cmItemStatus
* @param message
* @throws Exception
*/
protected abstract void postMessage(CMItemStatus cmItemStatus, String message) throws Exception;
/**
* The message is sent as User
* @param cmItemStatus
* @param userMessage
* @throws Exception
*/
public abstract void postUserMessage(CMItemStatus cmItemStatus, String userMessage) throws Exception;
protected abstract void createModerationThread() throws Exception ;
public void postItemCreated() throws Exception{
createModerationThread();
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.PENDING;
String message = String.format("@**%s** has created the item with name '%s' (id='%s'). The item is now in **%s** state and must be moderated.",
username, itemName, itemID, cmItemStatus.getFancyValue());
postMessage(cmItemStatus, message);
}
public void postItemUpdated() throws Exception {
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.PENDING;
String message = String.format("@**%s** has updated the item with name '%s' (id='%s'). The item is now in **%s** state and must be moderated.",
username, itemName, itemID, cmItemStatus.getFancyValue());
postMessage(cmItemStatus, message);
}
public void postItemRejected(String userMessage) throws Exception {
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.REJECTED;
String message = String.format("@**%s** has **%s** the item with name '%s' (id='%s'). The author can delete the item or update it to try to meet moderators requests if any.",
username, cmItemStatus.getFancyValue(), itemName, itemID);
postMessage(cmItemStatus, message);
postUserMessage(cmItemStatus, userMessage);
}
public void postItemApproved(String userMessage) throws Exception{
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.APPROVED;
String message = String.format("@**%s** has **%s** the item with name '%s' (id='%s'). The item is now available in the catalogue.",
username, cmItemStatus.getFancyValue(), itemName, itemID);
postMessage(cmItemStatus, message);
postUserMessage(cmItemStatus, userMessage);
}
}

View File

@ -5,13 +5,12 @@ import java.util.Set;
import javax.ws.rs.InternalServerErrorException; import javax.ws.rs.InternalServerErrorException;
import org.gcube.com.fasterxml.jackson.databind.JsonNode; 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; 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;
import org.gcube.gcat.api.CMItemStatus; import org.gcube.gcat.api.CMItemStatus;
import org.gcube.gcat.api.GCatConstants; import org.gcube.gcat.api.GCatConstants;
import org.gcube.gcat.moderation.thread.ModerationThread;
import org.gcube.gcat.moderation.thread.zulip.ZulipResponse.Result; import org.gcube.gcat.moderation.thread.zulip.ZulipResponse.Result;
import org.gcube.gcat.persistence.ckan.CKANUser;
import org.gcube.gcat.social.SocialUsers; import org.gcube.gcat.social.SocialUsers;
import org.gcube.gcat.utils.Constants; import org.gcube.gcat.utils.Constants;
import org.gcube.gcat.utils.ContextUtility; import org.gcube.gcat.utils.ContextUtility;
@ -28,7 +27,7 @@ import io.taliox.zulip.calls.streams.PostCreateStream;
/** /**
* @author Luca Frosini (ISTI - CNR) * @author Luca Frosini (ISTI - CNR)
*/ */
public class ZulipStream { public class ZulipStream extends ModerationThread {
private static final Logger logger = LoggerFactory.getLogger(ZulipStream.class); private static final Logger logger = LoggerFactory.getLogger(ZulipStream.class);
@ -40,25 +39,18 @@ public class ZulipStream {
protected ZulipRestExecutor gCatZulipRestExecutor; protected ZulipRestExecutor gCatZulipRestExecutor;
protected ZulipRestExecutor userZulipRestExecutor; protected ZulipRestExecutor userZulipRestExecutor;
protected String itemID;
protected String itemName;
protected String streamName; protected String streamName;
protected String streamDescription; protected String streamDescription;
protected CKANUser ckanUser; public ZulipStream() {
super();
protected ObjectMapper objectMapper; }
protected ZulipRestExecutor getZulipRestExecutor() { protected ZulipRestExecutor getZulipRestExecutor() {
ZulipAuth zulipAuth = new ZulipAuth(ContextUtility.getUsername()); ZulipAuth zulipAuth = new ZulipAuth(ContextUtility.getUsername());
return new ZulipRestExecutor(zulipAuth.getEmail(), zulipAuth.getAPIKey(), zulipAuth.getSite()); return new ZulipRestExecutor(zulipAuth.getEmail(), zulipAuth.getAPIKey(), zulipAuth.getSite());
} }
public ZulipStream() {
this.objectMapper = new ObjectMapper();
}
public ZulipRestExecutor getGCatZulipRestExecutor() { public ZulipRestExecutor getGCatZulipRestExecutor() {
if(gCatZulipRestExecutor==null) { if(gCatZulipRestExecutor==null) {
ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken()); ApplicationMode applicationMode = new ApplicationMode(Constants.getCatalogueApplicationToken());
@ -76,15 +68,6 @@ public class ZulipStream {
return userZulipRestExecutor; return userZulipRestExecutor;
} }
public void setItemCoordinates(String itemID, String itemName) {
this.itemID = itemID;
this.itemName = itemName;
}
public void setCKANUser(CKANUser ckanUser) {
this.ckanUser = ckanUser;
}
protected String getStreamName() { protected String getStreamName() {
if(streamName==null) { if(streamName==null) {
streamName = String.format("Item '%s' moderation", itemID); streamName = String.format("Item '%s' moderation", itemID);
@ -117,7 +100,8 @@ public class ZulipStream {
return zulipResponse; return zulipResponse;
} }
public void create() throws Exception { @Override
protected void createModerationThread() throws Exception {
ArrayNode streamsArrayNode = objectMapper.createArrayNode(); ArrayNode streamsArrayNode = objectMapper.createArrayNode();
ObjectNode streamobjectNode = objectMapper.createObjectNode(); ObjectNode streamobjectNode = objectMapper.createObjectNode();
streamobjectNode.put("name", getStreamName()); streamobjectNode.put("name", getStreamName());
@ -145,8 +129,6 @@ public class ZulipStream {
postCreateStream.setAnnounce(false); postCreateStream.setAnnounce(false);
executeZulipCall(gCatZulipRestExecutor, postCreateStream); executeZulipCall(gCatZulipRestExecutor, postCreateStream);
postItemCreated();
} }
protected void postMessageToStream(ZulipRestExecutor zulipRestExecutor, CMItemStatus cmItemStatus, String message) throws Exception { protected void postMessageToStream(ZulipRestExecutor zulipRestExecutor, CMItemStatus cmItemStatus, String message) throws Exception {
@ -155,42 +137,14 @@ public class ZulipStream {
executeZulipCall(zulipRestExecutor, postMessage); executeZulipCall(zulipRestExecutor, postMessage);
} }
public void postUserMessageToStream(CMItemStatus cmItemStatus, String message) throws Exception { @Override
protected void postMessage(CMItemStatus cmItemStatus, String message) throws Exception {
postMessageToStream(getGCatZulipRestExecutor(), cmItemStatus, message);
}
@Override
public void postUserMessage(CMItemStatus cmItemStatus, String message) throws Exception {
postMessageToStream(getUserZulipRestExecutor(), cmItemStatus, message); postMessageToStream(getUserZulipRestExecutor(), cmItemStatus, message);
} }
private void postItemCreated() throws Exception{
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.PENDING;
String message = String.format("@**%s** has created the item with name '%s' (id='%s'). The item is now in **%s** state and must be moderated.",
username, itemName, itemID, cmItemStatus.getFancyValue());
postMessageToStream(getGCatZulipRestExecutor(), cmItemStatus, message);
}
public void postItemUpdated() throws Exception{
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.PENDING;
String message = String.format("@**%s** has updated the item with name '%s' (id='%s'). The item is now in **%s** state and must be moderated.",
username, itemName, itemID, cmItemStatus.getFancyValue());
postMessageToStream(getGCatZulipRestExecutor(), cmItemStatus, message);
}
public void postItemRejected(String userMessage) throws Exception {
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.REJECTED;
String message = String.format("@**%s** has **%s** the item with name '%s' (id='%s'). The author can delete the item or update it to try to meet moderators requests if any.",
username, cmItemStatus.getFancyValue(), itemName, itemID);
postMessageToStream(getGCatZulipRestExecutor(), cmItemStatus, message);
postUserMessageToStream(cmItemStatus, userMessage);
}
public void postItemApproved(String userMessage) throws Exception{
String username = ckanUser.getPortalUser().getNameSurname();
CMItemStatus cmItemStatus = CMItemStatus.APPROVED;
String message = String.format("@**%s** has **%s** the item with name '%s' (id='%s'). The item is now available in the catalogue.",
username, cmItemStatus.getFancyValue(), itemName, itemID);
postMessageToStream(getGCatZulipRestExecutor(), cmItemStatus, message);
postUserMessageToStream(cmItemStatus, userMessage);
}
} }

View File

@ -29,7 +29,7 @@ import org.gcube.gcat.api.CMItemVisibility;
import org.gcube.gcat.api.GCatConstants; import org.gcube.gcat.api.GCatConstants;
import org.gcube.gcat.api.Role; import org.gcube.gcat.api.Role;
import org.gcube.gcat.api.interfaces.Moderated; import org.gcube.gcat.api.interfaces.Moderated;
import org.gcube.gcat.moderation.thread.zulip.ZulipStream; import org.gcube.gcat.moderation.thread.ModerationThread;
import org.gcube.gcat.oldutils.Validator; import org.gcube.gcat.oldutils.Validator;
import org.gcube.gcat.profile.MetadataUtility; import org.gcube.gcat.profile.MetadataUtility;
import org.gcube.gcat.social.PortalUser; import org.gcube.gcat.social.PortalUser;
@ -44,6 +44,7 @@ import org.slf4j.LoggerFactory;
public class CKANPackage extends CKAN implements Moderated { public class CKANPackage extends CKAN implements Moderated {
private static final Logger logger = LoggerFactory.getLogger(CKANPackage.class); private static final Logger logger = LoggerFactory.getLogger(CKANPackage.class);
/* /*
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list // see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_list
public static final String ITEM_LIST = CKAN.CKAN_API_PATH + "package_list"; public static final String ITEM_LIST = CKAN.CKAN_API_PATH + "package_list";
@ -122,7 +123,7 @@ public class CKANPackage extends CKAN implements Moderated {
protected final CKANInstance ckanInstance; protected final CKANInstance ckanInstance;
protected final Set<String> supportedOrganizations; protected final Set<String> supportedOrganizations;
protected ZulipStream zulipStream; protected ModerationThread moderationThread;
public CKANPackage() { public CKANPackage() {
super(); super();
@ -642,7 +643,7 @@ public class CKANPackage extends CKAN implements Moderated {
ArrayNode created = createResources(resourcesToBeCreated); ArrayNode created = createResources(resourcesToBeCreated);
((ObjectNode) result).replace(RESOURCES_KEY, created); ((ObjectNode) result).replace(RESOURCES_KEY, created);
createZulipStream(); postItemCreated();
if(!isModerationEnabled()) { if(!isModerationEnabled()) {
if(ckanInstance.getCurrentScopeBean().is(Type.VRE)) { if(ckanInstance.getCurrentScopeBean().is(Type.VRE)) {
@ -718,7 +719,7 @@ public class CKANPackage extends CKAN implements Moderated {
ckanResource.deleteFile(); ckanResource.deleteFile();
} }
postItemUpdatedToStream(); postItemUpdated();
return getAsCleanedString(result); return getAsCleanedString(result);
} catch(WebApplicationException e) { } catch(WebApplicationException e) {
@ -787,7 +788,7 @@ public class CKANPackage extends CKAN implements Moderated {
ckanResource.deleteFile(); ckanResource.deleteFile();
} }
postItemUpdatedToStream(); postItemUpdated();
return getAsCleanedString(result); return getAsCleanedString(result);
} catch(WebApplicationException e) { } catch(WebApplicationException e) {
@ -906,9 +907,9 @@ public class CKANPackage extends CKAN implements Moderated {
protected boolean isModerationEnabled() { protected boolean isModerationEnabled() {
boolean moderationEnabled = ckanInstance.isModerationEnabled(); boolean moderationEnabled = ckanInstance.isModerationEnabled();
if(moderationEnabled && zulipStream==null) { if(moderationEnabled && moderationThread==null) {
zulipStream = new ZulipStream(); moderationThread = ModerationThread.getDefaultInstance();
zulipStream.setCKANUser(ckanUser); moderationThread.setCKANUser(ckanUser);
} }
return moderationEnabled; return moderationEnabled;
} }
@ -1146,11 +1147,11 @@ public class CKANPackage extends CKAN implements Moderated {
((ObjectNode) jsonNode).put(SEARCHABLE_KEY, true); ((ObjectNode) jsonNode).put(SEARCHABLE_KEY, true);
} }
private void createZulipStream() throws Exception { private void postItemCreated() throws Exception {
try { try {
if(isModerationEnabled()) { if(isModerationEnabled()) {
zulipStream.setItemCoordinates(itemID, name); moderationThread.setItemCoordinates(itemID, name);
zulipStream.create(); moderationThread.postItemCreated();
} }
} catch(WebApplicationException e) { } catch(WebApplicationException e) {
throw e; throw e;
@ -1159,11 +1160,11 @@ public class CKANPackage extends CKAN implements Moderated {
} }
} }
private void postItemUpdatedToStream() { private void postItemUpdated() {
try { try {
if(isModerationEnabled()) { if(isModerationEnabled()) {
zulipStream.setItemCoordinates(itemID, name); moderationThread.setItemCoordinates(itemID, name);
zulipStream.postItemUpdated(); moderationThread.postItemUpdated();
} }
} catch(WebApplicationException e) { } catch(WebApplicationException e) {
throw e; throw e;
@ -1195,8 +1196,8 @@ public class CKANPackage extends CKAN implements Moderated {
String ret = sendPostRequest(ITEM_PATCH, getAsString(result)); String ret = sendPostRequest(ITEM_PATCH, getAsString(result));
result = mapper.readTree(ret); result = mapper.readTree(ret);
zulipStream.setItemCoordinates(itemID, name); moderationThread.setItemCoordinates(itemID, name);
zulipStream.postItemApproved(moderatorMessage); moderationThread.postItemApproved(moderatorMessage);
if(ckanInstance.getCurrentScopeBean().is(Type.VRE)) { if(ckanInstance.getCurrentScopeBean().is(Type.VRE)) {
// Actions performed after a package has been correctly created on ckan. // Actions performed after a package has been correctly created on ckan.
@ -1244,8 +1245,8 @@ public class CKANPackage extends CKAN implements Moderated {
String ret = sendPostRequest(ITEM_PATCH, getAsString(result)); String ret = sendPostRequest(ITEM_PATCH, getAsString(result));
result = mapper.readTree(ret); result = mapper.readTree(ret);
zulipStream.setItemCoordinates(itemID, name); moderationThread.setItemCoordinates(itemID, name);
zulipStream.postItemRejected(moderatorMessage); moderationThread.postItemRejected(moderatorMessage);
break; break;
default: default:
@ -1283,8 +1284,8 @@ public class CKANPackage extends CKAN implements Moderated {
} }
CMItemStatus cmItemStatus = getCMItemStatus(); CMItemStatus cmItemStatus = getCMItemStatus();
zulipStream.setItemCoordinates(itemID, name); moderationThread.setItemCoordinates(itemID, name);
zulipStream.postUserMessageToStream(cmItemStatus, message); moderationThread.postUserMessage(cmItemStatus, message);
return; return;
} }
throw new MethodNotSupportedException("The message operation is available only in moderation mode"); throw new MethodNotSupportedException("The message operation is available only in moderation mode");