task_21363 #1

Closed
francesco.mangiacrapa wants to merge 53 commits from task_21363 into master
16 changed files with 539 additions and 174 deletions
Showing only changes of commit fdbf2d3a76 - Show all commits

View File

@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.0.0-SNAPSHOT] - 2021-06-15 ## [v1.0.0-SNAPSHOT] - 2022-04-04
First Release - [#21363] Implemented the ckan-content-moderator-widget
- [#20650] Provided moderator skills to Catalogue Moderator(s)
- [#23108] Provided Moderation facility accessible to Catalogue Editor/Admin (only) in read only mode

View File

@ -15,11 +15,12 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
public class CkanContentModeratorCheckConfig { public class CkanContentModeratorCheckConfig {
private int configurationLoaded = 0; private int configurationLoaded = 0;
private static final int CONFIGURATION_EXPECTED = 2; private static final int CONFIGURATION_EXPECTED = 3;
private int MAX_RETRY_ON_LOADING_CONFIG = 20; private int MAX_RETRY_ON_LOADING_CONFIG = 20;
private int attemptLC = 0; private int attemptLC = 0;
private Boolean contentModerationEnabled = null; private Boolean contentModerationEnabled = null;
private Boolean moderatorRoleAssigned = null; private Boolean moderatorRoleAssigned = null;
private Boolean existsMyItemInModeration = null;
/** /**
* Instantiates a new ckan content moderator check config. * Instantiates a new ckan content moderator check config.
@ -32,6 +33,7 @@ public class CkanContentModeratorCheckConfig {
* Check configs. * Check configs.
* *
* @param whenDone the when done * @param whenDone the when done
* @param reloadGCatConfig the reload G cat config
* @throws Exception the exception * @throws Exception the exception
*/ */
public void checkConfigs(final Command whenDone, boolean reloadGCatConfig) throws Exception { public void checkConfigs(final Command whenDone, boolean reloadGCatConfig) throws Exception {
@ -39,8 +41,8 @@ public class CkanContentModeratorCheckConfig {
configurationLoaded = 0; configurationLoaded = 0;
attemptLC = 0; attemptLC = 0;
CkanContentModeratorWidgetController.contentModeratorService CkanContentModeratorWidgetController.contentModeratorService.isModerationEnabled(reloadGCatConfig,
.isModerationEnabled(reloadGCatConfig, new AsyncCallback<Boolean>() { new AsyncCallback<Boolean>() {
@Override @Override
public void onFailure(Throwable caught) { public void onFailure(Throwable caught) {
@ -52,7 +54,7 @@ public class CkanContentModeratorCheckConfig {
@Override @Override
public void onSuccess(Boolean result) { public void onSuccess(Boolean result) {
incrementConfigurationLoaded(); incrementConfigurationLoaded();
GWT.log("isContentModeratorEnabled: "+result); GWT.log("isContentModeratorEnabled: " + result);
contentModerationEnabled = result; contentModerationEnabled = result;
} }
}); });
@ -70,12 +72,31 @@ public class CkanContentModeratorCheckConfig {
@Override @Override
public void onSuccess(Boolean result) { public void onSuccess(Boolean result) {
incrementConfigurationLoaded(); incrementConfigurationLoaded();
GWT.log("isModeratorRoleAssigned: "+result); GWT.log("isModeratorRoleAssigned: " + result);
moderatorRoleAssigned = result; moderatorRoleAssigned = result;
} }
}); });
CkanContentModeratorWidgetController.contentModeratorService
.existsMyItemInModeration(new AsyncCallback<Boolean>() {
@Override
public void onFailure(Throwable caught) {
existsMyItemInModeration = false;
incrementConfigurationLoaded();
}
@Override
public void onSuccess(Boolean result) {
incrementConfigurationLoaded();
GWT.log("existsMyItemInModeration: " + result);
existsMyItemInModeration = result;
}
});
if (whenDone != null) { if (whenDone != null) {
final Timer timer = new Timer() { final Timer timer = new Timer() {
@ -83,9 +104,10 @@ public class CkanContentModeratorCheckConfig {
@Override @Override
public void run() { public void run() {
attemptLC++; attemptLC++;
GWT.log("checking configuration loaded, attempt "+attemptLC+" of "+MAX_RETRY_ON_LOADING_CONFIG); GWT.log("checking configuration loaded, attempt " + attemptLC + " of "
+ MAX_RETRY_ON_LOADING_CONFIG);
boolean configsLoaded = getConfigurationLoaded() == CONFIGURATION_EXPECTED; boolean configsLoaded = getConfigurationLoaded() == CONFIGURATION_EXPECTED;
GWT.log("configsLoaded: "+configsLoaded); GWT.log("configsLoaded: " + configsLoaded);
if (configsLoaded) { if (configsLoaded) {
GWT.log("ContentModeratorCheckConfig loaded correclty"); GWT.log("ContentModeratorCheckConfig loaded correclty");
whenDone.execute(); whenDone.execute();
@ -159,4 +181,18 @@ public class CkanContentModeratorCheckConfig {
} }
/**
* Checks if is exists my item in moderation.
*
* @return the boolean
* @throws Exception the exception
*/
public Boolean isExistsMyItemInModeration() throws Exception {
if (existsMyItemInModeration == null)
throw new Exception(
"Please, first check if the content moderation is enabled in this context by calling checkContentModeratorConfiguration");
return existsMyItemInModeration;
}
} }

View File

@ -57,25 +57,28 @@ public interface CkanContentModeratorService extends RemoteService {
* Gets the list items for status. * Gets the list items for status.
* *
* @param theStatus the the status * @param theStatus the the status
* @param limit the limit
* @param offset the offset * @param offset the offset
* @param limit the limit
* @param restrictedToLoggedInUser the restricted to logged in user
* @return the list items for status * @return the list items for status
* @throws Exception the exception * @throws Exception the exception
*/ */
public List<CatalogueDataset> getListItemsForStatus(ItemStatus theStatus, int limit, int offset) throws Exception; public List<CatalogueDataset> getListItemsForStatus(ItemStatus theStatus, int offset, int limit,
boolean restrictedToLoggedInUser) throws Exception;
/** /**
* Gets the data for status. * Gets the data for status.
* *
* @param status the status * @param status the status
* @param startIndex the start index * @param offset the offset
* @param lenght the lenght * @param limit the limit
* @param serverIndex the server index * @param serverStartIndex the server start index
* @param restrictedToLoggedInUser the restricted to logged in user
* @return the data for status * @return the data for status
* @throws Exception the exception * @throws Exception the exception
* @par@Override am lenght the lenght
*/ */
SearchedData getDataForStatus(ItemStatus status, int startIndex, int lenght, int serverIndex) throws Exception; public SearchedData getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex,
boolean restrictedToLoggedInUser) throws Exception;
/** /**
* Approve item. * Approve item.
@ -85,7 +88,7 @@ public interface CkanContentModeratorService extends RemoteService {
* @return the operation report * @return the operation report
* @throws Exception the exception * @throws Exception the exception
*/ */
OperationReport approveItem(List<String> itemNames, String moderatorMessage) throws Exception; public OperationReport approveItem(List<String> itemNames, String moderatorMessage) throws Exception;
/** /**
* Gets the CMS roles for user in the context. * Gets the CMS roles for user in the context.
@ -93,7 +96,7 @@ public interface CkanContentModeratorService extends RemoteService {
* @return the CMS roles for user in the context * @return the CMS roles for user in the context
* @throws Exception the exception * @throws Exception the exception
*/ */
ModerationUserRole getCMSRolesForUserInTheContext() throws Exception; public ModerationUserRole getCMSRolesForUserInTheContext() throws Exception;
/** /**
* Checks if is moderation enabled. * Checks if is moderation enabled.
@ -101,13 +104,22 @@ public interface CkanContentModeratorService extends RemoteService {
* @param reloadConfig the reload config * @param reloadConfig the reload config
* @return the boolean * @return the boolean
*/ */
Boolean isModerationEnabled(boolean reloadConfig); public Boolean isModerationEnabled(boolean reloadConfig);
/** /**
* Checks if is moderator role assigned. * Checks if is moderator role assigned.
* *
* @return true, if is moderator role assigned * @return true, if is moderat@Override or role assigned
* @throws Exception * @throws Exception the exception
*/ */
Boolean isModeratorRoleAssigned() throws Exception; public Boolean isModeratorRoleAssigned() throws Exception;
/**
* Exists my item in moderation.
*
* @return true if the user has at least one item moderatorated or in
* moderation.
* @throws Exception the exception
*/
public Boolean existsMyItemInModeration() throws Exception;
} }

View File

@ -34,26 +34,28 @@ public interface CkanContentModeratorServiceAsync {
* Gets the list items for status. * Gets the list items for status.
* *
* @param theStatus the the status * @param theStatus the the status
* @param limit the limit
* @param offset the offset * @param offset the offset
* @param limit the limit
* @param restrictedToLoggedInUser the restricted to logged in user
* @param callback the callback * @param callback the callback
* @return the list items for status * @return the list items for status
*/ */
void getListItemsForStatus(ItemStatus theStatus, int limit, int offset, void getListItemsForStatus(ItemStatus theStatus, int offset, int limit, boolean restrictedToLoggedInUser,
AsyncCallback<List<CatalogueDataset>> callback); AsyncCallback<List<CatalogueDataset>> callback);
/** /**
* Gets the data for status. * Gets the data for status.
* *
* @param status the status * @param status the status
* @param startIndex the start index * @param offset the offset
* @param lenght the lenght * @param limit the limit
* @param serverIndex the server index * @param serverStartIndex the server start index
* @param restrictedToLoggedInUser the restricted to logged in user
* @param asyncCallback the async callback * @param asyncCallback the async callback
* @return the data for status * @return the data for status
*/ */
void getDataForStatus(ItemStatus status, int startIndex, int lenght, int serverIndex, void getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex,
AsyncCallback<SearchedData> asyncCallback); boolean restrictedToLoggedInUser, AsyncCallback<SearchedData> asyncCallback);
/** /**
* Approve item. * Approve item.
@ -104,4 +106,13 @@ public interface CkanContentModeratorServiceAsync {
*/ */
void isModeratorRoleAssigned(AsyncCallback<Boolean> callback); void isModeratorRoleAssigned(AsyncCallback<Boolean> callback);
/**
* Exists my item in moderation.
*
* @param callback the callback
* @return true if the user has at least one item moderatorated or in
* moderation.
*/
void existsMyItemInModeration(AsyncCallback<Boolean> callback);
} }

View File

@ -3,7 +3,7 @@ package org.gcube.portlets.widgets.ckancontentmoderator.client;
import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus;
import org.gcube.portlets.widgets.ckancontentmoderator.client.ui.table.ItemsTable.DISPLAY_FIELD; import org.gcube.portlets.widgets.ckancontentmoderator.client.ui.table.ItemsTable.DISPLAY_FIELD;
import com.google.gwt.user.client.Command; import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.ComplexPanel;
/** /**
@ -23,10 +23,12 @@ public class CkanContentModeratorWidget {
* @param status the status * @param status the status
* @param displayFields the display fields * @param displayFields the display fields
* @param sortByField the sort by field * @param sortByField the sort by field
* @param readOnlyMode the read only mode is true if the Moderator Role is not assigned
* @param restrictDataToLoggedInUser the restrict data to logged in user
*/ */
public CkanContentModeratorWidget(ItemStatus status, DISPLAY_FIELD[] displayFields, DISPLAY_FIELD sortByField, public CkanContentModeratorWidget(ItemStatus status, DISPLAY_FIELD[] displayFields, DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) {
Command onConfigurationLoaded) { GWT.log("CkanContentModeratorWidget called. ReadOnlyMode: "+readOnlyMode);
cmsController = new CkanContentModeratorWidgetController(status, displayFields, sortByField); cmsController = new CkanContentModeratorWidgetController(status, displayFields, sortByField, readOnlyMode, restrictDataToLoggedInUser);
} }

View File

@ -59,21 +59,37 @@ public class CkanContentModeratorWidgetController {
private HashMap<String, CkanShowItemFrame> mapOfItemsTabDisplayed = new HashMap<String, CkanShowItemFrame>(); private HashMap<String, CkanShowItemFrame> mapOfItemsTabDisplayed = new HashMap<String, CkanShowItemFrame>();
private boolean readOnlyMode;
/** /**
* Instantiates a new ckan content moderator widget. * Instantiates a new ckan content moderator widget.
* *
* @param status the status * @param status the status
* @param displayFields the display fields * @param displayFields the display fields
* @param sortByField the sort by field * @param sortByField the sort by field
* @param readOnlyMode the read only mode
* @param restrictDataToLoggedInUser
*/ */
public CkanContentModeratorWidgetController(ItemStatus status, DISPLAY_FIELD[] displayFields, public CkanContentModeratorWidgetController(ItemStatus status, DISPLAY_FIELD[] displayFields,
DISPLAY_FIELD sortByField) { DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) {
toolbar = new ContentModeratorToolbar(eventBus, status); toolbar = new ContentModeratorToolbar(eventBus, status);
howeView = new HomeView(eventBus, status, displayFields, sortByField);
// GWT.log("***************** HARD CODED READONLY ********************** ");
// readOnlyMode = true;
// restrictDataToLoggedInUser = readOnlyMode;
howeView = new HomeView(eventBus, status, displayFields, sortByField, readOnlyMode, restrictDataToLoggedInUser);
mainTabPanel.addHomeWidget(howeView.getPanel()); mainTabPanel.addHomeWidget(howeView.getPanel());
mainPanel.add(toolbar); mainPanel.add(toolbar);
mainPanel.add(infoPanel); mainPanel.add(infoPanel);
mainPanel.add(mainTabPanel); mainPanel.add(mainTabPanel);
this.readOnlyMode = readOnlyMode;
howeView.hideUpdateStatusAction(readOnlyMode);
howeView.hideSelectableRow(readOnlyMode);
bindEvents(); bindEvents();
} }
@ -92,12 +108,13 @@ public class CkanContentModeratorWidgetController {
// if items selected are > 0 then shows button "Update status as.." // if items selected are > 0 then shows button "Update status as.."
howeView.setVisibleUpdateStatusAction(items.size() > 0); howeView.setVisibleUpdateStatusAction(items.size() > 0);
if(howeView.getDisplayingItemStatus().equals(ItemStatus.APPROVED)) { if (howeView.getDisplayingItemStatus().equals(ItemStatus.APPROVED)) {
GWT.log("The Item Status displayed is "+ItemStatus.APPROVED +" hiding update status actions"); GWT.log("The Item Status displayed is " + ItemStatus.APPROVED
+ " hiding update status actions");
howeView.setVisibleUpdateStatusAction(false); howeView.setVisibleUpdateStatusAction(false);
} }
//If an action updated the item status we reloading it // If an action updated the item status we reloading it
reloadItemsDisplayedInTab(); reloadItemsDisplayedInTab();
} }
} }
@ -117,11 +134,6 @@ public class CkanContentModeratorWidgetController {
csif.instanceFrame(clickedDataset.getUrl()); csif.instanceFrame(clickedDataset.getUrl());
mainTabPanel.addTab(clickedDataset.getTitle(), csif); mainTabPanel.addTab(clickedDataset.getTitle(), csif);
mapOfItemsTabDisplayed.put(clickedDataset.getUrl(), csif); mapOfItemsTabDisplayed.put(clickedDataset.getUrl(), csif);
// CkanInternalFramePanel cfp = new CkanInternalFramePanel(eventBus);
// cfp.instanceFrame(clickedDataset.getUrl());
// mainTabPanel.addTab(clickedDataset.getTitle(), cfp);
} }
} }
} }
@ -207,6 +219,9 @@ public class CkanContentModeratorWidgetController {
}); });
} }
/**
* Reload items displayed in tab.
*/
private void reloadItemsDisplayedInTab() { private void reloadItemsDisplayedInTab() {
for (String datasetURL : mapOfItemsTabDisplayed.keySet()) { for (String datasetURL : mapOfItemsTabDisplayed.keySet()) {
@ -215,6 +230,12 @@ public class CkanContentModeratorWidgetController {
} }
} }
/**
* Show message.
*
* @param msg the msg
* @param alertType the alert type
*/
private void showMessage(String msg, AlertType alertType) { private void showMessage(String msg, AlertType alertType) {
final Alert alert = new Alert(msg); final Alert alert = new Alert(msg);
@ -245,4 +266,13 @@ public class CkanContentModeratorWidgetController {
return mainPanel; return mainPanel;
} }
/**
* Checks if is read only mode.
*
* @return true, if is read only mode
*/
public boolean isReadOnlyMode() {
return readOnlyMode;
}
} }

View File

@ -1,22 +1,22 @@
package org.gcube.portlets.widgets.ckancontentmoderator.client; //package org.gcube.portlets.widgets.ckancontentmoderator.client;
//
import com.google.gwt.core.client.EntryPoint; //import com.google.gwt.core.client.EntryPoint;
//
/** ///**
* Entry point classes define <code>onModuleLoad()</code>. // * Entry point classes define <code>onModuleLoad()</code>.
*/ // */
public class CkanContentModeratorWidgetEntryPoint implements EntryPoint { //public class CkanContentModeratorWidgetEntryPoint implements EntryPoint {
/** // /**
* The message displayed to the user when the server cannot be reached or // * The message displayed to the user when the server cannot be reached or
* returns an error. // * returns an error.
*/ // */
private static final String SERVER_ERROR = "An error occurred while " // private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network " + "connection and try again."; // + "attempting to contact the server. Please check your network " + "connection and try again.";
//
/** // /**
* This is the entry point method. // * This is the entry point method.
*/ // */
public void onModuleLoad() { // public void onModuleLoad() {
} // }
//
} //}

View File

@ -13,4 +13,6 @@ public class ContentModeratorWidgetConstants {
public static int ITEMS_PER_PAGE = 10; public static int ITEMS_PER_PAGE = 10;
public static int ITEM_START_INDEX = 0; public static int ITEM_START_INDEX = 0;
public static String CKAN_FIELD_NAME_AUTHOR_MAIL = "author_email";
} }

View File

@ -7,12 +7,13 @@
font-weight: bold; font-weight: bold;
} }
.asBar { .as_simple_link {
background-color: none !important; background: none;
border: none;
} }
</ui:style> </ui:style>
<g:HTMLPanel> <g:HTMLPanel>
<b:AlertBlock close="false" addStyleNames="{style.asBar}" ui:field="alertBlockNav"> <b:AlertBlock close="false" addStyleNames="as_simple_link" ui:field="alertBlockNav">
<b:Button ui:field="button_reload" title="Reload the page" type="LINK">Reload</b:Button> <b:Button ui:field="button_reload" title="Reload the page" type="LINK">Reload</b:Button>
</b:AlertBlock> </b:AlertBlock>
<g:HTMLPanel ui:field="panel_container"> <g:HTMLPanel ui:field="panel_container">

View File

@ -19,6 +19,7 @@ import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.cellview.client.SimplePager; import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation; import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
@ -54,6 +55,7 @@ public class ContentModeratorPaginatedView {
private ItemStatus itemStatus; private ItemStatus itemStatus;
private int serverStartIndex; private int serverStartIndex;
private HandlerManager eventBus; private HandlerManager eventBus;
private boolean restrictDataToLoggedInUser;
/** /**
* Instantiates a new content moderator paginated view. * Instantiates a new content moderator paginated view.
@ -62,10 +64,12 @@ public class ContentModeratorPaginatedView {
* @param theStatus the the status * @param theStatus the the status
* @param displayFields the display fields * @param displayFields the display fields
* @param sortByField the sort by field * @param sortByField the sort by field
* @param restrictDataToLoggedInUser the restrict data to logged in user
*/ */
public ContentModeratorPaginatedView(HandlerManager eventbus, ItemStatus theStatus, DISPLAY_FIELD[] displayFields, public ContentModeratorPaginatedView(HandlerManager eventbus, ItemStatus theStatus, DISPLAY_FIELD[] displayFields,
DISPLAY_FIELD sortByField) { DISPLAY_FIELD sortByField, boolean restrictDataToLoggedInUser) {
this.itemStatus = theStatus; this.itemStatus = theStatus;
this.restrictDataToLoggedInUser = restrictDataToLoggedInUser;
this.initClassFirstRangeChanged = true; this.initClassFirstRangeChanged = true;
this.eventBus = eventbus; this.eventBus = eventbus;
itemsTable = new ItemsTable<CatalogueDataset>(eventbus, displayFields, sortByField); itemsTable = new ItemsTable<CatalogueDataset>(eventbus, displayFields, sortByField);
@ -237,7 +241,7 @@ public class ContentModeratorPaginatedView {
+ ", serverIndex:" + serverIndex + "]"); + ", serverIndex:" + serverIndex + "]");
CkanContentModeratorWidgetController.contentModeratorService.getDataForStatus(status, offset, limit, CkanContentModeratorWidgetController.contentModeratorService.getDataForStatus(status, offset, limit,
serverIndex, new AsyncCallback<SearchedData>() { serverIndex, restrictDataToLoggedInUser, new AsyncCallback<SearchedData>() {
@Override @Override
public void onSuccess(SearchedData result) { public void onSuccess(SearchedData result) {
@ -317,4 +321,13 @@ public class ContentModeratorPaginatedView {
} }
public void hideSelectableRow(boolean bool) {
Element tableEl = itemsTable.getCellTable().getElement();
if (bool)
tableEl.addClassName("hide_checkbox");
else
tableEl.removeClassName("hide_checkbox");
}
} }

View File

@ -36,6 +36,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
@ -73,6 +74,9 @@ public class HomeView extends Composite {
@UiField @UiField
Button permanentlyDelete; Button permanentlyDelete;
@UiField
HorizontalPanel updateStatusActionPanel;
private ScrollPanel confirmPanelContainer = new ScrollPanel(); private ScrollPanel confirmPanelContainer = new ScrollPanel();
private List<NavLink> setStatusOptions = new ArrayList<NavLink>(); private List<NavLink> setStatusOptions = new ArrayList<NavLink>();
@ -82,6 +86,8 @@ public class HomeView extends Composite {
private HandlerManager eventBus; private HandlerManager eventBus;
private LoadingPanel actionInProgressLoader = new LoadingPanel(new HTML("Performing action...")); private LoadingPanel actionInProgressLoader = new LoadingPanel(new HTML("Performing action..."));
private boolean readOnlyMode;
private boolean restrictDataToLoggedInUser;
/** /**
* The Interface HomeViewUiBinder. * The Interface HomeViewUiBinder.
@ -100,13 +106,18 @@ public class HomeView extends Composite {
* @param status the status * @param status the status
* @param displayFields the display fields * @param displayFields the display fields
* @param sortByField the sort by field * @param sortByField the sort by field
* @param readOnlyMode the read only mode
* @param restrictDataToLoggedInUser the restrict data to logged in user
*/ */
public HomeView(HandlerManager eventBus, ItemStatus status, DISPLAY_FIELD[] displayFields, public HomeView(HandlerManager eventBus, ItemStatus status, DISPLAY_FIELD[] displayFields,
DISPLAY_FIELD sortByField) { DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) {
initWidget(uiBinder.createAndBindUi(this)); initWidget(uiBinder.createAndBindUi(this));
setDisplayingWithStatus(status); setDisplayingWithStatus(status);
this.eventBus = eventBus; this.eventBus = eventBus;
paginatedView = new ContentModeratorPaginatedView(eventBus, status, displayFields, sortByField); this.readOnlyMode = readOnlyMode;
this.restrictDataToLoggedInUser = restrictDataToLoggedInUser;
paginatedView = new ContentModeratorPaginatedView(eventBus, status, displayFields, sortByField,
restrictDataToLoggedInUser);
cmsPanel.addToCenter(paginatedView.getCellPanel()); cmsPanel.addToCenter(paginatedView.getCellPanel());
cmsPanel.addToBottom(paginatedView.getPagerPanel()); cmsPanel.addToBottom(paginatedView.getPagerPanel());
panelContainer.add(cmsPanel.getPanel()); panelContainer.add(cmsPanel.getPanel());
@ -130,13 +141,20 @@ public class HomeView extends Composite {
} }
/**
* Show action loader.
*
* @param showActionInProgress the show action in progress
*/
private void showActionLoader(boolean showActionInProgress) { private void showActionLoader(boolean showActionInProgress) {
GWT.log("Show action in progress: "+showActionInProgress); GWT.log("Show action in progress: " + showActionInProgress);
actionLoaderPanel.setVisible(showActionInProgress); actionLoaderPanel.setVisible(showActionInProgress);
} }
/** /**
* Sets the status options according to item status selected * Sets the status options according to item status selected.
*
* @param selectedStatus the new status options
*/ */
private void setStatusOptions(ItemStatus selectedStatus) { private void setStatusOptions(ItemStatus selectedStatus) {
@ -148,16 +166,16 @@ public class HomeView extends Composite {
navLink.setVisible(false); navLink.setVisible(false);
} }
//Hiding the changing REJECT -> APPROVED // Hiding the changing REJECT -> APPROVED
//One item REJECT must be only updated to return to PENDING status // One item REJECT must be only updated to return to PENDING status
if(selectedStatus.equals(ItemStatus.REJECTED)) { if (selectedStatus.equals(ItemStatus.REJECTED)) {
if (navLink.getText().trim().equals(ItemStatus.APPROVED.getLabel())) { if (navLink.getText().trim().equals(ItemStatus.APPROVED.getLabel())) {
navLink.setVisible(false); navLink.setVisible(false);
} }
} }
//Hiding the changing of any status from the APPROVED // Hiding the changing of any status from the APPROVED
if(selectedStatus.equals(ItemStatus.APPROVED)) { if (selectedStatus.equals(ItemStatus.APPROVED)) {
navLink.setVisible(false); navLink.setVisible(false);
} }
@ -343,7 +361,8 @@ public class HomeView extends Composite {
showActionLoader(true); showActionLoader(true);
List<String> listDatasetNames = UtilFunct.toListDatasetNames(doActionCMS.getListSelectItems()); List<String> listDatasetNames = UtilFunct.toListDatasetNames(doActionCMS.getListSelectItems());
CkanContentModeratorWidgetController.contentModeratorService.permanentlyDelete(listDatasetNames, new AsyncCallback<OperationReport>() { CkanContentModeratorWidgetController.contentModeratorService.permanentlyDelete(listDatasetNames,
new AsyncCallback<OperationReport>() {
@Override @Override
public void onFailure(Throwable caught) { public void onFailure(Throwable caught) {
@ -374,13 +393,14 @@ public class HomeView extends Composite {
if (errorCount > 0) { if (errorCount > 0) {
msg += " <br/>Error occurred on deleting permanently " + errorCount + " item/s:"; msg += " <br/>Error occurred on deleting permanently " + errorCount + " item/s:";
for (String key : result.getErrorMapItems().keySet()) { for (String key : result.getErrorMapItems().keySet()) {
msg += "<br/> "+ key+". Error: "+ result.getErrorMapItems().get(key); msg += "<br/> " + key + ". Error: " + result.getErrorMapItems().get(key);
} }
alert = AlertType.WARNING; alert = AlertType.WARNING;
} }
eventBus.fireEvent(new SelectItemsWithItemStatusEvent(displayingItemStatus, msg, alert)); eventBus.fireEvent(
new SelectItemsWithItemStatusEvent(displayingItemStatus, msg, alert));
} }
}); });
@ -457,7 +477,7 @@ public class HomeView extends Composite {
if (errorCount > 0) { if (errorCount > 0) {
msg += " <br/>Error occurred on updating status to " + errorCount + " item/s:"; msg += " <br/>Error occurred on updating status to " + errorCount + " item/s:";
for (String key : result.getErrorMapItems().keySet()) { for (String key : result.getErrorMapItems().keySet()) {
msg += "<br/> "+ key+". Error: "+ result.getErrorMapItems().get(key); msg += "<br/> " + key + ". Error: " + result.getErrorMapItems().get(key);
} }
alert = AlertType.WARNING; alert = AlertType.WARNING;
@ -512,7 +532,7 @@ public class HomeView extends Composite {
if (errorCount > 0) { if (errorCount > 0) {
msg += " <br/>Error occurred on approving " + errorCount + " item/s:"; msg += " <br/>Error occurred on approving " + errorCount + " item/s:";
for (String key : result.getErrorMapItems().keySet()) { for (String key : result.getErrorMapItems().keySet()) {
msg += "<br/> "+ key+". Error: "+ result.getErrorMapItems().get(key); msg += "<br/> " + key + ". Error: " + result.getErrorMapItems().get(key);
} }
alert = AlertType.WARNING; alert = AlertType.WARNING;
@ -554,10 +574,9 @@ public class HomeView extends Composite {
boolean isPermanentlyDelete = doActionCMSView.isPermanentlyDelete(); boolean isPermanentlyDelete = doActionCMSView.isPermanentlyDelete();
if(isPermanentlyDelete) { if (isPermanentlyDelete) {
msg += " deleted permanently from Catalogue"; msg += " deleted permanently from Catalogue";
} } else {
else {
msg += " moved to " + toStatus + " status."; msg += " moved to " + toStatus + " status.";
} }
} }
@ -566,7 +585,7 @@ public class HomeView extends Composite {
if (errorCount > 0) { if (errorCount > 0) {
msg += " <br/>Error occurred on rejecting " + errorCount + " item/s:"; msg += " <br/>Error occurred on rejecting " + errorCount + " item/s:";
for (String key : result.getErrorMapItems().keySet()) { for (String key : result.getErrorMapItems().keySet()) {
msg += "<br/> "+ key+". Error: "+ result.getErrorMapItems().get(key); msg += "<br/> " + key + ". Error: " + result.getErrorMapItems().get(key);
} }
alert = AlertType.WARNING; alert = AlertType.WARNING;
@ -584,8 +603,49 @@ public class HomeView extends Composite {
} }
} }
/**
* Gets the displaying item status.
*
* @return the displaying item status
*/
public ItemStatus getDisplayingItemStatus() { public ItemStatus getDisplayingItemStatus() {
return displayingItemStatus; return displayingItemStatus;
} }
/**
* Hide update status action.
*
* @param readOnlyMode the read only mode
*/
public void hideUpdateStatusAction(boolean readOnlyMode) {
updateStatusActionPanel.setVisible(!readOnlyMode);
}
/**
* Hide selectable row.
*
* @param bool the bool
*/
public void hideSelectableRow(boolean bool) {
paginatedView.hideSelectableRow(bool);
}
/**
* Checks if is read only mode.
*
* @return true, if is read only mode
*/
public boolean isReadOnlyMode() {
return readOnlyMode;
}
/**
* Checks if is restrict data to logged in user.
*
* @return true, if is restrict data to logged in user
*/
public boolean isRestrictDataToLoggedInUser() {
return restrictDataToLoggedInUser;
}
} }

View File

@ -42,7 +42,7 @@
<b:Heading ui:field="pageHeader" size="4" <b:Heading ui:field="pageHeader" size="4"
addStyleNames="{style.headinghome}">Items with status: </b:Heading> addStyleNames="{style.headinghome}">Items with status: </b:Heading>
<g:HorizontalPanel <g:HorizontalPanel
addStyleNames="{style.font-size-14}"> addStyleNames="{style.font-size-14}" ui:field="updateStatusActionPanel">
<b:CheckBox ui:field="cbSelectAll" <b:CheckBox ui:field="cbSelectAll"
addStyleNames="{style.margin-left-5}"></b:CheckBox> addStyleNames="{style.margin-left-5}"></b:CheckBox>
<b:Nav> <b:Nav>

View File

@ -22,8 +22,17 @@
vertical-align: middle !important; vertical-align: middle !important;
} }
.hide_checkbox input[type="checkbox"] {
display: none;
}
/***** WS EXPLORER DOCK PANEL - CENTER FLOW PANEL *****/ /***** WS EXPLORER DOCK PANEL - CENTER FLOW PANEL *****/
.we-dock-center-panel { .we-dock-center-panel {
overflow-y: auto !important; overflow-y: auto !important;
/* border: 1px solid #DDD; */ /* border: 1px solid #DDD; */
} }
.as_simple_link {
background: none;
border: none;
}

View File

@ -7,11 +7,14 @@ import java.util.Map;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.utillibrary.gcat.GCatCaller;
import org.gcube.datacatalogue.utillibrary.server.DataCatalogueImpl; import org.gcube.datacatalogue.utillibrary.server.DataCatalogueImpl;
import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem; import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem;
import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset; import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset;
import org.gcube.portlets.widgets.ckancontentmoderator.client.CkanContentModeratorService; import org.gcube.portlets.widgets.ckancontentmoderator.client.CkanContentModeratorService;
import org.gcube.portlets.widgets.ckancontentmoderator.client.ContentModeratorWidgetConstants;
import org.gcube.portlets.widgets.ckancontentmoderator.server.CkanContentModeratorUtil.QUERY_OPERATOR;
import org.gcube.portlets.widgets.ckancontentmoderator.shared.CMSUserRole; import org.gcube.portlets.widgets.ckancontentmoderator.shared.CMSUserRole;
import org.gcube.portlets.widgets.ckancontentmoderator.shared.CatalogueDataset; import org.gcube.portlets.widgets.ckancontentmoderator.shared.CatalogueDataset;
import org.gcube.portlets.widgets.ckancontentmoderator.shared.ModerationUserRole; import org.gcube.portlets.widgets.ckancontentmoderator.shared.ModerationUserRole;
@ -73,6 +76,63 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem
return isCatalogueModerator; return isCatalogueModerator;
} }
/**
* Exists my item in moderation.
*
* @return true if the user has at least one item moderatorated or in
* moderation.
* @throws Exception the exception
*/
@Override
public Boolean existsMyItemInModeration() throws Exception {
LOG.info("called existsMyItemInModeration");
try {
/*
* if(!GcubeContextUtil.isWithinPortal()) {
* LOG.warn("#### DEV MODE ENABLED #######"); boolean defaultValue = true;
* LOG.info("DEV MODE: existsMyItemInModeration returning: " + defaultValue);
* return defaultValue; }
*/
String scope = setContexts();
DataCatalogueImpl catalogueImpl = CatalogueCMSFactory.getFactory().getCatalogueImplPerScope(scope);
GCubeUser user = GcubeContextUtil.getCurrentUser(getThreadLocalRequest());
String valueOfQueryEmails = CkanContentModeratorUtil.userQueryForEmails(user, QUERY_OPERATOR.OR);
/// BUILDING MODERATION_STATUS QUERY
String system_cm_prefix = GCatCaller.MODERATOR_ITEM_STATUS_FIELD_NAME;
StringBuilder queryValuesBuilder = new StringBuilder();
// QUERYING AUTHOR_MAIL MUST BE IN LIST OF EMAIL
queryValuesBuilder
.append(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL + ":" + valueOfQueryEmails);
queryValuesBuilder.append(" AND ");
// QUERYING THE ITEM MUST HAVE THE MODERATIONS STATUS
queryValuesBuilder.append("extras_" + system_cm_prefix + ":*");
Map<String, String> query = new HashMap<String, String>(1);
query.put("q", queryValuesBuilder.toString());
String listItems = catalogueImpl.performQuery(query);
LOG.debug("query returned items: " + listItems);
boolean haveItemInModeration = false;
if (listItems != null && !listItems.isEmpty()) {
haveItemInModeration = true;
}
LOG.info("existsMyItemInModeration returning: " + haveItemInModeration);
return haveItemInModeration;
} catch (Exception e) {
LOG.error("Error occured on checking existsMyItemInModeration, so returning false", e);
return false;
}
}
/** /**
* Gets the CMS roles for user in the context. * Gets the CMS roles for user in the context.
* *
@ -111,19 +171,31 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem
* @param theStatus the the status * @param theStatus the the status
* @param offset the offset * @param offset the offset
* @param limit the limit * @param limit the limit
* @param restrictedToLoggedInUser if true restricts the list of items to logged
* in user
* @return the list items for status * @return the list items for status
* @throws Exception the exception * @throws Exception the exception
*/ */
@Override @Override
public List<CatalogueDataset> getListItemsForStatus(ItemStatus theStatus, int offset, int limit) throws Exception { public List<CatalogueDataset> getListItemsForStatus(ItemStatus theStatus, int offset, int limit,
LOG.info("called getListItemsForStatus with [status: " + theStatus + ", offset: " + offset + "], [limit: " boolean restrictedToLoggedInUser) throws Exception {
+ limit + "]"); LOG.info("called getListItemsForStatus with [status: " + theStatus + ", offset: " + offset + ", limit: " + limit
+ ", restrictedToLoggedInUser: " + restrictedToLoggedInUser + "]");
List<CatalogueDataset> datasetList = null; List<CatalogueDataset> datasetList = null;
try { try {
String scope = setContexts(); String scope = setContexts();
DataCatalogueImpl catalogueImpl = CatalogueCMSFactory.getFactory().getCatalogueImplPerScope(scope); DataCatalogueImpl catalogueImpl = CatalogueCMSFactory.getFactory().getCatalogueImplPerScope(scope);
CatalogueContentModeratorSystem cmsInstance = catalogueImpl.getCatalogueContentModerator(); CatalogueContentModeratorSystem cmsInstance = catalogueImpl.getCatalogueContentModerator();
List<CkanDataset> datasets = cmsInstance.getListItemsForStatus(theStatus, limit, offset);
Map<String, String> filters = null;
if (restrictedToLoggedInUser) {
filters = new HashMap<String, String>(1);
GCubeUser user = GcubeContextUtil.getCurrentUser(getThreadLocalRequest());
String valueOfQueryEmails = CkanContentModeratorUtil.userQueryForEmails(user, QUERY_OPERATOR.OR);
filters.put(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL, valueOfQueryEmails);
}
List<CkanDataset> datasets = cmsInstance.getListItemsForStatus(theStatus, limit, offset, filters);
if (datasets != null) { if (datasets != null) {
int size = datasets.size(); int size = datasets.size();
datasetList = new ArrayList<CatalogueDataset>(size); datasetList = new ArrayList<CatalogueDataset>(size);
@ -306,8 +378,8 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem
* @throws Exception the exception * @throws Exception the exception
*/ */
@Override @Override
public SearchedData getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex) public SearchedData getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex,
throws Exception { boolean restrictedToLoggedInUser) throws Exception {
LOG.info("called getDataForStatus [status: " + status + ", offset: " + offset + ", limit: " + limit LOG.info("called getDataForStatus [status: " + status + ", offset: " + offset + ", limit: " + limit
+ ", serverIndex: " + serverStartIndex); + ", serverIndex: " + serverStartIndex);
@ -315,16 +387,25 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem
int searchStartIndex = offset; int searchStartIndex = offset;
CatalogueContentModeratorSystem cmsInstance = CatalogueCMSFactory.getFactory().getCMSPerScope(scope); CatalogueContentModeratorSystem cmsInstance = CatalogueCMSFactory.getFactory().getCMSPerScope(scope);
SearchedData searchedData = new SearchedData(offset, limit, searchStartIndex, false); SearchedData searchedData = new SearchedData(offset, limit, searchStartIndex, false);
long totalItemsForStatus = cmsInstance.countListItemsForStatus(status);
Map<String, String> filters = null;
if (restrictedToLoggedInUser) {
filters = new HashMap<String, String>(1);
GCubeUser user = GcubeContextUtil.getCurrentUser(getThreadLocalRequest());
String valueOfQueryEmails = CkanContentModeratorUtil.userQueryForEmails(user, QUERY_OPERATOR.OR);
filters.put(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL, valueOfQueryEmails);
}
long totalItemsForStatus = cmsInstance.countListItemsForStatus(status, filters);
LOG.info("totalItemsForStatus " + status + " are : " + totalItemsForStatus); LOG.info("totalItemsForStatus " + status + " are : " + totalItemsForStatus);
List<CatalogueDataset> listDataset = new ArrayList<CatalogueDataset>(); List<CatalogueDataset> listDataset = new ArrayList<CatalogueDataset>();
try { try {
LOG.debug("getListItemsForStatus with searchStartIndex: " + searchStartIndex + ", limit: " + limit); LOG.debug("getListItemsForStatus with searchStartIndex: " + searchStartIndex + ", limit: " + limit);
listDataset = getListItemsForStatus(status, searchStartIndex, limit); listDataset = getListItemsForStatus(status, searchStartIndex, limit, restrictedToLoggedInUser);
} catch (Exception e) { } catch (Exception e) {
String error = "Error occurred on getting items for status: " + status; String error = "Error occurred on getting items for status: " + status;
LOG.error(error, e); LOG.error(error, e);
throw new Exception(error+". Cause: "+e.getMessage()); throw new Exception(error + ". Cause: " + e.getMessage());
} }
int listDatasetSize = listDataset.size(); int listDatasetSize = listDataset.size();

View File

@ -0,0 +1,102 @@
package org.gcube.portlets.widgets.ckancontentmoderator.server;
import java.util.ArrayList;
import java.util.List;
import org.gcube.vomanagement.usermanagement.model.Email;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Class CkanContentModeratorUtil.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Apr 6, 2022
*/
public class CkanContentModeratorUtil {
private static Logger LOG = LoggerFactory.getLogger(CkanContentModeratorUtil.class);
public static enum QUERY_OPERATOR {
AND, OR
}
/**
* User query for emails.
*
* @param user the user
* @return the string representing the value of the query for filtering for User
* Mails
* @throws Exception the exception
*/
public static String userQueryForEmails(GCubeUser user, QUERY_OPERATOR operator) throws Exception {
LOG.debug("userQueryForEmails called for user {}", user);
List<Email> listServerEmails = user.getEmailAddresses();
LOG.debug("List server mails: {}", listServerEmails);
List<String> emailsAddresses = new ArrayList<String>();
boolean notFoundMail = listServerEmails == null || listServerEmails.isEmpty();
if (notFoundMail) {
LOG.warn("No list mail found in " + GCubeUser.class.getSimpleName() + " getEmailAddresses()");
String mail = user.getEmail();
LOG.debug("Read mail: " + mail);
if (mail != null && !mail.isEmpty()) {
LOG.info("Email found in " + GCubeUser.class.getSimpleName() + " getEmail()");
emailsAddresses.add(mail);
}
} else {
for (Email email : listServerEmails) {
emailsAddresses.add(email.getEmail());
}
}
LOG.info("Email/s found for user {} is/are: {}", user.getUsername(), emailsAddresses);
if (emailsAddresses.isEmpty()) {
throw new Exception("No email found for user: " + user.getUsername());
}
if (operator == null)
operator = QUERY_OPERATOR.OR;
StringBuilder queryMails = new StringBuilder();
String queryOperator = operator.name();
// BUILDING EMAILS QUERY
int numberOfEmails = emailsAddresses.size();
String theQuery = "";
// case 1 email address
if (numberOfEmails == 1) {
theQuery = "'" + emailsAddresses.get(0) + "'";
} else {
// case N > 1 email addresses
for (int i = 0; i < emailsAddresses.size() - 1; i++) {
String email = emailsAddresses.get(i);
if (i == 0) {
// opening the query and adding first email address
queryMails.append("('" + email + "'");
} else {
// adding the operator and the email address
queryMails.append(" " + queryOperator + " '" + email + "'");
}
}
theQuery = queryMails.toString();
// to be sure that endsWith Operator
if (!theQuery.endsWith(queryOperator)) {
theQuery += " " + queryOperator + " ";
}
// adding last email address and closing the query
theQuery += "'" + emailsAddresses.get(numberOfEmails - 1) + "')";
}
return theQuery;
}
}

View File

@ -2,14 +2,16 @@ package org.gcube.portlets.widgets.ckancontentmoderator.server;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem; import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem;
import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus;
import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset; import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset;
import org.junit.Test; import org.gcube.portlets.widgets.ckancontentmoderator.client.ContentModeratorWidgetConstants;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class CkanContentModeratorServiceTest { public class CkanContentModeratorServiceTest {
@ -33,7 +35,9 @@ public class CkanContentModeratorServiceTest {
ItemStatus itemStatus = ItemStatus.PENDING; ItemStatus itemStatus = ItemStatus.PENDING;
try { try {
CatalogueContentModeratorSystem cms = CatalogueCMSFactory.getFactory().getCMSPerScope(scope); CatalogueContentModeratorSystem cms = CatalogueCMSFactory.getFactory().getCMSPerScope(scope);
List<CkanDataset> items = cms.getListItemsForStatus(itemStatus, 20, 0); Map<String, String> filters = new HashMap<String, String>(1);
filters.put(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL, "francesco.mangiacrapa@isti.cnr.it");
List<CkanDataset> items = cms.getListItemsForStatus(itemStatus, 20, 0, filters);
int i = 0; int i = 0;
System.out.println("Datasets with status "+itemStatus+" are: "+items.size()); System.out.println("Datasets with status "+itemStatus+" are: "+items.size());
for (CkanDataset ckanDataset : items) { for (CkanDataset ckanDataset : items) {