diff --git a/CHANGELOG.md b/CHANGELOG.md index 3325b51..975282f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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). -## [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 diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorCheckConfig.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorCheckConfig.java index 3c36cf9..7e5351e 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorCheckConfig.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorCheckConfig.java @@ -15,11 +15,12 @@ import com.google.gwt.user.client.rpc.AsyncCallback; public class CkanContentModeratorCheckConfig { 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 attemptLC = 0; private Boolean contentModerationEnabled = null; private Boolean moderatorRoleAssigned = null; + private Boolean existsMyItemInModeration = null; /** * Instantiates a new ckan content moderator check config. @@ -31,7 +32,8 @@ public class CkanContentModeratorCheckConfig { /** * Check configs. * - * @param whenDone the when done + * @param whenDone the when done + * @param reloadGCatConfig the reload G cat config * @throws Exception the exception */ public void checkConfigs(final Command whenDone, boolean reloadGCatConfig) throws Exception { @@ -39,8 +41,8 @@ public class CkanContentModeratorCheckConfig { configurationLoaded = 0; attemptLC = 0; - CkanContentModeratorWidgetController.contentModeratorService - .isModerationEnabled(reloadGCatConfig, new AsyncCallback() { + CkanContentModeratorWidgetController.contentModeratorService.isModerationEnabled(reloadGCatConfig, + new AsyncCallback() { @Override public void onFailure(Throwable caught) { @@ -52,7 +54,7 @@ public class CkanContentModeratorCheckConfig { @Override public void onSuccess(Boolean result) { incrementConfigurationLoaded(); - GWT.log("isContentModeratorEnabled: "+result); + GWT.log("isContentModeratorEnabled: " + result); contentModerationEnabled = result; } }); @@ -70,12 +72,31 @@ public class CkanContentModeratorCheckConfig { @Override public void onSuccess(Boolean result) { incrementConfigurationLoaded(); - GWT.log("isModeratorRoleAssigned: "+result); + GWT.log("isModeratorRoleAssigned: " + result); moderatorRoleAssigned = result; } }); + CkanContentModeratorWidgetController.contentModeratorService + .existsMyItemInModeration(new AsyncCallback() { + + @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) { final Timer timer = new Timer() { @@ -83,9 +104,10 @@ public class CkanContentModeratorCheckConfig { @Override public void run() { 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; - GWT.log("configsLoaded: "+configsLoaded); + GWT.log("configsLoaded: " + configsLoaded); if (configsLoaded) { GWT.log("ContentModeratorCheckConfig loaded correclty"); 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; + } + } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorService.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorService.java index 8326861..d911e69 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorService.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorService.java @@ -56,26 +56,29 @@ public interface CkanContentModeratorService extends RemoteService { /** * Gets the list items for status. * - * @param theStatus the the status - * @param limit the limit - * @param offset the offset + * @param theStatus the the status + * @param offset the offset + * @param limit the limit + * @param restrictedToLoggedInUser the restricted to logged in user * @return the list items for status * @throws Exception the exception */ - public List getListItemsForStatus(ItemStatus theStatus, int limit, int offset) throws Exception; + public List getListItemsForStatus(ItemStatus theStatus, int offset, int limit, + boolean restrictedToLoggedInUser) throws Exception; /** * Gets the data for status. * - * @param status the status - * @param startIndex the start index - * @param lenght the lenght - * @param serverIndex the server index + * @param status the status + * @param offset the offset + * @param limit the limit + * @param serverStartIndex the server start index + * @param restrictedToLoggedInUser the restricted to logged in user * @return the data for status * @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. @@ -85,7 +88,7 @@ public interface CkanContentModeratorService extends RemoteService { * @return the operation report * @throws Exception the exception */ - OperationReport approveItem(List itemNames, String moderatorMessage) throws Exception; + public OperationReport approveItem(List itemNames, String moderatorMessage) throws Exception; /** * 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 * @throws Exception the exception */ - ModerationUserRole getCMSRolesForUserInTheContext() throws Exception; + public ModerationUserRole getCMSRolesForUserInTheContext() throws Exception; /** * Checks if is moderation enabled. @@ -101,13 +104,22 @@ public interface CkanContentModeratorService extends RemoteService { * @param reloadConfig the reload config * @return the boolean */ - Boolean isModerationEnabled(boolean reloadConfig); + public Boolean isModerationEnabled(boolean reloadConfig); /** * Checks if is moderator role assigned. * - * @return true, if is moderator role assigned - * @throws Exception + * @return true, if is moderat@Override or role assigned + * @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; } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorServiceAsync.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorServiceAsync.java index 8c85577..3432856 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorServiceAsync.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorServiceAsync.java @@ -33,27 +33,29 @@ public interface CkanContentModeratorServiceAsync { /** * Gets the list items for status. * - * @param theStatus the the status - * @param limit the limit - * @param offset the offset - * @param callback the callback + * @param theStatus the the status + * @param offset the offset + * @param limit the limit + * @param restrictedToLoggedInUser the restricted to logged in user + * @param callback the callback * @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> callback); /** * Gets the data for status. * - * @param status the status - * @param startIndex the start index - * @param lenght the lenght - * @param serverIndex the server index - * @param asyncCallback the async callback + * @param status the status + * @param offset the offset + * @param limit the limit + * @param serverStartIndex the server start index + * @param restrictedToLoggedInUser the restricted to logged in user + * @param asyncCallback the async callback * @return the data for status */ - void getDataForStatus(ItemStatus status, int startIndex, int lenght, int serverIndex, - AsyncCallback asyncCallback); + void getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex, + boolean restrictedToLoggedInUser, AsyncCallback asyncCallback); /** * Approve item. @@ -104,4 +106,13 @@ public interface CkanContentModeratorServiceAsync { */ void isModeratorRoleAssigned(AsyncCallback 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 callback); + } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidget.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidget.java index a0b86d1..6abaa57 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidget.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidget.java @@ -3,7 +3,7 @@ package org.gcube.portlets.widgets.ckancontentmoderator.client; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; 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; /** @@ -23,10 +23,12 @@ public class CkanContentModeratorWidget { * @param status the status * @param displayFields the display fields * @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, - Command onConfigurationLoaded) { - cmsController = new CkanContentModeratorWidgetController(status, displayFields, sortByField); + public CkanContentModeratorWidget(ItemStatus status, DISPLAY_FIELD[] displayFields, DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) { + GWT.log("CkanContentModeratorWidget called. ReadOnlyMode: "+readOnlyMode); + cmsController = new CkanContentModeratorWidgetController(status, displayFields, sortByField, readOnlyMode, restrictDataToLoggedInUser); } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetController.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetController.java index d2d8e91..f3a2b4a 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetController.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetController.java @@ -56,24 +56,40 @@ public class CkanContentModeratorWidgetController { public final static HandlerManager eventBus = new HandlerManager(null); private HomeView howeView; - + private HashMap mapOfItemsTabDisplayed = new HashMap(); + private boolean readOnlyMode; + /** * Instantiates a new ckan content moderator widget. * * @param status the status * @param displayFields the display fields * @param sortByField the sort by field + * @param readOnlyMode the read only mode + * @param restrictDataToLoggedInUser */ public CkanContentModeratorWidgetController(ItemStatus status, DISPLAY_FIELD[] displayFields, - DISPLAY_FIELD sortByField) { + DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) { 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()); mainPanel.add(toolbar); mainPanel.add(infoPanel); mainPanel.add(mainTabPanel); + this.readOnlyMode = readOnlyMode; + + + + + howeView.hideUpdateStatusAction(readOnlyMode); + howeView.hideSelectableRow(readOnlyMode); bindEvents(); } @@ -91,13 +107,14 @@ public class CkanContentModeratorWidgetController { List items = clickItemEvent.getSelectItems(); // if items selected are > 0 then shows button "Update status as.." howeView.setVisibleUpdateStatusAction(items.size() > 0); - - if(howeView.getDisplayingItemStatus().equals(ItemStatus.APPROVED)) { - GWT.log("The Item Status displayed is "+ItemStatus.APPROVED +" hiding update status actions"); + + if (howeView.getDisplayingItemStatus().equals(ItemStatus.APPROVED)) { + GWT.log("The Item Status displayed is " + ItemStatus.APPROVED + + " hiding update status actions"); howeView.setVisibleUpdateStatusAction(false); } - - //If an action updated the item status we reloading it + + // If an action updated the item status we reloading it reloadItemsDisplayedInTab(); } } @@ -117,11 +134,6 @@ public class CkanContentModeratorWidgetController { csif.instanceFrame(clickedDataset.getUrl()); mainTabPanel.addTab(clickedDataset.getTitle(), csif); mapOfItemsTabDisplayed.put(clickedDataset.getUrl(), csif); - -// CkanInternalFramePanel cfp = new CkanInternalFramePanel(eventBus); -// cfp.instanceFrame(clickedDataset.getUrl()); -// mainTabPanel.addTab(clickedDataset.getTitle(), cfp); - } } } @@ -206,15 +218,24 @@ public class CkanContentModeratorWidgetController { } }); } - + + /** + * Reload items displayed in tab. + */ private void reloadItemsDisplayedInTab() { - + for (String datasetURL : mapOfItemsTabDisplayed.keySet()) { CkanShowItemFrame showItemFrame = mapOfItemsTabDisplayed.get(datasetURL); showItemFrame.reloadPage(); } } + /** + * Show message. + * + * @param msg the msg + * @param alertType the alert type + */ private void showMessage(String msg, AlertType alertType) { final Alert alert = new Alert(msg); @@ -245,4 +266,13 @@ public class CkanContentModeratorWidgetController { return mainPanel; } + /** + * Checks if is read only mode. + * + * @return true, if is read only mode + */ + public boolean isReadOnlyMode() { + return readOnlyMode; + } + } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetEntryPoint.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetEntryPoint.java index 9628596..85a6868 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetEntryPoint.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/CkanContentModeratorWidgetEntryPoint.java @@ -1,22 +1,22 @@ -package org.gcube.portlets.widgets.ckancontentmoderator.client; - -import com.google.gwt.core.client.EntryPoint; - -/** - * Entry point classes define onModuleLoad(). - */ -public class CkanContentModeratorWidgetEntryPoint implements EntryPoint { - /** - * The message displayed to the user when the server cannot be reached or - * returns an error. - */ - private static final String SERVER_ERROR = "An error occurred while " - + "attempting to contact the server. Please check your network " + "connection and try again."; - - /** - * This is the entry point method. - */ - public void onModuleLoad() { - } - -} +//package org.gcube.portlets.widgets.ckancontentmoderator.client; +// +//import com.google.gwt.core.client.EntryPoint; +// +///** +// * Entry point classes define onModuleLoad(). +// */ +//public class CkanContentModeratorWidgetEntryPoint implements EntryPoint { +// /** +// * The message displayed to the user when the server cannot be reached or +// * returns an error. +// */ +// private static final String SERVER_ERROR = "An error occurred while " +// + "attempting to contact the server. Please check your network " + "connection and try again."; +// +// /** +// * This is the entry point method. +// */ +// public void onModuleLoad() { +// } +// +//} diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ContentModeratorWidgetConstants.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ContentModeratorWidgetConstants.java index 48c8093..35659e2 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ContentModeratorWidgetConstants.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ContentModeratorWidgetConstants.java @@ -5,7 +5,7 @@ package org.gcube.portlets.widgets.ckancontentmoderator.client; * * @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it * - * Jun 15, 2021 + * Jun 15, 2021 */ public class ContentModeratorWidgetConstants { @@ -13,4 +13,6 @@ public class ContentModeratorWidgetConstants { public static int ITEMS_PER_PAGE = 10; public static int ITEM_START_INDEX = 0; + + public static String CKAN_FIELD_NAME_AUTHOR_MAIL = "author_email"; } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/CkanShowItemFrame.ui.xml b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/CkanShowItemFrame.ui.xml index 3356a1a..3365f3d 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/CkanShowItemFrame.ui.xml +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/CkanShowItemFrame.ui.xml @@ -7,12 +7,13 @@ font-weight: bold; } - .asBar { - background-color: none !important; + .as_simple_link { + background: none; + border: none; } - + Reload diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/ContentModeratorPaginatedView.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/ContentModeratorPaginatedView.java index 4692c2a..644e790 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/ContentModeratorPaginatedView.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/ContentModeratorPaginatedView.java @@ -19,6 +19,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.user.cellview.client.SimplePager; 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.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; @@ -54,6 +55,7 @@ public class ContentModeratorPaginatedView { private ItemStatus itemStatus; private int serverStartIndex; private HandlerManager eventBus; + private boolean restrictDataToLoggedInUser; /** * Instantiates a new content moderator paginated view. @@ -62,10 +64,12 @@ public class ContentModeratorPaginatedView { * @param theStatus the the status * @param displayFields the display fields * @param sortByField the sort by field + * @param restrictDataToLoggedInUser the restrict data to logged in user */ public ContentModeratorPaginatedView(HandlerManager eventbus, ItemStatus theStatus, DISPLAY_FIELD[] displayFields, - DISPLAY_FIELD sortByField) { + DISPLAY_FIELD sortByField, boolean restrictDataToLoggedInUser) { this.itemStatus = theStatus; + this.restrictDataToLoggedInUser = restrictDataToLoggedInUser; this.initClassFirstRangeChanged = true; this.eventBus = eventbus; itemsTable = new ItemsTable(eventbus, displayFields, sortByField); @@ -75,7 +79,7 @@ public class ContentModeratorPaginatedView { initPagination(ITEMS_PER_PAGE); // loadNewPage(ITEM_START_INDEX, ITEMS_PER_PAGE, false); loadItemsForStatus(theStatus); - + } /** @@ -109,7 +113,7 @@ public class ContentModeratorPaginatedView { pager.setPageSize(itemsPerPage); pager.getElement().getStyle().setProperty("margin", "auto"); vPanel.add(loadingPanel); - + ScrollPanel scroll = new ScrollPanel(); scroll.getElement().getStyle().setProperty("maxHeight", "470px"); scroll.add(getCellTable()); @@ -237,7 +241,7 @@ public class ContentModeratorPaginatedView { + ", serverIndex:" + serverIndex + "]"); CkanContentModeratorWidgetController.contentModeratorService.getDataForStatus(status, offset, limit, - serverIndex, new AsyncCallback() { + serverIndex, restrictDataToLoggedInUser, new AsyncCallback() { @Override 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"); + + } + } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.java index 0508369..f58b335 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.java @@ -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.HTML; 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.Widget; @@ -63,7 +64,7 @@ public class HomeView extends Composite { @UiField Heading pageHeader; - + @UiField HTMLPanel actionLoaderPanel; @@ -73,6 +74,9 @@ public class HomeView extends Composite { @UiField Button permanentlyDelete; + @UiField + HorizontalPanel updateStatusActionPanel; + private ScrollPanel confirmPanelContainer = new ScrollPanel(); private List setStatusOptions = new ArrayList(); @@ -80,8 +84,10 @@ public class HomeView extends Composite { private ItemStatus displayingItemStatus; private HandlerManager eventBus; - + private LoadingPanel actionInProgressLoader = new LoadingPanel(new HTML("Performing action...")); + private boolean readOnlyMode; + private boolean restrictDataToLoggedInUser; /** * The Interface HomeViewUiBinder. @@ -96,17 +102,22 @@ public class HomeView extends Composite { /** * Instantiates a new home view. * - * @param eventBus the event bus - * @param status the status - * @param displayFields the display fields - * @param sortByField the sort by field + * @param eventBus the event bus + * @param status the status + * @param displayFields the display fields + * @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, - DISPLAY_FIELD sortByField) { + DISPLAY_FIELD sortByField, boolean readOnlyMode, boolean restrictDataToLoggedInUser) { initWidget(uiBinder.createAndBindUi(this)); setDisplayingWithStatus(status); 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.addToBottom(paginatedView.getPagerPanel()); panelContainer.add(cmsPanel.getPanel()); @@ -120,23 +131,30 @@ public class HomeView extends Composite { setStatusOptions.add(nl); } - + showActionLoader(false); actionLoaderPanel.add(actionInProgressLoader); - + setStatusOptions(status); bindEvents(); confirmPanel.add(confirmPanelContainer); } - + + /** + * Show action loader. + * + * @param showActionInProgress the show action in progress + */ private void showActionLoader(boolean showActionInProgress) { - GWT.log("Show action in progress: "+showActionInProgress); + GWT.log("Show action in progress: " + 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) { @@ -147,20 +165,20 @@ public class HomeView extends Composite { if (navLink.getText().trim().equals(displayingItemStatus.getLabel())) { navLink.setVisible(false); } - - //Hiding the changing REJECT -> APPROVED - //One item REJECT must be only updated to return to PENDING status - if(selectedStatus.equals(ItemStatus.REJECTED)) { + + // Hiding the changing REJECT -> APPROVED + // One item REJECT must be only updated to return to PENDING status + if (selectedStatus.equals(ItemStatus.REJECTED)) { if (navLink.getText().trim().equals(ItemStatus.APPROVED.getLabel())) { navLink.setVisible(false); } } - - //Hiding the changing of any status from the APPROVED - if(selectedStatus.equals(ItemStatus.APPROVED)) { + + // Hiding the changing of any status from the APPROVED + if (selectedStatus.equals(ItemStatus.APPROVED)) { navLink.setVisible(false); } - + } } @@ -317,7 +335,7 @@ public class HomeView extends Composite { * Show do action delete permanently. */ private void showDoActionViewDeletePermanently() { - + confirmPanelContainer.clear(); GWT.log("showDoActionViewDeletePermanently..."); @@ -341,49 +359,51 @@ public class HomeView extends Composite { public void onClick(ClickEvent event) { confirmPanelContainer.clear(); showActionLoader(true); - + List listDatasetNames = UtilFunct.toListDatasetNames(doActionCMS.getListSelectItems()); - CkanContentModeratorWidgetController.contentModeratorService.permanentlyDelete(listDatasetNames, new AsyncCallback() { + CkanContentModeratorWidgetController.contentModeratorService.permanentlyDelete(listDatasetNames, + new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - showActionLoader(false); - Window.alert(caught.getMessage()); - eventBus.fireEvent(new SelectItemsWithItemStatusEvent(displayingItemStatus, - "Sorry an error occurred. Please, refresh and try again", AlertType.ERROR)); - - } + @Override + public void onFailure(Throwable caught) { + showActionLoader(false); + Window.alert(caught.getMessage()); + eventBus.fireEvent(new SelectItemsWithItemStatusEvent(displayingItemStatus, + "Sorry an error occurred. Please, refresh and try again", AlertType.ERROR)); - @Override - public void onSuccess(OperationReport result) { - showActionLoader(false); - AlertType alert = AlertType.SUCCESS; - int count = selectedItems.size(); - String msg = "Deleted permanently"; - if (count > 0) { - if (count == 1) { - msg += " one item"; - } else { - msg += " " + count + " items"; } - msg += " from Catalogue"; - } - - int errorCount = result.getErrorMapItems().size(); - if (errorCount > 0) { - msg += "
Error occurred on deleting permanently " + errorCount + " item/s:"; - for (String key : result.getErrorMapItems().keySet()) { - msg += "
"+ key+". Error: "+ result.getErrorMapItems().get(key); + @Override + public void onSuccess(OperationReport result) { + showActionLoader(false); + AlertType alert = AlertType.SUCCESS; + int count = selectedItems.size(); + String msg = "Deleted permanently"; + if (count > 0) { + if (count == 1) { + msg += " one item"; + } else { + msg += " " + count + " items"; + } + + msg += " from Catalogue"; + } + + int errorCount = result.getErrorMapItems().size(); + if (errorCount > 0) { + msg += "
Error occurred on deleting permanently " + errorCount + " item/s:"; + for (String key : result.getErrorMapItems().keySet()) { + msg += "
" + key + ". Error: " + result.getErrorMapItems().get(key); + } + + alert = AlertType.WARNING; + } + + eventBus.fireEvent( + new SelectItemsWithItemStatusEvent(displayingItemStatus, msg, alert)); + } - - alert = AlertType.WARNING; - } - - eventBus.fireEvent(new SelectItemsWithItemStatusEvent(displayingItemStatus, msg, alert)); - - } - }); + }); } }); @@ -457,9 +477,9 @@ public class HomeView extends Composite { if (errorCount > 0) { msg += "
Error occurred on updating status to " + errorCount + " item/s:"; for (String key : result.getErrorMapItems().keySet()) { - msg += "
"+ key+". Error: "+ result.getErrorMapItems().get(key); + msg += "
" + key + ". Error: " + result.getErrorMapItems().get(key); } - + alert = AlertType.WARNING; } @@ -512,9 +532,9 @@ public class HomeView extends Composite { if (errorCount > 0) { msg += "
Error occurred on approving " + errorCount + " item/s:"; for (String key : result.getErrorMapItems().keySet()) { - msg += "
"+ key+". Error: "+ result.getErrorMapItems().get(key); + msg += "
" + key + ". Error: " + result.getErrorMapItems().get(key); } - + alert = AlertType.WARNING; } @@ -551,13 +571,12 @@ public class HomeView extends Composite { } else { msg += count + " items"; } - + boolean isPermanentlyDelete = doActionCMSView.isPermanentlyDelete(); - - if(isPermanentlyDelete) { + + if (isPermanentlyDelete) { msg += " deleted permanently from Catalogue"; - } - else { + } else { msg += " moved to " + toStatus + " status."; } } @@ -566,9 +585,9 @@ public class HomeView extends Composite { if (errorCount > 0) { msg += "
Error occurred on rejecting " + errorCount + " item/s:"; for (String key : result.getErrorMapItems().keySet()) { - msg += "
"+ key+". Error: "+ result.getErrorMapItems().get(key); + msg += "
" + key + ". Error: " + result.getErrorMapItems().get(key); } - + alert = AlertType.WARNING; } @@ -583,9 +602,50 @@ public class HomeView extends Composite { break; } } - + + /** + * Gets the displaying item status. + * + * @return the displaying item status + */ public ItemStatus getDisplayingItemStatus() { 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; + } + } diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.ui.xml b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.ui.xml index 41ad7bb..33a13cf 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.ui.xml +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/client/ui/HomeView.ui.xml @@ -42,7 +42,7 @@ Items with status: + addStyleNames="{style.font-size-14}" ui:field="updateStatusActionPanel"> diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/public/content-moderator-widget.css b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/public/content-moderator-widget.css index 4f5cd4d..d3aad17 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/public/content-moderator-widget.css +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/public/content-moderator-widget.css @@ -22,8 +22,17 @@ vertical-align: middle !important; } +.hide_checkbox input[type="checkbox"] { + display: none; +} + /***** WS EXPLORER DOCK PANEL - CENTER FLOW PANEL *****/ .we-dock-center-panel { overflow-y: auto !important; /* border: 1px solid #DDD; */ +} + +.as_simple_link { + background: none; + border: none; } \ No newline at end of file diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceImpl.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceImpl.java index c390428..f07c2cd 100644 --- a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceImpl.java +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceImpl.java @@ -7,11 +7,14 @@ import java.util.Map; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; 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.cms.CatalogueContentModeratorSystem; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; import org.gcube.datacatalogue.utillibrary.shared.jackan.model.CkanDataset; 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.CatalogueDataset; import org.gcube.portlets.widgets.ckancontentmoderator.shared.ModerationUserRole; @@ -73,6 +76,63 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem 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 query = new HashMap(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. * @@ -108,22 +168,34 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem /** * Gets the list items for status. * - * @param theStatus the the status - * @param offset the offset - * @param limit the limit + * @param theStatus the the status + * @param offset the offset + * @param limit the limit + * @param restrictedToLoggedInUser if true restricts the list of items to logged + * in user * @return the list items for status * @throws Exception the exception */ @Override - public List getListItemsForStatus(ItemStatus theStatus, int offset, int limit) throws Exception { - LOG.info("called getListItemsForStatus with [status: " + theStatus + ", offset: " + offset + "], [limit: " - + limit + "]"); + public List getListItemsForStatus(ItemStatus theStatus, int offset, int limit, + boolean restrictedToLoggedInUser) throws Exception { + LOG.info("called getListItemsForStatus with [status: " + theStatus + ", offset: " + offset + ", limit: " + limit + + ", restrictedToLoggedInUser: " + restrictedToLoggedInUser + "]"); List datasetList = null; try { String scope = setContexts(); DataCatalogueImpl catalogueImpl = CatalogueCMSFactory.getFactory().getCatalogueImplPerScope(scope); CatalogueContentModeratorSystem cmsInstance = catalogueImpl.getCatalogueContentModerator(); - List datasets = cmsInstance.getListItemsForStatus(theStatus, limit, offset); + + Map filters = null; + if (restrictedToLoggedInUser) { + filters = new HashMap(1); + GCubeUser user = GcubeContextUtil.getCurrentUser(getThreadLocalRequest()); + String valueOfQueryEmails = CkanContentModeratorUtil.userQueryForEmails(user, QUERY_OPERATOR.OR); + filters.put(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL, valueOfQueryEmails); + } + + List datasets = cmsInstance.getListItemsForStatus(theStatus, limit, offset, filters); if (datasets != null) { int size = datasets.size(); datasetList = new ArrayList(size); @@ -306,25 +378,34 @@ public class CkanContentModeratorServiceImpl extends RemoteServiceServlet implem * @throws Exception the exception */ @Override - public SearchedData getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex) - throws Exception { + public SearchedData getDataForStatus(ItemStatus status, int offset, int limit, int serverStartIndex, + boolean restrictedToLoggedInUser) throws Exception { LOG.info("called getDataForStatus [status: " + status + ", offset: " + offset + ", limit: " + limit + ", serverIndex: " + serverStartIndex); - + String scope = setContexts(); int searchStartIndex = offset; CatalogueContentModeratorSystem cmsInstance = CatalogueCMSFactory.getFactory().getCMSPerScope(scope); SearchedData searchedData = new SearchedData(offset, limit, searchStartIndex, false); - long totalItemsForStatus = cmsInstance.countListItemsForStatus(status); + + Map filters = null; + if (restrictedToLoggedInUser) { + filters = new HashMap(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); List listDataset = new ArrayList(); try { LOG.debug("getListItemsForStatus with searchStartIndex: " + searchStartIndex + ", limit: " + limit); - listDataset = getListItemsForStatus(status, searchStartIndex, limit); + listDataset = getListItemsForStatus(status, searchStartIndex, limit, restrictedToLoggedInUser); } catch (Exception e) { String error = "Error occurred on getting items for status: " + status; LOG.error(error, e); - throw new Exception(error+". Cause: "+e.getMessage()); + throw new Exception(error + ". Cause: " + e.getMessage()); } int listDatasetSize = listDataset.size(); diff --git a/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorUtil.java b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorUtil.java new file mode 100644 index 0000000..3b739cd --- /dev/null +++ b/src/main/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorUtil.java @@ -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 listServerEmails = user.getEmailAddresses(); + LOG.debug("List server mails: {}", listServerEmails); + List emailsAddresses = new ArrayList(); + + 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; + } +} diff --git a/src/test/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceTest.java b/src/test/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceTest.java index 1c87a34..c85e22c 100644 --- a/src/test/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceTest.java +++ b/src/test/java/org/gcube/portlets/widgets/ckancontentmoderator/server/CkanContentModeratorServiceTest.java @@ -2,14 +2,16 @@ package org.gcube.portlets.widgets.ckancontentmoderator.server; import static org.junit.Assert.fail; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.datacatalogue.utillibrary.server.cms.CatalogueContentModeratorSystem; import org.gcube.datacatalogue.utillibrary.shared.ItemStatus; 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; public class CkanContentModeratorServiceTest { @@ -33,7 +35,9 @@ public class CkanContentModeratorServiceTest { ItemStatus itemStatus = ItemStatus.PENDING; try { CatalogueContentModeratorSystem cms = CatalogueCMSFactory.getFactory().getCMSPerScope(scope); - List items = cms.getListItemsForStatus(itemStatus, 20, 0); + Map filters = new HashMap(1); + filters.put(ContentModeratorWidgetConstants.CKAN_FIELD_NAME_AUTHOR_MAIL, "francesco.mangiacrapa@isti.cnr.it"); + List items = cms.getListItemsForStatus(itemStatus, 20, 0, filters); int i = 0; System.out.println("Datasets with status "+itemStatus+" are: "+items.size()); for (CkanDataset ckanDataset : items) {