2018-12-04 12:06:22 +01:00
package org.gcube.gcat.persistence.ckan ;
2020-06-22 19:39:29 +02:00
import java.io.StringWriter ;
2018-12-04 12:06:22 +01:00
import java.util.ArrayList ;
import java.util.HashMap ;
2020-06-22 15:39:37 +02:00
import java.util.HashSet ;
2018-12-04 12:06:22 +01:00
import java.util.List ;
import java.util.Map ;
2020-06-22 15:39:37 +02:00
import java.util.Set ;
2021-12-03 17:41:38 +01:00
import java.util.concurrent.TimeUnit ;
2019-10-01 18:00:40 +02:00
import java.util.regex.Matcher ;
import java.util.regex.Pattern ;
2018-12-04 12:06:22 +01:00
import javax.ws.rs.BadRequestException ;
2020-06-22 15:39:37 +02:00
import javax.ws.rs.ForbiddenException ;
2018-12-04 12:06:22 +01:00
import javax.ws.rs.InternalServerErrorException ;
2021-11-18 17:49:24 +01:00
import javax.ws.rs.NotAllowedException ;
2018-12-04 12:06:22 +01:00
import javax.ws.rs.WebApplicationException ;
2019-05-20 17:23:49 +02:00
import javax.ws.rs.core.MultivaluedMap ;
2018-12-04 12:06:22 +01:00
2021-05-14 15:34:11 +02:00
import org.apache.http.MethodNotSupportedException ;
2021-05-10 17:05:05 +02:00
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.ObjectNode ;
2018-12-04 12:06:22 +01:00
import org.gcube.common.scope.impl.ScopeBean.Type ;
2019-05-20 17:23:49 +02:00
import org.gcube.gcat.api.GCatConstants ;
2022-02-15 09:59:02 +01:00
import org.gcube.gcat.api.configuration.CatalogueConfiguration ;
2021-12-02 11:50:18 +01:00
import org.gcube.gcat.api.moderation.CMItemStatus ;
import org.gcube.gcat.api.moderation.CMItemVisibility ;
import org.gcube.gcat.api.moderation.Moderated ;
import org.gcube.gcat.api.moderation.ModerationContent ;
import org.gcube.gcat.api.roles.Role ;
2022-02-16 22:34:30 +01:00
import org.gcube.gcat.configuration.CatalogueConfigurationFactory ;
2021-11-26 12:27:31 +01:00
import org.gcube.gcat.moderation.thread.ModerationThread ;
2018-12-04 12:06:22 +01:00
import org.gcube.gcat.oldutils.Validator ;
2019-01-10 12:29:47 +01:00
import org.gcube.gcat.profile.MetadataUtility ;
2019-09-12 14:26:24 +02:00
import org.gcube.gcat.social.SocialPost ;
2018-12-04 12:06:22 +01:00
import org.gcube.gcat.utils.URIResolver ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
/ * *
* @author Luca Frosini ( ISTI - CNR )
* /
2021-11-19 16:49:43 +01:00
public class CKANPackage extends CKAN implements Moderated {
2018-12-04 12:06:22 +01:00
private static final Logger logger = LoggerFactory . getLogger ( CKANPackage . class ) ;
2021-11-26 12:27:31 +01:00
2019-02-08 12:25:19 +01:00
/ *
2018-12-04 12:06:22 +01:00
// 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 " ;
2019-02-08 12:25:19 +01:00
* /
// see https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search
public static final String ITEM_LIST = CKAN . CKAN_API_PATH + " package_search " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create
2018-12-04 12:06:22 +01:00
public static final String ITEM_CREATE = CKAN . CKAN_API_PATH + " package_create " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.get.package_show
2018-12-04 12:06:22 +01:00
public static final String ITEM_SHOW = CKAN . CKAN_API_PATH + " package_show " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update
2018-12-04 12:06:22 +01:00
public static final String ITEM_UPDATE = CKAN . CKAN_API_PATH + " package_update " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch
2018-12-04 12:06:22 +01:00
public static final String ITEM_PATCH = CKAN . CKAN_API_PATH + " package_patch " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.package_delete
2018-12-04 12:06:22 +01:00
public static final String ITEM_DELETE = CKAN . CKAN_API_PATH + " package_delete " ;
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.delete.dataset_purge
2018-12-04 12:06:22 +01:00
public static final String ITEM_PURGE = CKAN . CKAN_API_PATH + " dataset_purge " ;
2021-05-11 16:05:39 +02:00
2019-02-08 12:25:19 +01:00
// limit in https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search
2022-05-24 17:35:48 +02:00
public static final String ROWS_KEY = " rows " ;
2019-02-08 12:25:19 +01:00
// offset in https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search
2022-05-24 17:35:48 +02:00
public static final String START_KEY = " start " ;
2019-02-08 12:25:19 +01:00
2019-10-01 18:00:40 +02:00
protected static final String ORGANIZATION_FILTER_TEMPLATE = GCatConstants . ORGANIZATION_PARAMETER + " :%s " ;
2021-12-03 17:41:38 +01:00
protected static final String ORGANIZATION_REGEX = GCatConstants . ORGANIZATION_PARAMETER + " :[a-zA-Z0-9_ \\ - \" ]* " ;
2019-10-01 18:00:40 +02:00
protected static final Pattern ORGANIZATION_REGEX_PATTERN ;
static {
ORGANIZATION_REGEX_PATTERN = Pattern . compile ( ORGANIZATION_REGEX ) ;
}
2019-02-08 12:25:19 +01:00
2018-12-04 12:06:22 +01:00
protected static final String LICENSE_KEY = " license_id " ;
2019-02-26 14:58:06 +01:00
protected static final String EXTRAS_ITEM_URL_KEY = " Item URL " ;
2018-12-04 12:06:22 +01:00
protected static final String AUTHOR_KEY = " author " ;
protected static final String AUTHOR_EMAIL_KEY = " author_email " ;
2021-04-16 16:14:13 +02:00
protected static final String MAINTAINER_KEY = " maintainer " ;
protected static final String MAINTAINER_EMAIL_KEY = " maintainer_email " ;
2018-12-04 12:06:22 +01:00
protected static final String OWNER_ORG_KEY = " owner_org " ;
protected static final String RESOURCES_KEY = " resources " ;
protected static final String TITLE_KEY = " title " ;
2019-02-08 12:04:20 +01:00
public static final String EXTRAS_KEY = " extras " ;
public static final String EXTRAS_KEY_KEY = " key " ;
public static final String EXTRAS_KEY_VALUE_SYSTEM_TYPE = " system:type " ;
public static final String EXTRAS_VALUE_KEY = " value " ;
2019-02-08 14:40:57 +01:00
// The 'results' array is included in the 'result' object for package_search
private static final String RESULTS_KEY = " results " ;
2019-02-08 16:49:30 +01:00
protected static final String PRIVATE_KEY = " private " ;
2019-02-08 14:40:57 +01:00
protected static final String SEARCHABLE_KEY = " searchable " ;
2019-05-20 17:23:49 +02:00
protected static final String CAPACITY_KEY = " capacity " ;
2019-02-08 16:49:30 +01:00
2021-05-11 16:05:39 +02:00
protected static final String CM_STATUS_QUERY_FILTER_KEY = " extras_systemcm_item_status " ;
protected static final String INCLUDE_PRIVATE_KEY = " include_private " ;
2019-02-08 14:40:57 +01:00
// protected static final String INCLUDE_DRAFTS_KEY = "include_drafts";
2018-12-04 12:06:22 +01:00
public static final String GROUPS_KEY = " groups " ;
public static final String TAGS_KEY = " tags " ;
2019-09-16 14:48:18 +02:00
2018-12-04 12:06:22 +01:00
protected final List < CKANResource > managedResources ;
protected String itemID ;
2022-04-06 17:15:46 +02:00
protected String itemTitle ;
2022-03-31 15:49:22 +02:00
protected String itemURL ;
2018-12-04 12:06:22 +01:00
2021-05-10 16:16:18 +02:00
protected final CKANUser ckanUser ;
2020-06-22 15:39:37 +02:00
2022-02-15 09:59:02 +01:00
protected final CatalogueConfiguration configuration ;
2020-06-22 15:39:37 +02:00
2021-11-26 12:27:31 +01:00
protected ModerationThread moderationThread ;
2021-11-17 17:47:58 +01:00
2018-12-04 12:06:22 +01:00
public CKANPackage ( ) {
super ( ) ;
2021-05-10 17:05:05 +02:00
2018-12-04 12:06:22 +01:00
LIST = ITEM_LIST ;
CREATE = ITEM_CREATE ;
READ = ITEM_SHOW ;
UPDATE = ITEM_UPDATE ;
PATCH = ITEM_PATCH ;
DELETE = ITEM_DELETE ;
PURGE = ITEM_PURGE ;
managedResources = new ArrayList < CKANResource > ( ) ;
2021-05-10 17:05:05 +02:00
2022-02-15 09:59:02 +01:00
configuration = CatalogueConfigurationFactory . getInstance ( ) ;
2020-06-22 15:39:37 +02:00
2022-04-21 17:12:41 +02:00
ckanUser = CKANUserCache . getCurrrentCKANUser ( ) ;
2018-12-04 12:06:22 +01:00
}
2020-06-22 15:39:37 +02:00
protected CKANOrganization checkGotOrganization ( String gotOrganization ) throws ForbiddenException {
2022-02-15 09:59:02 +01:00
if ( ! configuration . getSupportedOrganizations ( ) . contains ( gotOrganization ) ) {
2020-06-22 15:39:37 +02:00
String error = String . format (
" IS Configuration does not allow to publish in %s organizations. Allowed organization are: %s " ,
2022-02-15 09:59:02 +01:00
gotOrganization , configuration . getSupportedOrganizations ( ) ) ;
2020-06-22 15:39:37 +02:00
throw new ForbiddenException ( error ) ;
}
2020-06-19 17:32:21 +02:00
CKANOrganization ckanOrganization = new CKANOrganization ( ) ;
ckanOrganization . setName ( gotOrganization ) ;
ckanOrganization . read ( ) ;
return ckanOrganization ;
}
2020-06-22 15:39:37 +02:00
protected CKANOrganization getPublishingOrganization ( ObjectNode objectNode ) throws ForbiddenException {
CKANOrganization ckanOrganization = null ;
2020-06-19 17:32:21 +02:00
if ( objectNode . has ( OWNER_ORG_KEY ) ) {
2020-06-22 15:39:37 +02:00
String gotOrganizationName = objectNode . get ( OWNER_ORG_KEY ) . asText ( ) ;
ckanOrganization = checkGotOrganization ( gotOrganizationName ) ;
2020-06-19 17:32:21 +02:00
}
2020-06-22 15:39:37 +02:00
if ( ckanOrganization = = null ) {
// owner organization must be specified if the token belongs to a VRE
2022-02-15 21:18:02 +01:00
String organizationFromContext = configuration . getDefaultOrganization ( ) ;
2020-06-22 15:39:37 +02:00
ckanOrganization = checkGotOrganization ( organizationFromContext ) ;
2020-06-22 15:51:11 +02:00
objectNode . put ( OWNER_ORG_KEY , organizationFromContext ) ;
2020-06-19 17:32:21 +02:00
}
2020-06-22 15:39:37 +02:00
return ckanOrganization ;
2020-06-19 17:32:21 +02:00
}
2018-12-04 12:06:22 +01:00
public ObjectNode checkBaseInformation ( String json ) throws Exception {
2020-11-30 19:44:15 +01:00
return checkBaseInformation ( json , false ) ;
}
2021-02-10 14:18:38 +01:00
public JsonNode cleanResult ( JsonNode jsonNode ) {
if ( jsonNode . has ( OWNER_ORG_KEY ) ) {
( ( ObjectNode ) jsonNode ) . remove ( OWNER_ORG_KEY ) ;
}
2021-11-23 17:53:37 +01:00
// Removing all Content Moderation Keys
if ( jsonNode . has ( EXTRAS_KEY ) ) {
ArrayNode extras = ( ArrayNode ) jsonNode . get ( EXTRAS_KEY ) ;
// It is not possible to remove the element of an array while iterating it.
// We need to create a new array only with valie elements;
ArrayNode newExtras = mapper . createArrayNode ( ) ;
boolean foundOne = false ;
for ( int i = 0 ; i < extras . size ( ) ; i + + ) {
JsonNode extra = extras . get ( i ) ;
if ( extra . has ( EXTRAS_KEY_KEY ) & &
extra . get ( EXTRAS_KEY_KEY ) ! = null & &
2021-12-02 11:50:18 +01:00
extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . startsWith ( Moderated . SYSTEM_CM_PREFIX ) ) {
2021-11-23 17:53:37 +01:00
foundOne = true ;
} else {
newExtras . add ( extra . deepCopy ( ) ) ;
}
}
if ( foundOne ) {
( ( ObjectNode ) jsonNode ) . replace ( EXTRAS_KEY , newExtras ) ;
}
}
2021-02-10 14:18:38 +01:00
return jsonNode ;
}
2021-11-23 17:53:37 +01:00
protected String getAsCleanedString ( JsonNode node ) {
JsonNode jsonNode = cleanResult ( node ) ;
return getAsString ( jsonNode ) ;
}
2020-11-30 19:44:15 +01:00
/ * *
* @param json The json to check
* @param allowPartialInfo used for patch method which provide only partial information ( i . e . the info to patch )
* @return ObjectNode from json
* @throws Exception
* /
public ObjectNode checkBaseInformation ( String json , boolean allowPartialInfo ) throws Exception {
2018-12-04 12:06:22 +01:00
ObjectNode objectNode = ( ObjectNode ) mapper . readTree ( json ) ;
2020-11-30 19:44:15 +01:00
try {
objectNode = ( ObjectNode ) checkName ( objectNode ) ;
} catch ( Exception e ) {
if ( ! allowPartialInfo ) {
throw e ;
}
}
2018-12-04 12:06:22 +01:00
// We need to enforce the itemID to properly manage resource persistence
if ( objectNode . has ( ID_KEY ) ) {
itemID = objectNode . get ( ID_KEY ) . asText ( ) ;
}
2019-02-08 16:49:30 +01:00
// To include private item in search result (e.g. listing) a private package must be searchable
2020-12-01 09:57:48 +01:00
// The package it is just included in the search and listing results but remain private and cannot be accessed
2019-02-08 16:49:30 +01:00
// if not authorized
if ( objectNode . has ( PRIVATE_KEY ) ) {
boolean privatePackage = objectNode . get ( PRIVATE_KEY ) . asBoolean ( ) ;
if ( privatePackage ) {
2021-12-15 18:03:51 +01:00
/ *
* This version is not properly managed by CKAN .
* It is converted to :
* searchable : " true "
* which is incidentally considered as true value even is not correct .
* We need to provide a string with T as capitol letters to make it working
* objectNode . put ( SEARCHABLE_KEY , true ) ;
* /
objectNode . put ( SEARCHABLE_KEY , " True " ) ;
2019-02-08 16:49:30 +01:00
}
}
2018-12-04 12:06:22 +01:00
// check license
String licenseId = null ;
if ( objectNode . has ( LICENSE_KEY ) ) {
licenseId = objectNode . get ( LICENSE_KEY ) . asText ( ) ;
}
2020-12-01 09:55:16 +01:00
if ( licenseId ! = null & & ! licenseId . isEmpty ( ) ) {
try {
CKANLicense . checkLicenseId ( licenseId ) ;
} catch ( Exception e ) {
throw new BadRequestException (
" You must specify an existing license identifier for the item. License list can be retrieved using licence collection " ) ;
}
} else if ( ! allowPartialInfo ) {
2018-12-04 12:06:22 +01:00
throw new BadRequestException (
" You must specify a license identifier for the item. License list can be retrieved using licence collection " ) ;
}
2019-05-20 17:23:49 +02:00
if ( objectNode . has ( CAPACITY_KEY ) ) {
/ *
* When a client provides the ' capacity ' field as ' private ' , the item is not counted in the
* total number of items in the GUI . We want to avoid such a behavior
* See https : //support.d4science.org/issues/16410
* /
objectNode . remove ( CAPACITY_KEY ) ;
}
2021-12-06 17:45:15 +01:00
String authorName = ckanUser . getSurnameName ( ) ;
2021-04-16 16:14:13 +02:00
if ( authorName = = null | | authorName . compareTo ( " " ) = = 0 ) {
authorName = ckanUser . getName ( ) ;
}
objectNode . put ( AUTHOR_KEY , authorName ) ;
2021-12-06 17:45:15 +01:00
String authorEmail = ckanUser . getEMail ( ) ;
2021-04-16 16:14:13 +02:00
objectNode . put ( AUTHOR_EMAIL_KEY , authorEmail ) ;
if ( ! objectNode . has ( MAINTAINER_KEY ) ) {
if ( ! objectNode . has ( MAINTAINER_EMAIL_KEY ) ) {
objectNode . put ( MAINTAINER_KEY , authorName ) ;
objectNode . put ( MAINTAINER_EMAIL_KEY , authorEmail ) ;
} else {
objectNode . put ( MAINTAINER_KEY , objectNode . get ( MAINTAINER_EMAIL_KEY ) . toString ( ) ) ;
}
}
2018-12-04 12:06:22 +01:00
2020-06-23 13:17:58 +02:00
getPublishingOrganization ( objectNode ) ;
2019-05-20 17:23:49 +02:00
2018-12-04 12:06:22 +01:00
return objectNode ;
}
protected JsonNode validateJson ( String json ) {
try {
// check base information (and set them if needed)
ObjectNode objectNode = checkBaseInformation ( json ) ;
// Validating against profiles if any
2019-05-20 17:23:49 +02:00
MetadataUtility metadataUtility = new MetadataUtility ( ) ;
2019-01-10 12:29:47 +01:00
if ( ! metadataUtility . getMetadataProfiles ( ) . isEmpty ( ) ) {
2019-02-27 17:36:09 +01:00
Validator validator = new Validator ( mapper ) ;
2019-05-20 17:23:49 +02:00
objectNode = validator . validateAgainstProfile ( objectNode , metadataUtility ) ;
2018-12-04 12:06:22 +01:00
}
return objectNode ;
} catch ( BadRequestException e ) {
throw e ;
} catch ( Exception e ) {
throw new BadRequestException ( e ) ;
}
}
2021-12-03 17:41:38 +01:00
protected Map < String , String > addFieldsFilters ( Map < String , String > parameters , String . . . requiredFields ) {
StringBuffer stringBuffer = new StringBuffer ( ) ;
stringBuffer . append ( " [ " ) ;
stringBuffer . append ( " ' " ) ;
stringBuffer . append ( ID_KEY ) ;
stringBuffer . append ( " ' " ) ;
stringBuffer . append ( " , " ) ;
stringBuffer . append ( " ' " ) ;
stringBuffer . append ( NAME_KEY ) ;
stringBuffer . append ( " ' " ) ;
for ( String requiredField : requiredFields ) {
if ( requiredField ! = null & & requiredField . compareTo ( " " ) ! = 0 ) {
stringBuffer . append ( " , " ) ;
stringBuffer . append ( " ' " ) ;
stringBuffer . append ( requiredField ) ;
stringBuffer . append ( " ' " ) ;
}
}
stringBuffer . append ( " ] " ) ;
parameters . put ( " fl " , stringBuffer . toString ( ) ) ;
return parameters ;
}
protected Map < String , String > getListingParameters ( int limit , int offset , String . . . requiredFields ) {
2019-02-08 12:25:19 +01:00
Map < String , String > parameters = new HashMap < > ( ) ;
if ( limit < = 0 ) {
// According to CKAN documentation
// the number of matching rows to return. There is a hard limit of 1000 datasets per query.
// see https://docs.ckan.org/en/2.6/api/index.html#ckan.logic.action.get.package_search
limit = 1000 ;
}
parameters . put ( ROWS_KEY , String . valueOf ( limit ) ) ;
2019-09-16 14:48:18 +02:00
2019-02-08 12:25:19 +01:00
if ( offset < 0 ) {
offset = 0 ;
}
2022-04-06 12:01:11 +02:00
parameters . put ( START_KEY , String . valueOf ( offset ) ) ;
// parameters.put(START_KEY, String.valueOf(pageNumber * limit));
2019-02-08 12:25:19 +01:00
2021-12-03 11:25:32 +01:00
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
parameters = checkListParameters ( queryParameters , parameters ) ;
2021-02-03 16:28:17 +01:00
2021-12-03 17:41:38 +01:00
parameters = addFieldsFilters ( parameters , requiredFields ) ;
2021-11-19 16:49:43 +01:00
parameters = addModerationStatusFilter ( parameters ) ;
return parameters ;
}
2021-12-03 11:25:32 +01:00
2021-12-20 13:46:50 +01:00
protected void reuseInstance ( ) {
this . name = null ;
this . result = null ;
this . itemID = null ;
2022-04-06 17:15:46 +02:00
this . itemURL = null ;
this . itemTitle = null ;
2021-12-20 13:46:50 +01:00
}
2021-12-03 11:25:32 +01:00
/ * *
* @param purge indicate if the item
* @return the name list of deleted items
* /
public String deleteAll ( boolean purge ) {
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
if ( queryParameters . containsKey ( GCatConstants . OWN_ONLY_QUERY_PARAMETER ) ) {
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) < Role . ADMIN . ordinal ( ) ) {
2021-12-03 11:25:32 +01:00
queryParameters . remove ( GCatConstants . OWN_ONLY_QUERY_PARAMETER ) ;
queryParameters . add ( GCatConstants . OWN_ONLY_QUERY_PARAMETER , Boolean . TRUE . toString ( ) ) ;
}
} else {
queryParameters . add ( GCatConstants . OWN_ONLY_QUERY_PARAMETER , Boolean . TRUE . toString ( ) ) ;
}
2021-12-03 17:41:38 +01:00
int limit = 25 ;
int offset = 0 ;
Map < String , String > parameters = getListingParameters ( limit , offset , " resources " ) ;
2021-12-03 11:25:32 +01:00
ObjectNode objectNode = mapper . createObjectNode ( ) ;
ArrayNode deleted = mapper . createArrayNode ( ) ;
ArrayNode notDeleted = mapper . createArrayNode ( ) ;
sendGetRequest ( LIST , parameters ) ;
ArrayNode results = ( ArrayNode ) result . get ( RESULTS_KEY ) ;
2021-12-03 17:41:38 +01:00
Set < String > notDeletedSet = new HashSet < > ( ) ;
2021-12-03 11:25:32 +01:00
while ( results . size ( ) > 0 ) {
2021-12-03 17:41:38 +01:00
int alreadyTriedAndNotDeletedAgain = 0 ;
2021-12-03 11:25:32 +01:00
for ( JsonNode node : results ) {
try {
2021-12-20 13:46:50 +01:00
this . reuseInstance ( ) ;
2021-12-03 11:25:32 +01:00
this . result = node ;
this . name = node . get ( NAME_KEY ) . asText ( ) ;
this . itemID = node . get ( ID_KEY ) . asText ( ) ;
delete ( purge ) ;
deleted . add ( name ) ;
2021-12-03 17:41:38 +01:00
if ( notDeletedSet . contains ( name ) ) {
notDeletedSet . remove ( name ) ;
}
try {
Thread . sleep ( TimeUnit . MILLISECONDS . toMillis ( 300 ) ) ;
} catch ( InterruptedException e ) {
}
2021-12-03 11:25:32 +01:00
} catch ( Exception e ) {
try {
if ( name ! = null ) {
2021-12-03 17:41:38 +01:00
if ( notDeletedSet . contains ( name ) ) {
alreadyTriedAndNotDeletedAgain + + ;
} else {
notDeleted . add ( name ) ;
notDeletedSet . add ( name ) ;
}
2021-12-03 11:25:32 +01:00
logger . error ( " Error while trying to delete item with name {} " , name ) ;
} else {
logger . error ( " Unable to get the name of {}. " , mapper . writeValueAsString ( node ) ) ;
}
} catch ( Exception ex ) {
logger . error ( " " , ex ) ;
}
}
}
2021-12-03 17:41:38 +01:00
try {
Thread . sleep ( TimeUnit . SECONDS . toMillis ( 5 ) ) ;
} catch ( InterruptedException e ) {
}
if ( purge ) {
setApiKey ( CKANUtility . getApiKey ( ) ) ;
}
if ( limit = = alreadyTriedAndNotDeletedAgain ) {
offset + + ;
parameters = getListingParameters ( limit , offset , " resources " ) ;
}
2021-12-03 11:25:32 +01:00
sendGetRequest ( LIST , parameters ) ;
results = ( ArrayNode ) result . get ( RESULTS_KEY ) ;
2021-12-03 17:41:38 +01:00
}
if ( notDeleted . size ( ) ! = notDeletedSet . size ( ) ) {
notDeleted = mapper . createArrayNode ( ) ;
for ( String name : notDeletedSet ) {
notDeleted . add ( name ) ;
}
2021-12-03 11:25:32 +01:00
}
2021-12-03 17:41:38 +01:00
objectNode . set ( " deleted " , deleted ) ;
objectNode . set ( " failed " , notDeleted ) ;
2021-12-03 11:25:32 +01:00
return getAsString ( objectNode ) ;
}
2021-11-19 16:49:43 +01:00
public String list ( Map < String , String > parameters ) {
sendGetRequest ( LIST , parameters ) ;
ArrayNode results = ( ArrayNode ) result . get ( RESULTS_KEY ) ;
2022-07-26 12:06:10 +02:00
boolean allFields = false ;
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
if ( queryParameters . containsKey ( GCatConstants . ALL_FIELDS_QUERY_PARAMETER ) ) {
allFields = Boolean . parseBoolean ( queryParameters . get ( GCatConstants . ALL_FIELDS_QUERY_PARAMETER ) . get ( 0 ) ) ;
}
if ( allFields ) {
return getAsString ( results ) ;
}
2021-11-19 16:49:43 +01:00
ArrayNode arrayNode = mapper . createArrayNode ( ) ;
for ( JsonNode node : results ) {
try {
String name = node . get ( NAME_KEY ) . asText ( ) ;
arrayNode . add ( name ) ;
} catch ( Exception e ) {
try {
2021-12-03 11:25:32 +01:00
logger . error ( " Unable to get the name of {}. The Item will not be included in the result " ,
2021-11-19 16:49:43 +01:00
mapper . writeValueAsString ( node ) ) ;
} catch ( Exception ex ) {
logger . error ( " " , ex ) ;
2021-05-14 15:34:11 +02:00
}
}
2021-05-11 11:43:24 +02:00
}
2021-11-19 16:49:43 +01:00
return getAsString ( arrayNode ) ;
}
@Override
public String list ( int limit , int offset ) {
2021-12-03 11:25:32 +01:00
Map < String , String > parameters = getListingParameters ( limit , offset ) ;
2019-10-01 18:00:40 +02:00
return list ( parameters ) ;
}
2021-11-19 16:49:43 +01:00
public int count ( ) {
2021-12-03 11:25:32 +01:00
Map < String , String > parameters = getListingParameters ( 1 , 0 ) ;
2021-11-19 16:49:43 +01:00
sendGetRequest ( LIST , parameters ) ;
int count = result . get ( GCatConstants . COUNT_KEY ) . asInt ( ) ;
return count ;
}
2020-06-22 19:39:29 +02:00
protected Set < String > checkOrganizationFilter ( String q ) {
2019-10-01 18:00:40 +02:00
Matcher m = ORGANIZATION_REGEX_PATTERN . matcher ( q ) ;
2019-10-04 14:16:34 +02:00
2020-06-22 19:39:29 +02:00
Set < String > matches = new HashSet < > ( ) ;
2019-10-01 18:00:40 +02:00
while ( m . find ( ) ) {
2020-06-22 19:39:29 +02:00
matches . add ( q . substring ( m . start ( ) , m . end ( ) ) . replace ( GCatConstants . ORGANIZATION_PARAMETER + " : " , " " ) ) ;
2019-10-01 18:00:40 +02:00
}
2020-06-22 19:39:29 +02:00
return matches ;
2019-10-01 18:00:40 +02:00
}
2021-12-03 11:25:32 +01:00
protected static String [ ] allowedListQueryParameters = new String [ ] { " fq " , " fq_list " , " sort " ,
2020-02-04 09:45:26 +01:00
/* "facet", "facet.mincount", "facet.limit", "facet.field", */
2019-10-04 14:42:44 +02:00
" include_drafts " , " include_private " , " ext_bbox " } ;
2019-10-04 14:16:34 +02:00
2020-06-22 19:39:29 +02:00
protected String getFilterForOrganizations ( ) {
StringWriter stringWriter = new StringWriter ( ) ;
2022-07-14 17:18:20 +02:00
stringWriter . append ( String . format ( GCatConstants . ORGANIZATION_FILTER_TEMPLATE , configuration . getDefaultOrganization ( ) ) ) ;
/ *
* TODO
*
* This generated something like :
* organization : orgfortesting OR organization : prevre OR organization : data_inrae
* and it seems not working
* I need to investigate better this part .
*
2020-06-22 19:39:29 +02:00
int i = 1 ;
2022-02-15 09:59:02 +01:00
for ( String organizationName : configuration . getSupportedOrganizations ( ) ) {
2020-06-22 19:39:29 +02:00
stringWriter . append ( String . format ( GCatConstants . ORGANIZATION_FILTER_TEMPLATE , organizationName ) ) ;
2022-02-15 09:59:02 +01:00
if ( i ! = configuration . getSupportedOrganizations ( ) . size ( ) ) {
2020-06-22 19:39:29 +02:00
// Please note that an item can only belong to a single organization.
// Hence the query must put supported organizations in OR.
stringWriter . append ( " OR " ) ;
}
i + + ;
}
2022-07-14 17:18:20 +02:00
* /
2020-06-22 19:39:29 +02:00
return stringWriter . toString ( ) ;
}
2019-10-01 18:00:40 +02:00
protected Map < String , String > checkListParameters ( MultivaluedMap < String , String > queryParameters ,
Map < String , String > parameters ) {
String q = null ;
if ( queryParameters . containsKey ( GCatConstants . Q_KEY ) ) {
q = queryParameters . getFirst ( GCatConstants . Q_KEY ) ;
}
2020-06-22 19:39:29 +02:00
if ( q ! = null ) {
Set < String > organizations = checkOrganizationFilter ( q ) ;
if ( organizations . size ( ) = = 0 ) {
2019-10-01 18:00:40 +02:00
// Adding organization filter to q
2020-06-22 19:39:29 +02:00
String filter = getFilterForOrganizations ( ) ;
2021-12-03 11:25:32 +01:00
q = String . format ( " %s AND %s " , q , filter ) ;
2020-06-22 19:39:29 +02:00
} else {
2022-02-15 09:59:02 +01:00
organizations . removeAll ( configuration . getSupportedOrganizations ( ) ) ;
2020-06-22 19:39:29 +02:00
if ( organizations . size ( ) > 0 ) {
2022-02-15 09:59:02 +01:00
String error = String . format ( " It is not possible to query the following organizations %s. Supported organization in this context are %s " , organizations . toString ( ) , configuration . getSupportedOrganizations ( ) . toString ( ) ) ;
2020-06-22 19:39:29 +02:00
throw new ForbiddenException ( error ) ;
}
2019-09-27 17:33:10 +02:00
}
2019-10-01 18:00:40 +02:00
} else {
2020-06-22 19:39:29 +02:00
String filter = getFilterForOrganizations ( ) ;
2021-12-03 11:25:32 +01:00
q = filter ;
2019-09-27 17:33:10 +02:00
}
2021-12-03 11:25:32 +01:00
if ( queryParameters . containsKey ( GCatConstants . OWN_ONLY_QUERY_PARAMETER ) ) {
if ( ! queryParameters . get ( GCatConstants . OWN_ONLY_QUERY_PARAMETER ) . isEmpty ( ) & & Boolean . parseBoolean ( queryParameters . get ( GCatConstants . OWN_ONLY_QUERY_PARAMETER ) . get ( 0 ) ) ) {
2021-12-06 17:45:15 +01:00
String filter = String . format ( " %s:%s " , AUTHOR_EMAIL_KEY , ckanUser . getEMail ( ) ) ;
2021-12-03 11:25:32 +01:00
q = String . format ( " %s AND %s " , q , filter ) ;
}
}
parameters . put ( GCatConstants . Q_KEY , q ) ;
2019-09-27 17:33:10 +02:00
2019-10-04 14:42:44 +02:00
for ( String key : allowedListQueryParameters ) {
2019-10-04 14:16:34 +02:00
if ( queryParameters . containsKey ( key ) ) {
parameters . put ( key , queryParameters . getFirst ( key ) ) ;
2019-10-01 18:00:40 +02:00
}
2019-09-27 17:33:10 +02:00
}
2019-02-08 12:25:19 +01:00
2019-02-08 15:17:09 +01:00
// parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true));
2019-02-08 14:40:57 +01:00
// By default not including draft
// parameters.put(INCLUDE_DRAFTS_KEY, String.valueOf(false));
2019-10-01 18:00:40 +02:00
return parameters ;
}
2018-12-04 12:06:22 +01:00
protected void rollbackManagedResources ( ) {
for ( CKANResource ckanResource : managedResources ) {
try {
ckanResource . rollback ( ) ;
2019-09-16 14:48:18 +02:00
} catch ( Exception e ) {
2018-12-04 12:06:22 +01:00
logger . error ( " Unable to rollback resource {} to the original value " , ckanResource . getResourceID ( ) ) ;
}
}
}
protected ArrayNode createResources ( ArrayNode resourcesToBeCreated ) {
ArrayNode created = mapper . createArrayNode ( ) ;
for ( JsonNode resourceNode : resourcesToBeCreated ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
String json = ckanResource . create ( getAsString ( resourceNode ) ) ;
created . add ( getAsJsonNode ( json ) ) ;
managedResources . add ( ckanResource ) ;
}
return created ;
}
2019-02-26 14:58:06 +01:00
protected JsonNode addExtraField ( JsonNode jsonNode , String key , String value ) {
ArrayNode extras = null ;
boolean found = false ;
if ( jsonNode . has ( EXTRAS_KEY ) ) {
extras = ( ArrayNode ) jsonNode . get ( EXTRAS_KEY ) ;
for ( JsonNode extra : extras ) {
2021-11-23 17:53:37 +01:00
if ( extra . has ( EXTRAS_KEY_KEY ) & & extra . get ( EXTRAS_KEY_KEY ) ! = null & & extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . compareTo ( key ) = = 0 ) {
2019-02-26 14:58:06 +01:00
( ( ObjectNode ) extra ) . put ( EXTRAS_VALUE_KEY , value ) ;
found = true ;
break ;
}
}
2019-09-16 14:48:18 +02:00
} else {
2021-05-11 16:05:39 +02:00
extras = ( ( ObjectNode ) jsonNode ) . putArray ( EXTRAS_KEY ) ;
2019-02-26 14:58:06 +01:00
}
if ( ! found ) {
ObjectNode extra = mapper . createObjectNode ( ) ;
extra . put ( EXTRAS_KEY_KEY , key ) ;
extra . put ( EXTRAS_VALUE_KEY , value ) ;
extras . add ( extra ) ;
}
return jsonNode ;
}
2021-11-23 17:53:37 +01:00
protected JsonNode getExtraField ( JsonNode jsonNode , String key ) {
if ( jsonNode . has ( EXTRAS_KEY ) ) {
ArrayNode extras = ( ArrayNode ) jsonNode . get ( EXTRAS_KEY ) ;
for ( JsonNode extra : extras ) {
if ( extra . has ( EXTRAS_KEY_KEY ) & & extra . get ( EXTRAS_KEY_KEY ) ! = null & & extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . compareTo ( key ) = = 0 ) {
return extra . get ( EXTRAS_VALUE_KEY ) ;
}
}
}
return null ;
}
2019-02-26 14:58:06 +01:00
protected String addItemURLViaResolver ( JsonNode jsonNode ) {
// Adding Item URL via Resolver
2022-03-31 15:49:22 +02:00
itemURL = URIResolver . getCatalogueItemURL ( name ) ;
addExtraField ( jsonNode , EXTRAS_ITEM_URL_KEY , itemURL ) ;
return itemURL ;
2019-02-26 14:58:06 +01:00
}
2022-04-06 17:15:46 +02:00
protected void sendSocialPost ( ) {
2019-05-20 17:23:49 +02:00
try {
2021-05-14 15:34:11 +02:00
boolean makePost = false ;
2019-05-20 17:23:49 +02:00
try {
2019-09-16 14:48:18 +02:00
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
2021-05-14 15:34:11 +02:00
if ( queryParameters . containsKey ( GCatConstants . SOCIAL_POST_QUERY_PARAMETER ) ) {
makePost = Boolean . parseBoolean ( queryParameters . getFirst ( GCatConstants . SOCIAL_POST_QUERY_PARAMETER ) ) ;
2019-05-20 17:23:49 +02:00
}
2019-09-16 14:48:18 +02:00
} catch ( Exception e ) {
2021-05-14 15:34:11 +02:00
makePost = false ;
2019-05-20 17:23:49 +02:00
}
2021-05-14 15:34:11 +02:00
if ( makePost ) {
2019-05-20 17:23:49 +02:00
ArrayNode arrayNode = ( ArrayNode ) result . get ( TAGS_KEY ) ;
2021-05-14 15:34:11 +02:00
SocialPost socialPost = new SocialPost ( ) ;
socialPost . setItemID ( itemID ) ;
2022-03-31 15:49:22 +02:00
socialPost . setItemURL ( itemURL ) ;
2022-04-06 17:15:46 +02:00
socialPost . setItemTitle ( itemTitle ) ;
2021-05-14 15:34:11 +02:00
socialPost . setTags ( arrayNode ) ;
2021-06-21 17:09:49 +02:00
Boolean notification = null ;
try {
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
if ( queryParameters . containsKey ( GCatConstants . SOCIAL_POST_NOTIFICATION_QUERY_PARAMETER ) ) {
notification = Boolean . parseBoolean ( queryParameters . getFirst ( GCatConstants . SOCIAL_POST_NOTIFICATION_QUERY_PARAMETER ) ) ;
}
} catch ( Exception e ) {
}
socialPost . setNotification ( notification ) ;
2021-05-14 15:34:11 +02:00
socialPost . start ( ) ;
2019-09-16 14:48:18 +02:00
} else {
2019-05-20 17:23:49 +02:00
logger . info ( " The request explicitly disabled the Social Post. " ) ;
}
2019-09-16 14:48:18 +02:00
} catch ( Exception e ) {
logger . warn (
" error dealing with Social Post. The service will not raise the exception belove. Please contact the administrator to let him know about this message. " ,
e ) ;
2019-05-20 17:23:49 +02:00
}
}
2021-11-18 17:49:24 +01:00
protected boolean isItemCreator ( ) {
2021-12-06 17:45:15 +01:00
return result . get ( AUTHOR_EMAIL_KEY ) . asText ( ) . compareTo ( ckanUser . getEMail ( ) ) = = 0 ;
2021-11-18 17:49:24 +01:00
}
2022-04-06 17:15:46 +02:00
protected void parseResult ( ) {
if ( this . itemID = = null ) {
this . itemID = result . get ( ID_KEY ) . asText ( ) ;
}
this . itemTitle = result . get ( TITLE_KEY ) . asText ( ) ;
this . itemURL = getExtraField ( result , EXTRAS_ITEM_URL_KEY ) . asText ( ) ;
}
2021-11-22 16:38:56 +01:00
protected void readItem ( ) throws Exception {
2021-12-03 11:25:32 +01:00
if ( this . result = = null ) {
String ret = super . read ( ) ;
this . result = mapper . readTree ( ret ) ;
}
2022-04-06 17:15:46 +02:00
parseResult ( ) ;
2021-11-22 16:38:56 +01:00
}
2021-11-18 17:49:24 +01:00
2021-03-09 12:16:42 +01:00
@Override
public String read ( ) {
try {
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2021-11-19 16:49:43 +01:00
checkModerationRead ( ) ;
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2021-03-09 12:16:42 +01:00
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
2021-11-19 16:49:43 +01:00
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.create.package_create
2018-12-04 12:06:22 +01:00
@Override
public String create ( String json ) {
try {
logger . debug ( " Going to create Item {} " , json ) ;
2021-05-14 15:34:11 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) < Role . EDITOR . ordinal ( ) ) {
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 ( ) ) ;
2021-05-11 11:43:24 +02:00
}
2018-12-04 12:06:22 +01:00
JsonNode jsonNode = validateJson ( json ) ;
2021-11-22 16:38:56 +01:00
setItemToPending ( jsonNode ) ;
2021-05-11 16:05:39 +02:00
2018-12-04 12:06:22 +01:00
ArrayNode resourcesToBeCreated = mapper . createArrayNode ( ) ;
if ( jsonNode . has ( RESOURCES_KEY ) ) {
resourcesToBeCreated = ( ArrayNode ) jsonNode . get ( RESOURCES_KEY ) ;
( ( ObjectNode ) jsonNode ) . remove ( RESOURCES_KEY ) ;
}
2022-02-15 09:59:02 +01:00
if ( configuration . getScopeBean ( ) . is ( Type . VRE ) ) {
2022-03-31 15:49:22 +02:00
addItemURLViaResolver ( jsonNode ) ;
2019-05-20 17:23:49 +02:00
}
2019-02-26 14:58:06 +01:00
2018-12-04 12:06:22 +01:00
super . create ( getAsString ( jsonNode ) ) ;
2022-04-06 17:15:46 +02:00
parseResult ( ) ;
2018-12-04 12:06:22 +01:00
ArrayNode created = createResources ( resourcesToBeCreated ) ;
( ( ObjectNode ) result ) . replace ( RESOURCES_KEY , created ) ;
2021-11-26 12:27:31 +01:00
postItemCreated ( ) ;
2021-11-17 17:47:58 +01:00
2021-11-23 17:53:37 +01:00
if ( ! isModerationEnabled ( ) ) {
2022-02-15 09:59:02 +01:00
if ( configuration . getScopeBean ( ) . is ( Type . VRE ) ) {
2021-11-23 17:53:37 +01:00
// Actions performed after a package has been correctly created on ckan.
2022-04-06 17:15:46 +02:00
sendSocialPost ( ) ;
2021-11-23 17:53:37 +01:00
}
}
2021-02-10 14:18:38 +01:00
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2018-12-04 12:06:22 +01:00
} catch ( WebApplicationException e ) {
rollbackManagedResources ( ) ;
throw e ;
} catch ( Exception e ) {
rollbackManagedResources ( ) ;
throw new InternalServerErrorException ( e ) ;
}
}
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.update.package_update
2018-12-04 12:06:22 +01:00
@Override
public String update ( String json ) {
try {
JsonNode jsonNode = validateJson ( json ) ;
2021-12-15 18:03:51 +01:00
/ *
* Going to read the item from CKAN just to check the item status .
* I need to reset the result first because the current contains
* the extras as sent by the client which are not trusted
* /
this . result = null ;
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2018-12-04 12:06:22 +01:00
2021-05-14 15:34:11 +02:00
jsonNode = checkModerationUpdate ( jsonNode ) ;
2019-09-16 14:48:18 +02:00
Map < String , CKANResource > originalResources = new HashMap < > ( ) ;
ArrayNode originalResourcesarrayNode = ( ArrayNode ) result . get ( RESOURCES_KEY ) ;
if ( originalResources ! = null ) {
2018-12-04 12:06:22 +01:00
for ( JsonNode resourceNode : originalResourcesarrayNode ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
ckanResource . setPreviousRepresentation ( resourceNode ) ;
String resourceID = ckanResource . getResourceID ( ) ;
originalResources . put ( resourceID , ckanResource ) ;
}
}
if ( jsonNode . has ( RESOURCES_KEY ) ) {
ArrayNode resourcesToBeSend = mapper . createArrayNode ( ) ;
ArrayNode receivedResources = ( ArrayNode ) jsonNode . get ( RESOURCES_KEY ) ;
for ( JsonNode resourceNode : receivedResources ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
String resourceId = CKANResource . extractResourceID ( resourceNode ) ;
2019-09-16 14:48:18 +02:00
if ( resourceId ! = null ) {
2018-12-04 12:06:22 +01:00
if ( originalResources . containsKey ( resourceId ) ) {
ckanResource = originalResources . get ( resourceId ) ;
originalResources . remove ( resourceId ) ;
2019-09-16 14:48:18 +02:00
} else {
throw new BadRequestException (
2020-02-04 09:45:26 +01:00
" The content contains a resource with id " + resourceId + " which does not exists " ) ;
2018-12-04 12:06:22 +01:00
}
}
2020-06-22 15:39:37 +02:00
if ( originalResources . get ( resourceId ) ! = null
& & ( ! originalResources . get ( resourceId ) . getPreviousRepresentation ( ) . equals ( resourceNode ) ) ) {
2020-02-04 09:45:26 +01:00
resourceNode = ckanResource . createOrUpdate ( resourceNode ) ;
}
2018-12-04 12:06:22 +01:00
resourcesToBeSend . add ( resourceNode ) ;
managedResources . add ( ckanResource ) ;
}
( ( ObjectNode ) jsonNode ) . replace ( RESOURCES_KEY , resourcesToBeSend ) ;
}
2019-02-26 14:58:06 +01:00
addItemURLViaResolver ( jsonNode ) ;
2018-12-04 12:06:22 +01:00
sendPostRequest ( ITEM_UPDATE , getAsString ( jsonNode ) ) ;
for ( String resourceId : originalResources . keySet ( ) ) {
CKANResource ckanResource = originalResources . get ( resourceId ) ;
ckanResource . deleteFile ( ) ;
}
2021-11-26 12:27:31 +01:00
postItemUpdated ( ) ;
2021-11-22 16:38:56 +01:00
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2018-12-04 12:06:22 +01:00
} catch ( WebApplicationException e ) {
rollbackManagedResources ( ) ;
throw e ;
} catch ( Exception e ) {
rollbackManagedResources ( ) ;
throw new InternalServerErrorException ( e ) ;
}
}
2021-02-22 09:29:52 +01:00
// see https://docs.ckan.org/en/latest/api/#ckan.logic.action.patch.package_patch
2018-12-04 12:06:22 +01:00
@Override
public String patch ( String json ) {
2020-11-30 19:44:15 +01:00
try {
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2021-05-11 11:43:24 +02:00
2020-12-02 16:57:39 +01:00
JsonNode jsonNode = checkBaseInformation ( json , true ) ;
( ( ObjectNode ) jsonNode ) . put ( ID_KEY , this . itemID ) ;
2020-11-30 19:44:15 +01:00
2021-05-14 15:34:11 +02:00
jsonNode = checkModerationUpdate ( jsonNode ) ;
2020-11-30 19:44:15 +01:00
Map < String , CKANResource > originalResources = new HashMap < > ( ) ;
ArrayNode originalResourcesarrayNode = ( ArrayNode ) result . get ( RESOURCES_KEY ) ;
if ( originalResources ! = null ) {
for ( JsonNode resourceNode : originalResourcesarrayNode ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
ckanResource . setPreviousRepresentation ( resourceNode ) ;
String resourceID = ckanResource . getResourceID ( ) ;
originalResources . put ( resourceID , ckanResource ) ;
}
}
if ( jsonNode . has ( RESOURCES_KEY ) ) {
ArrayNode resourcesToBeSend = mapper . createArrayNode ( ) ;
ArrayNode receivedResources = ( ArrayNode ) jsonNode . get ( RESOURCES_KEY ) ;
for ( JsonNode resourceNode : receivedResources ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
String resourceId = CKANResource . extractResourceID ( resourceNode ) ;
if ( resourceId ! = null ) {
if ( originalResources . containsKey ( resourceId ) ) {
ckanResource = originalResources . get ( resourceId ) ;
originalResources . remove ( resourceId ) ;
} else {
throw new BadRequestException (
" The content contains a resource with id " + resourceId + " which does not exists " ) ;
}
}
if ( originalResources . get ( resourceId ) ! = null
& & ( ! originalResources . get ( resourceId ) . getPreviousRepresentation ( ) . equals ( resourceNode ) ) ) {
resourceNode = ckanResource . createOrUpdate ( resourceNode ) ;
}
resourcesToBeSend . add ( resourceNode ) ;
managedResources . add ( ckanResource ) ;
}
( ( ObjectNode ) jsonNode ) . replace ( RESOURCES_KEY , resourcesToBeSend ) ;
}
addItemURLViaResolver ( jsonNode ) ;
sendPostRequest ( ITEM_PATCH , getAsString ( jsonNode ) ) ;
2022-04-06 17:15:46 +02:00
parseResult ( ) ;
2020-11-30 19:44:15 +01:00
for ( String resourceId : originalResources . keySet ( ) ) {
CKANResource ckanResource = originalResources . get ( resourceId ) ;
ckanResource . deleteFile ( ) ;
}
2021-11-26 12:27:31 +01:00
postItemUpdated ( ) ;
2021-11-22 16:38:56 +01:00
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2020-11-30 19:44:15 +01:00
} catch ( WebApplicationException e ) {
rollbackManagedResources ( ) ;
throw e ;
} catch ( Exception e ) {
rollbackManagedResources ( ) ;
throw new InternalServerErrorException ( e ) ;
}
2018-12-04 12:06:22 +01:00
}
@Override
protected void delete ( ) {
2021-11-19 16:49:43 +01:00
checkModerationDelete ( ) ;
2018-12-04 12:06:22 +01:00
super . delete ( ) ;
}
@Override
public void purge ( ) {
try {
2021-12-20 13:46:50 +01:00
setApiKey ( CKANUtility . getSysAdminAPI ( ) ) ;
readItem ( ) ;
2021-12-03 17:41:38 +01:00
checkModerationDelete ( ) ;
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) < Role . ADMIN . ordinal ( ) & & ! isItemCreator ( ) ) {
2021-12-20 13:46:50 +01:00
throw new ForbiddenException ( " Only " + Role . ADMIN . getPortalRole ( ) + " s and item creator are entitled to purge an item " ) ;
}
2021-11-22 16:38:56 +01:00
if ( result . has ( RESOURCES_KEY ) ) {
itemID = result . get ( ID_KEY ) . asText ( ) ;
ArrayNode arrayNode = ( ArrayNode ) result . get ( RESOURCES_KEY ) ;
for ( JsonNode jsonNode : arrayNode ) {
CKANResource ckanResource = new CKANResource ( itemID ) ;
ckanResource . setPreviousRepresentation ( jsonNode ) ;
2021-12-03 17:41:38 +01:00
ckanResource . deleteFile ( ) ; // Only delete file is required because the item will be purged at the end
2021-11-22 16:38:56 +01:00
}
2018-12-04 12:06:22 +01:00
}
2021-11-22 16:38:56 +01:00
super . purge ( ) ;
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
2018-12-04 12:06:22 +01:00
}
}
2021-11-16 18:57:05 +01:00
/ * *
* Used for bulk purging . Internal use only
* /
2022-05-12 16:25:58 +02:00
public void purgeNoCheckNoDeleteFiles ( ) {
setApiKey ( CKANUtility . getSysAdminAPI ( ) ) ;
super . purge ( ) ;
2021-11-16 18:57:05 +01:00
}
2021-11-17 17:47:58 +01:00
/ *
2021-11-19 16:49:43 +01:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-11-17 17:47:58 +01:00
* Moderation Related functions
2021-11-19 16:49:43 +01:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-11-17 17:47:58 +01:00
*
* /
2021-11-18 16:54:17 +01:00
2021-11-19 16:49:43 +01:00
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 ) {
2021-12-02 11:50:18 +01:00
if ( extra . has ( EXTRAS_KEY_KEY ) & & extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . compareTo ( Moderated . SYSTEM_CM_ITEM_STATUS ) = = 0 ) {
2021-11-19 16:49:43 +01:00
cmItemStatusString = extra . get ( EXTRAS_VALUE_KEY ) . asText ( ) ;
found = true ;
break ;
}
}
}
CMItemStatus cmItemStatus = CMItemStatus . getCMItemStatusFromValue ( cmItemStatusString ) ;
if ( ! found ) {
// The item was published before activating the moderation.
// The item is considered as approved and the item representation must be updated
setToApproved ( result ) ;
2021-12-15 18:03:51 +01:00
String ret = sendPostRequest ( ITEM_UPDATE , getAsString ( result ) ) ;
2021-11-19 16:49:43 +01:00
try {
result = mapper . readTree ( ret ) ;
} catch ( Exception e ) {
new InternalServerErrorException ( e ) ;
}
}
return cmItemStatus ;
}
protected CMItemStatus getRequestedCMItemStatus ( ) {
CMItemStatus cmItemStatus = null ;
try {
MultivaluedMap < String , String > queryParameters = uriInfo . getQueryParameters ( ) ;
2021-12-02 11:50:18 +01:00
if ( queryParameters . containsKey ( Moderated . CM_ITEM_STATUS_QUERY_PARAMETER ) ) {
String cmItemStatusString = queryParameters . getFirst ( Moderated . CM_ITEM_STATUS_QUERY_PARAMETER ) ;
2021-11-19 16:49:43 +01:00
cmItemStatus = CMItemStatus . getCMItemStatusFromValue ( cmItemStatusString ) ;
}
} catch ( Exception e ) {
cmItemStatus = null ;
}
return cmItemStatus ;
}
2021-11-18 16:54:17 +01:00
protected boolean isModerationEnabled ( ) {
2022-02-15 09:59:02 +01:00
boolean moderationEnabled = configuration . isModerationEnabled ( ) ;
2021-11-26 12:27:31 +01:00
if ( moderationEnabled & & moderationThread = = null ) {
moderationThread = ModerationThread . getDefaultInstance ( ) ;
moderationThread . setCKANUser ( ckanUser ) ;
2021-11-18 16:54:17 +01:00
}
return moderationEnabled ;
}
2021-11-19 16:49:43 +01:00
protected Map < String , String > addModerationStatusFilter ( Map < String , String > parameters ) {
if ( isModerationEnabled ( ) ) {
String q = parameters . get ( GCatConstants . Q_KEY ) ;
CMItemStatus cmItemStatus = getRequestedCMItemStatus ( ) ;
2022-04-21 13:18:15 +02:00
this . apiKey = CKANUtility . getSysAdminAPI ( ) ;
2021-12-06 17:45:15 +01:00
if ( ! ckanUser . isCatalogueModerator ( ) ) {
2022-04-21 13:18:15 +02:00
q = String . format ( " %s AND %s:%s " , q , AUTHOR_EMAIL_KEY , ckanUser . getEMail ( ) ) ;
parameters . put ( GCatConstants . Q_KEY , q ) ;
2021-11-19 16:49:43 +01:00
switch ( ckanUser . getRole ( ) ) {
case ADMIN :
2022-03-31 13:05:33 +02:00
case MANAGER :
2021-11-19 16:49:43 +01:00
case EDITOR :
break ;
case MEMBER :
if ( cmItemStatus ! = null & & cmItemStatus ! = CMItemStatus . APPROVED ) {
throw new ForbiddenException ( " You are only authorized to list " + CMItemStatus . APPROVED . getValue ( ) + " items " ) ;
}
break ;
default :
break ;
}
}
2022-07-26 13:52:06 +02:00
boolean cmItemStatusWasNull = false ;
2022-04-21 13:18:15 +02:00
if ( cmItemStatus = = null ) {
2022-07-26 13:52:06 +02:00
cmItemStatusWasNull = true ;
2022-04-21 13:18:15 +02:00
cmItemStatus = CMItemStatus . APPROVED ;
2021-11-19 16:49:43 +01:00
}
2022-04-21 15:41:13 +02:00
StringBuffer stringBuffer = new StringBuffer ( ) ;
stringBuffer . append ( " ( " ) ;
stringBuffer . append ( CM_STATUS_QUERY_FILTER_KEY ) ;
stringBuffer . append ( " : " ) ;
2022-04-21 13:18:15 +02:00
stringBuffer . append ( cmItemStatus . getValue ( ) ) ;
2022-04-21 15:41:13 +02:00
2022-07-26 13:52:06 +02:00
if ( cmItemStatusWasNull ) {
2022-04-21 13:18:15 +02:00
stringBuffer . append ( " OR (*:* - " ) ;
stringBuffer . append ( CM_STATUS_QUERY_FILTER_KEY ) ;
stringBuffer . append ( " :[* TO *]) " ) ;
}
2022-07-26 13:52:06 +02:00
2022-04-21 13:18:15 +02:00
stringBuffer . append ( " ) " ) ;
q = String . format ( " %s AND %s " , q , stringBuffer . toString ( ) ) ;
parameters . put ( GCatConstants . Q_KEY , q ) ;
2021-11-19 16:49:43 +01:00
parameters . put ( INCLUDE_PRIVATE_KEY , String . valueOf ( true ) ) ;
2021-12-20 13:46:50 +01:00
} else {
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) > = Role . ADMIN . ordinal ( ) ) {
2021-12-20 13:46:50 +01:00
parameters . put ( INCLUDE_PRIVATE_KEY , String . valueOf ( true ) ) ;
}
2021-11-19 16:49:43 +01:00
}
return parameters ;
2021-11-17 17:47:58 +01:00
}
2021-11-19 16:49:43 +01:00
protected void checkModerationRead ( ) {
if ( isModerationEnabled ( ) ) {
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
if ( cmItemStatus = = CMItemStatus . APPROVED ) {
return ;
}
if ( isItemCreator ( ) ) {
// The author is entitled to read its own items independently from the status
return ;
}
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) > = Role . ADMIN . ordinal ( ) | | ckanUser . isCatalogueModerator ( ) ) {
2021-11-19 16:49:43 +01:00
// Catalogue-Admin and Catalogue-Moderator are entitled to read items with any statues
return ;
}
throw new ForbiddenException ( " You are not entitled to read the item " ) ;
}
2021-11-17 17:47:58 +01:00
}
2021-11-16 18:57:05 +01:00
2021-11-19 16:49:43 +01:00
protected JsonNode checkModerationUpdate ( JsonNode jsonNode ) {
2021-11-16 18:57:05 +01:00
if ( isModerationEnabled ( ) ) {
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
boolean setToPending = true ;
switch ( cmItemStatus ) {
case APPROVED :
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) < Role . ADMIN . ordinal ( ) & & ! isItemCreator ( ) ) {
2021-11-19 16:49:43 +01:00
throw new ForbiddenException ( " Only " + Role . ADMIN . getPortalRole ( ) + " s and item creator are entitled to update an " + cmItemStatus . getValue ( ) + " item " ) ;
}
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) > = Role . ADMIN . ordinal ( ) ) {
2021-11-19 16:49:43 +01:00
setToApproved ( jsonNode ) ;
setToPending = false ;
2021-11-16 18:57:05 +01:00
}
break ;
case PENDING :
2021-11-18 17:53:00 +01:00
if ( isItemCreator ( ) ) {
2021-11-16 18:57:05 +01:00
break ;
}
2021-12-06 17:45:15 +01:00
if ( ckanUser . isCatalogueModerator ( ) ) {
2021-11-16 18:57:05 +01:00
break ;
}
throw new ForbiddenException ( " You are not entitled to update a " + cmItemStatus . getValue ( ) + " item " ) ;
case REJECTED :
2021-11-18 17:53:00 +01:00
if ( isItemCreator ( ) ) {
2021-11-16 18:57:05 +01:00
break ;
}
2021-12-06 17:45:15 +01:00
if ( ckanUser . isCatalogueModerator ( ) ) {
2021-11-16 18:57:05 +01:00
break ;
}
throw new ForbiddenException ( " You are not entitled to update a " + cmItemStatus . getValue ( ) + " item " ) ;
default :
break ;
}
if ( setToPending ) {
2021-11-22 16:38:56 +01:00
setItemToPending ( jsonNode ) ;
2021-11-16 18:57:05 +01:00
}
}
return jsonNode ;
}
2021-11-19 16:49:43 +01:00
protected void checkModerationDelete ( ) {
2021-11-22 16:38:56 +01:00
try {
if ( isModerationEnabled ( ) ) {
readItem ( ) ;
2022-03-31 13:05:33 +02:00
if ( ckanUser . getRole ( ) . ordinal ( ) > = Role . ADMIN . ordinal ( ) ) {
2021-11-22 16:38:56 +01:00
// Ad Admin can delete any item independently from the status
return ;
}
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
switch ( cmItemStatus ) {
case APPROVED :
if ( isItemCreator ( ) ) {
break ;
}
throw new ForbiddenException ( " Only " + Role . ADMIN . getPortalRole ( ) + " s and item creator are entitled to delete an " + cmItemStatus . getValue ( ) + " item " ) ;
case REJECTED :
if ( isItemCreator ( ) ) {
break ;
}
2021-12-06 17:45:15 +01:00
if ( ckanUser . isCatalogueModerator ( ) ) {
2021-11-22 16:38:56 +01:00
break ;
}
throw new ForbiddenException ( " You are not entitled to delete a " + cmItemStatus . getValue ( ) + " item " ) ;
case PENDING :
if ( isItemCreator ( ) ) {
break ;
}
2021-12-06 17:45:15 +01:00
if ( ckanUser . isCatalogueModerator ( ) ) {
2021-11-22 16:38:56 +01:00
break ;
}
throw new ForbiddenException ( " You are not entitled to update a " + cmItemStatus . getValue ( ) + " item " ) ;
2021-11-19 16:49:43 +01:00
2021-11-22 16:38:56 +01:00
default :
2021-11-19 16:49:43 +01:00
break ;
2021-11-22 16:38:56 +01:00
}
}
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
2021-11-19 16:49:43 +01:00
}
2021-11-16 18:57:05 +01:00
}
protected void setToRejected ( JsonNode jsonNode ) {
2021-12-02 11:50:18 +01:00
addExtraField ( jsonNode , Moderated . SYSTEM_CM_ITEM_STATUS , CMItemStatus . REJECTED . getValue ( ) ) ;
2021-11-19 16:49:43 +01:00
}
2021-11-22 16:38:56 +01:00
protected void setItemToPending ( JsonNode jsonNode ) {
if ( isModerationEnabled ( ) ) {
2021-12-02 11:50:18 +01:00
addExtraField ( jsonNode , Moderated . SYSTEM_CM_ITEM_STATUS , CMItemStatus . PENDING . getValue ( ) ) ;
2021-11-22 16:38:56 +01:00
CMItemVisibility cmItemVisibility = CMItemVisibility . PUBLIC ;
if ( jsonNode . has ( PRIVATE_KEY ) ) {
boolean privatePackage = jsonNode . get ( PRIVATE_KEY ) . asBoolean ( ) ;
if ( privatePackage ) {
cmItemVisibility = CMItemVisibility . RESTRICTED ;
}
2021-11-19 16:49:43 +01:00
}
2021-12-02 11:50:18 +01:00
addExtraField ( jsonNode , Moderated . SYSTEM_CM_ITEM_VISIBILITY , cmItemVisibility . getValue ( ) ) ;
2021-11-22 16:38:56 +01:00
( ( ObjectNode ) jsonNode ) . put ( PRIVATE_KEY , true ) ;
2021-12-15 18:03:51 +01:00
/ *
* This version is not properly managed by CKAN .
* It is converted to :
* searchable : " false "
* which is considered as true value .
* We need to provide a string with F as capitol letters to make it working
* ( ( ObjectNode ) jsonNode ) . put ( SEARCHABLE_KEY , false ) ;
* /
( ( ObjectNode ) jsonNode ) . put ( SEARCHABLE_KEY , " False " ) ;
2021-11-19 16:49:43 +01:00
}
2021-11-16 18:57:05 +01:00
}
protected void setToApproved ( JsonNode jsonNode ) {
ArrayNode extras = ( ArrayNode ) jsonNode . get ( EXTRAS_KEY ) ;
boolean approvedSet = false ;
CMItemVisibility cmItemVisibility = null ;
for ( JsonNode extra : extras ) {
2021-12-02 11:50:18 +01:00
if ( extra . has ( EXTRAS_KEY_KEY ) & & extra . get ( EXTRAS_KEY_KEY ) ! = null & & extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . compareTo ( Moderated . SYSTEM_CM_ITEM_STATUS ) = = 0 ) {
2021-11-16 18:57:05 +01:00
( ( ObjectNode ) extra ) . put ( EXTRAS_VALUE_KEY , CMItemStatus . APPROVED . getValue ( ) ) ;
approvedSet = true ;
}
2021-12-02 11:50:18 +01:00
if ( extra . has ( EXTRAS_KEY_KEY ) & & extra . get ( EXTRAS_KEY_KEY ) ! = null & & extra . get ( EXTRAS_KEY_KEY ) . asText ( ) . compareTo ( Moderated . SYSTEM_CM_ITEM_VISIBILITY ) = = 0 ) {
2021-11-16 18:57:05 +01:00
cmItemVisibility = CMItemVisibility . getCMItemStatusFromValue ( extra . get ( EXTRAS_VALUE_KEY ) . asText ( ) ) ;
}
}
if ( ! approvedSet ) {
2021-12-02 11:50:18 +01:00
addExtraField ( jsonNode , Moderated . SYSTEM_CM_ITEM_STATUS , CMItemStatus . APPROVED . getValue ( ) ) ;
2021-11-16 18:57:05 +01:00
}
if ( cmItemVisibility = = null ) {
cmItemVisibility = CMItemVisibility . PUBLIC ;
2021-12-02 11:50:18 +01:00
addExtraField ( jsonNode , Moderated . SYSTEM_CM_ITEM_VISIBILITY , cmItemVisibility . getValue ( ) ) ;
2021-11-16 18:57:05 +01:00
}
2021-12-15 18:03:51 +01:00
boolean privateItem = cmItemVisibility = = CMItemVisibility . RESTRICTED ? true : false ;
( ( ObjectNode ) jsonNode ) . put ( PRIVATE_KEY , privateItem ) ;
if ( privateItem ) {
( ( ObjectNode ) jsonNode ) . put ( SEARCHABLE_KEY , " True " ) ;
} else {
( ( ObjectNode ) jsonNode ) . remove ( SEARCHABLE_KEY ) ;
}
2021-11-16 18:57:05 +01:00
}
2021-11-26 12:27:31 +01:00
private void postItemCreated ( ) throws Exception {
2021-11-22 16:38:56 +01:00
try {
if ( isModerationEnabled ( ) ) {
2022-04-06 17:15:46 +02:00
moderationThread . setItemCoordinates ( itemID , name , itemTitle , itemURL ) ;
2021-11-26 12:27:31 +01:00
moderationThread . postItemCreated ( ) ;
2021-11-22 16:38:56 +01:00
}
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
2021-11-19 16:49:43 +01:00
}
2021-11-26 12:27:31 +01:00
private void postItemUpdated ( ) {
2021-11-22 16:38:56 +01:00
try {
if ( isModerationEnabled ( ) ) {
2022-04-06 17:15:46 +02:00
moderationThread . setItemCoordinates ( itemID , name , itemTitle , itemURL ) ;
2021-11-26 12:27:31 +01:00
moderationThread . postItemUpdated ( ) ;
2021-11-22 16:38:56 +01:00
}
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
2021-11-19 16:49:43 +01:00
}
@Override
public String approve ( String moderatorMessage ) {
2021-11-16 18:57:05 +01:00
try {
if ( isModerationEnabled ( ) ) {
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2021-11-16 18:57:05 +01:00
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
switch ( cmItemStatus ) {
case APPROVED :
// Nothing TO DO
break ;
case REJECTED :
throw new MethodNotSupportedException ( " You can't approve a rejected item. The item must be updated first. The update will set the item in pending, than it can be approved/rejected. " ) ;
case PENDING :
2021-12-06 17:45:15 +01:00
if ( ! ckanUser . isCatalogueModerator ( ) ) {
2021-11-16 18:57:05 +01:00
throw new MethodNotSupportedException ( " Only catalogue moderator can approve a pending item. " ) ;
}
setToApproved ( result ) ;
2022-04-11 16:10:49 +02:00
// Need to use sysadmin because the user could not have the right to modify the item
setApiKey ( CKANUtility . getSysAdminAPI ( ) ) ;
2021-12-15 18:03:51 +01:00
String ret = sendPostRequest ( ITEM_UPDATE , getAsString ( result ) ) ;
2022-04-11 16:14:33 +02:00
// Resetting the api key
setApiKey ( null ) ;
2021-11-22 16:38:56 +01:00
result = mapper . readTree ( ret ) ;
2022-04-06 17:15:46 +02:00
parseResult ( ) ;
moderationThread . setItemCoordinates ( itemID , name , itemTitle , itemURL ) ;
2021-11-26 12:27:31 +01:00
moderationThread . postItemApproved ( moderatorMessage ) ;
2021-11-23 17:53:37 +01:00
2022-02-15 09:59:02 +01:00
if ( configuration . getScopeBean ( ) . is ( Type . VRE ) ) {
2021-11-23 17:53:37 +01:00
// Actions performed after a package has been correctly created on ckan.
2022-04-06 17:15:46 +02:00
sendSocialPost ( ) ;
2021-11-22 16:38:56 +01:00
}
2021-11-23 17:53:37 +01:00
2021-11-16 18:57:05 +01:00
break ;
default :
break ;
}
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2021-11-16 18:57:05 +01:00
}
throw new MethodNotSupportedException ( " The approve operation is available only in moderation mode " ) ;
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
2021-11-19 16:49:43 +01:00
@Override
public String reject ( String moderatorMessage ) {
2021-11-16 18:57:05 +01:00
try {
if ( isModerationEnabled ( ) ) {
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2021-11-16 18:57:05 +01:00
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
switch ( cmItemStatus ) {
case APPROVED :
throw new MethodNotSupportedException ( " You can't rejected an approved item. The item must be updated first. The update will set the item in pending, than it can be approved/rejected. " ) ;
case REJECTED :
// Nothing TO DO
break ;
case PENDING :
2021-12-06 17:45:15 +01:00
if ( ! ckanUser . isCatalogueModerator ( ) ) {
2021-11-16 18:57:05 +01:00
throw new MethodNotSupportedException ( " Only catalogue moderator can reject a pending item. " ) ;
}
2021-11-22 16:38:56 +01:00
2021-11-16 18:57:05 +01:00
setToRejected ( result ) ;
2022-04-11 16:10:49 +02:00
// Need to use sysadmin because the user could not have the right to modify the item
setApiKey ( CKANUtility . getSysAdminAPI ( ) ) ;
2021-11-22 16:38:56 +01:00
String ret = sendPostRequest ( ITEM_PATCH , getAsString ( result ) ) ;
2022-04-11 16:14:33 +02:00
// Resetting the api key
setApiKey ( null ) ;
2021-11-22 16:38:56 +01:00
result = mapper . readTree ( ret ) ;
2022-04-06 17:15:46 +02:00
parseResult ( ) ;
moderationThread . setItemCoordinates ( itemID , name , itemTitle , itemURL ) ;
2021-11-26 12:27:31 +01:00
moderationThread . postItemRejected ( moderatorMessage ) ;
2021-11-16 18:57:05 +01:00
break ;
default :
break ;
}
2021-11-23 17:53:37 +01:00
return getAsCleanedString ( result ) ;
2021-11-16 18:57:05 +01:00
}
throw new MethodNotSupportedException ( " The reject operation is available only in moderation mode " ) ;
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
2021-11-19 16:49:43 +01:00
@Override
public void message ( String message ) {
2021-11-16 18:57:05 +01:00
try {
if ( isModerationEnabled ( ) ) {
2021-11-19 16:49:43 +01:00
if ( message = = null | | message . compareTo ( " " ) = = 0 ) {
2021-11-18 17:49:24 +01:00
return ;
}
2021-11-22 16:38:56 +01:00
readItem ( ) ;
2021-11-18 17:49:24 +01:00
// Catalogue Moderators are allowed to post message to the dedicated Stream
2021-12-06 17:45:15 +01:00
if ( ! ckanUser . isCatalogueModerator ( ) ) {
2021-11-18 17:49:24 +01:00
// Users that are not
if ( ! isItemCreator ( ) ) {
2021-12-02 11:50:18 +01:00
throw new NotAllowedException ( " Only item creator and " + Moderated . CATALOGUE_MODERATOR + " s are entitled to partecipate to the moderation discussion thread. " ) ;
2022-04-06 17:15:46 +02:00
} else {
moderationThread . setItemAuthor ( true ) ;
2021-11-18 17:49:24 +01:00
}
}
2021-11-22 16:38:56 +01:00
2021-11-18 17:49:24 +01:00
CMItemStatus cmItemStatus = getCMItemStatus ( ) ;
2022-04-06 17:15:46 +02:00
moderationThread . setItemCoordinates ( itemID , name , itemTitle , itemURL ) ;
2021-11-26 12:27:31 +01:00
moderationThread . postUserMessage ( cmItemStatus , message ) ;
2021-11-23 17:53:37 +01:00
return ;
2021-11-16 18:57:05 +01:00
}
throw new MethodNotSupportedException ( " The message operation is available only in moderation mode " ) ;
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
2021-12-02 11:50:18 +01:00
public String moderate ( String json ) {
try {
ModerationContent moderationContent = mapper . readValue ( json , ModerationContent . class ) ;
String message = moderationContent . getMessage ( ) ;
if ( moderationContent . getCMItemStatus ( ) ! = null ) {
CMItemStatus cmItemStatus = moderationContent . getCMItemStatus ( ) ;
switch ( cmItemStatus ) {
case APPROVED :
return approve ( message ) ;
case REJECTED :
return reject ( message ) ;
default :
throw new BadRequestException ( " Allowed moderation operations are approve, reject and message " ) ;
}
} else {
2022-04-11 16:10:49 +02:00
if ( message = = null | | message . length ( ) = = 0 ) {
2021-12-02 11:50:18 +01:00
throw new BadRequestException ( " Allowed moderation operations are approve, reject and message " ) ;
}
message ( message ) ;
return null ;
}
} catch ( WebApplicationException e ) {
throw e ;
} catch ( Exception e ) {
throw new InternalServerErrorException ( e ) ;
}
}
2021-12-20 13:46:50 +01:00
2021-12-02 11:50:18 +01:00
2018-12-04 12:06:22 +01:00
}