#25433 Added spinner during resource creation, implemented

This commit is contained in:
Francesco Mangiacrapa 2023-07-25 15:24:37 +02:00
parent 316912b060
commit 0cdad77490
6 changed files with 220 additions and 189 deletions

View File

@ -4,6 +4,12 @@
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).
## [v2.1.3-SNAPSHOT] - 2023-07-25
**Enhancement**
- [#25433] Added spinner during resource creation
## [v2.1.2] - 2023-03-10
**Bug fixes**

View File

@ -7,13 +7,13 @@
<parent>
<artifactId>maven-parent</artifactId>
<groupId>org.gcube.tools</groupId>
<version>1.1.0</version>
<version>1.2.0</version>
<relativePath />
</parent>
<groupId>org.gcube.portlets.widgets</groupId>
<artifactId>ckan-metadata-publisher-widget</artifactId>
<version>2.1.2</version>
<version>2.1.3-SNAPSHOT</version>
<name>gCube Ckan metadata publisher widget</name>
<description>

View File

@ -1,13 +1,20 @@
package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.icons;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
public interface Images extends ClientBundle {
/** The Constant ICONS. */
public static final Images ICONS = GWT.create(Images.class);
@Source("file.png")
ImageResource fileIcon();
@Source("folder.png")
ImageResource folderIcon();
@Source("loading.gif")
ImageResource loading();
}

View File

@ -3,6 +3,7 @@ package org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.resources;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherService;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.CKanPublisherServiceAsync;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.events.AddResourceEvent;
import org.gcube.portlets.widgets.ckandatapublisherwidget.client.ui.utils.LoaderIcon;
import org.gcube.portlets.widgets.ckandatapublisherwidget.shared.ResourceElementBean;
import com.github.gwtbootstrap.client.ui.AlertBlock;
@ -23,6 +24,7 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;
/**
@ -57,6 +59,7 @@ public class AddResourceToDataset extends Composite{
@UiField Button goToDatasetButton;
@UiField ControlGroup urlControlGroup;
@UiField ControlGroup nameControlGroup;
@UiField FlowPanel infoPanel;
public AddResourceToDataset(HandlerManager eventBus, String datasetId, String datasetTitle, String datasetOrg, String owner, final String datasetUrl) {
initWidget(uiBinder.createAndBindUi(this));
@ -130,11 +133,15 @@ public class AddResourceToDataset extends Composite{
// disable add button
addResourceButton.setEnabled(false);
LoaderIcon loader = new LoaderIcon("Adding resource, please wait...");
infoPanel.add(loader);
// try to create
ckanServices.addResourceToDataset(resource, datasetId, new AsyncCallback<ResourceElementBean>() {
@Override
public void onSuccess(ResourceElementBean result) {
infoPanel.clear();
if(result != null){
showAlert("Resource created correctly", AlertType.SUCCESS);
@ -153,7 +160,7 @@ public class AddResourceToDataset extends Composite{
@Override
public void onFailure(Throwable caught) {
infoPanel.clear();
showAlert("Unable to add this resource, sorry. Error is: " + caught.getMessage(), AlertType.ERROR);
}

View File

@ -59,8 +59,10 @@
</b:Legend>
<b:Alert type="INFO" close="false">The URL of the resource you are
publishing (only HTTPS URLs are allowed). If your resource is a file that you own on your
desktop, please upload that file to your workspace and generate a
publishing (only HTTPS URLs are allowed). If your resource is a
file that you own on your
desktop, please upload that file to your
workspace and generate a
public URL for that file.</b:Alert>
<b:ControlGroup ui:field="urlControlGroup">
@ -108,6 +110,9 @@
<b:Button title="Add resource" ui:field="addResourceButton"
type="PRIMARY">Add</b:Button>
<g:FlowPanel ui:field="infoPanel">
</g:FlowPanel>
</b:Fieldset>
</b:Form>

View File

@ -50,10 +50,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.liferay.portal.service.UserLocalServiceUtil;
/**
* Server side of the data publisher.
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class CKANPublisherServicesImpl extends RemoteServiceServlet implements CKanPublisherService {
@ -61,7 +60,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
private static final long serialVersionUID = 7252248774050361697L;
// Logger
//private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CKANPublisherServicesImpl.class);
// private static final org.slf4j.Logger logger =
// LoggerFactory.getLogger(CKANPublisherServicesImpl.class);
private static final Logger logger = LoggerFactory.getLogger(CKANPublisherServicesImpl.class);
private static final String ITEM_URL_FIELD = "Item URL";
private static final String SYS_TYPE = "system:type";
@ -70,7 +70,6 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
// map <orgName, scope>
private ConcurrentHashMap<String, String> mapOrganizationScope = new ConcurrentHashMap<String, String>();
/**
* Dev mode set contexts.
*/
@ -94,17 +93,20 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
DataCatalogue instance = null;
String scopeInWhichDiscover = null;
try {
scopeInWhichDiscover = scope != null && !scope.isEmpty() ? scope : GenericUtils.getCurrentContext(getThreadLocalRequest(), false);
scopeInWhichDiscover = scope != null && !scope.isEmpty() ? scope
: GenericUtils.getCurrentContext(getThreadLocalRequest(), false);
logger.debug("Discovering ckan instance into scope " + scopeInWhichDiscover);
instance = DataCatalogueFactory.getFactory().getUtilsPerScope(scopeInWhichDiscover);
} catch (Exception e) {
logger.warn("Unable to retrieve ckan utils in scope " + scopeInWhichDiscover + ". Error is " + e.getLocalizedMessage());
logger.warn("Unable to retrieve ckan utils in scope " + scopeInWhichDiscover + ". Error is "
+ e.getLocalizedMessage());
}
return instance;
}
/**
* Retrieve the list of organizations in which the user can publish (roles ADMIN/EDITOR).
* Retrieve the list of organizations in which the user can publish (roles
* ADMIN/EDITOR).
*
* @param username the username
* @param scope the scope
@ -112,22 +114,24 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
* @throws UserManagementSystemException the user management system exception
* @throws GroupRetrievalFault the group retrieval fault
*/
private List<OrganizationBean> getUserOrganizationsListAdmin(String username, String scope) throws UserManagementSystemException, GroupRetrievalFault {
private List<OrganizationBean> getUserOrganizationsListAdmin(String username, String scope)
throws UserManagementSystemException, GroupRetrievalFault {
logger.debug("Request for user " + username + " organizations list");
List<OrganizationBean> orgsName = new ArrayList<OrganizationBean>();
HttpSession httpSession = getThreadLocalRequest().getSession();
String keyPerScope = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_ORGANIZATIONS_PUBLISH_KEY, scope);
String keyPerScope = CatalogueUtilMethods
.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_ORGANIZATIONS_PUBLISH_KEY, scope);
if (httpSession.getAttribute(keyPerScope) != null) {
orgsName = (List<OrganizationBean>) httpSession.getAttribute(keyPerScope);
logger.info("List of organizations was into session " + orgsName);
}
else{
} else {
String gatewayURL = GenericUtils.getGatewayClientHostname(getThreadLocalRequest());
logger.info("The Gateway URL is: " + gatewayURL);
CatalogueRoleManager.getHighestRole(scope, username, GenericUtils.getGroupFromScope(scope).getGroupName(), this, orgsName, gatewayURL);
CatalogueRoleManager.getHighestRole(scope, username, GenericUtils.getGroupFromScope(scope).getGroupName(),
this, orgsName, gatewayURL);
httpSession.setAttribute(keyPerScope, orgsName);
logger.info("Organizations name for user " + username + " has been saved into session " + orgsName);
}
@ -144,8 +148,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
try {
UserLocalServiceUtil.getService();
return true;
}
catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) {
} catch (com.liferay.portal.kernel.bean.BeanLocatorException ex) {
logger.trace("Development Mode ON");
return false;
}
@ -155,12 +158,12 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
* Gets the workspace from storage hub.
*
* @return the workspace from storage hub
* @throws Exception
* the exception
* @throws Exception the exception
*/
protected Workspace getWorkspaceFromStorageHub() throws Exception {
GCubeUser user = PortalContext.getConfiguration().getCurrentUser(this.getThreadLocalRequest());
StorageHubWrapper storageHubWrapper = WorkspaceUtils.getStorageHubWrapper(this.getThreadLocalRequest(), null, user);
StorageHubWrapper storageHubWrapper = WorkspaceUtils.getStorageHubWrapper(this.getThreadLocalRequest(), null,
user);
return storageHubWrapper.getWorkspace();
}
@ -190,7 +193,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
HttpSession httpSession = getThreadLocalRequest().getSession();
String scope = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest());
logger.info("Request for CKAN licenses for scope " + scope);
String keyPerScope = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_LICENSES_KEY, scope);
String keyPerScope = CatalogueUtilMethods
.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_LICENSES_KEY, scope);
// if(!isWithinPortal()){
// logger.info("DEV MODE returning funny licenses...");
@ -203,8 +207,7 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
if (httpSession.getAttribute(keyPerScope) != null) {
licensesBean = (List<LicenseBean>) httpSession.getAttribute(keyPerScope);
logger.info("List of licenses was into session");
}
else{
} else {
List<CkanLicense> licenses = getCatalogue(scope).getLicenses();
licensesBean = new ArrayList<LicenseBean>();
for (CkanLicense license : licenses) {
@ -215,7 +218,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
Collections.sort(licensesBean, new Comparator<LicenseBean>() {
public int compare(LicenseBean l1, LicenseBean l2) {
return l1.getTitle().compareTo(l2.getTitle());
}});
}
});
httpSession.setAttribute(keyPerScope, licensesBean);
logger.info("List of licenses has been saved into session");
@ -224,7 +228,6 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
return licensesBean;
}
/**
* Gets the dataset bean.
*
@ -246,8 +249,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
String scope = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest());
logger.debug("Scope recovered from session is " + scope);
logger.debug("Request dataset metadata bean for folder with id " + folderId
+ " whose owner is " + userName);
logger.debug(
"Request dataset metadata bean for folder with id " + folderId + " whose owner is " + userName);
UserManager liferUserManager = new LiferayUserManager();
GCubeUser userOwner = liferUserManager.getUserByUsername(userName);
@ -406,33 +409,22 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
}
}
String datasetId = utils.createCkanDatasetMultipleCustomFields(userName,
title,
null,
organizationNameOrId,
author,
authorMail,
maintainer,
maintainerMail,
version,
description,
licenseId,
listOfTags,
customFields,
resources,
setPublic,
true,
true);
String datasetId = utils.createCkanDatasetMultipleCustomFields(userName, title, null, organizationNameOrId,
author, authorMail, maintainer, maintainerMail, version, description, licenseId, listOfTags,
customFields, resources, setPublic, true, true);
if (datasetId != null) {
logger.info("Dataset created!");
toCreate.setId(datasetId);
//#23491 Building the go to the item to "Catalogue Portlet URL" (instead of URI Resolver URL)
// #23491 Building the go to the item to "Catalogue Portlet URL" (instead of URI
// Resolver URL)
String catalogueURL = utils.getPortletUrl();
// logger.debug("Returning catalogueURL: "+catalogueURL);
// logger.debug("Returning datasetId: "+datasetId);
toCreate.setSource(String.format("%s?path=/dataset/%s", catalogueURL, datasetId));
logger.debug("Returning getSource(): " + toCreate.getSource());
logger.debug("Returning dataset: " + toCreate);
// #24744 Returning lazy object
@ -476,22 +468,19 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
logger.info("called addResourceToDataset");
devModeSetContexts();
String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername();
logger.debug("Incoming request for creating new resource for dataset with id " + datasetId + " and organization name of the dataset is " + resource.getOrganizationNameDatasetParent());
logger.debug("Incoming request for creating new resource for dataset with id " + datasetId
+ " and organization name of the dataset is " + resource.getOrganizationNameDatasetParent());
logger.debug("Owner is " + username + " and resource is " + resource);
ResourceBean resourceBean = new ResourceBean(
resource.getUrl(),
resource.getName(),
resource.getDescription(),
null,
username,
datasetId,
null);
ResourceBean resourceBean = new ResourceBean(resource.getUrl(), resource.getName(), resource.getDescription(),
null, username, datasetId, null);
// get the scope in which we should discover the ckan instance given the organization name in which the dataset was created
// get the scope in which we should discover the ckan instance given the
// organization name in which the dataset was created
String scope = getScopeFromOrgName(resource.getOrganizationNameDatasetParent());
DataCatalogue catalogue = getCatalogue(scope);
String resourceId = catalogue.addResourceToDataset(resourceBean, resource.getOrganizationNameDatasetParent(), username);
String resourceId = catalogue.addResourceToDataset(resourceBean, resource.getOrganizationNameDatasetParent(),
username);
if (resourceId != null) {
logger.info("Resource " + resource.getName() + " is now available");
@ -517,7 +506,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
boolean deleted = false;
devModeSetContexts();
try {
// get the scope in which we should discover the ckan instance given the organization name in which the dataset was created
// get the scope in which we should discover the ckan instance given the
// organization name in which the dataset was created
String scope = getScopeFromOrgName(resource.getOrganizationNameDatasetParent());
DataCatalogue catalogue = getCatalogue(scope);
String username = GenericUtils.getCurrentUser(getThreadLocalRequest()).getUsername();
@ -573,7 +563,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
try {
String scopeFromOrgName = getScopeFromOrgName(orgName);
String idFromTitle = CatalogueUtilMethods.fromProductTitleToName(title);
logger.debug("Evaluating if dataset with id " + title + " in context " + scopeFromOrgName + " already exists");
logger.debug(
"Evaluating if dataset with id " + title + " in context " + scopeFromOrgName + " already exists");
return getCatalogue(scopeFromOrgName).existProductWithNameOrId(idFromTitle);
} catch (Exception e) {
logger.error("Unable to check if such a dataset id already exists", e);
@ -582,12 +573,14 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
}
/**
* The method tries to retrieve the scope related to the organization using the map first,
* if no match is found, it retrieves such information by using liferay
* The method tries to retrieve the scope related to the organization using the
* map first, if no match is found, it retrieves such information by using
* liferay
*/
private String getScopeFromOrgName(String orgName) {
logger.info("Request for scope related to orgName " + orgName + " [map that will be used is " + mapOrganizationScope.toString() + "]");
logger.info("Request for scope related to orgName " + orgName + " [map that will be used is "
+ mapOrganizationScope.toString() + "]");
if (orgName == null || orgName.isEmpty())
throw new IllegalArgumentException("orgName cannot be empty or null!");
@ -601,7 +594,8 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
String evaluatedScope = GenericUtils.retrieveScopeFromOrganizationName(orgName);
// see #20801
if (evaluatedScope == null || evaluatedScope.isEmpty()) {
logger.warn("Scope detected for OrganizationName: "+orgName+" is null or empty, skipping filling 'mapOrganizationScope' and returning null");
logger.warn("Scope detected for OrganizationName: " + orgName
+ " is null or empty, skipping filling 'mapOrganizationScope' and returning null");
return toReturn;
}
mapOrganizationScope.put(orgName, evaluatedScope);
@ -640,10 +634,12 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
// get http session
HttpSession httpSession = getThreadLocalRequest().getSession();
String scope = orgName != null ? getScopeFromOrgName(orgName) : GenericUtils.getScopeFromClientUrl(getThreadLocalRequest());
String scope = orgName != null ? getScopeFromOrgName(orgName)
: GenericUtils.getScopeFromClientUrl(getThreadLocalRequest());
// check if they are in session
String keyPerScopeGroups = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_MEMBER, scope);
String keyPerScopeGroups = CatalogueUtilMethods
.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_MEMBER, scope);
if (httpSession.getAttribute(keyPerScopeGroups) != null) {
toReturn = (List<OrganizationBean>) httpSession.getAttribute(keyPerScopeGroups);
@ -655,17 +651,20 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
DataCatalogue catalogue = getCatalogue(scope);
// Fixing Incident #12563
if (username != null && !username.isEmpty()) {
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> mapRoleGroup = catalogue.getUserRoleByGroup(username);
Map<String, Map<CkanGroup, RolesCkanGroupOrOrg>> mapRoleGroup = catalogue
.getUserRoleByGroup(username);
Set<Entry<String, Map<CkanGroup, RolesCkanGroupOrOrg>>> set = mapRoleGroup.entrySet();
for (Entry<String, Map<CkanGroup, RolesCkanGroupOrOrg>> entry : set) {
Set<Entry<CkanGroup, RolesCkanGroupOrOrg>> subSet = entry.getValue().entrySet();
for (Entry<CkanGroup, RolesCkanGroupOrOrg> subEntry : subSet) {
toReturn.add(new OrganizationBean(subEntry.getKey().getTitle(), subEntry.getKey().getName(), false));
toReturn.add(new OrganizationBean(subEntry.getKey().getTitle(),
subEntry.getKey().getName(), false));
}
}
httpSession.setAttribute(keyPerScopeGroups, toReturn);
} else
logger.warn("The API_KEY for "+username+ " is null or empty in the catalogue: "+catalogue.getCatalogueUrl());
logger.warn("The API_KEY for " + username + " is null or empty in the catalogue: "
+ catalogue.getCatalogueUrl());
} catch (Exception e) {
logger.error("Error on recovery the user groups for " + username, e);
}
@ -677,7 +676,6 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
return toReturn;
}
/**
* Checks if is publisher user.
*
@ -704,11 +702,15 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
String scopePerCurrentUrl = GenericUtils.getScopeFromClientUrl(getThreadLocalRequest());
// get key per scope
String keyPerScopeRole = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_HIGHEST_ROLE, scopePerCurrentUrl);
String keyPerScopeOrganizations = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_ORGANIZATIONS_PUBLISH_KEY, scopePerCurrentUrl);
String keyPerScopeGroups = CatalogueUtilMethods.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_MEMBER, scopePerCurrentUrl);
String keyPerScopeRole = CatalogueUtilMethods
.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_HIGHEST_ROLE, scopePerCurrentUrl);
String keyPerScopeOrganizations = CatalogueUtilMethods.concatenateSessionKeyScope(
SessionCatalogueAttributes.CKAN_ORGANIZATIONS_PUBLISH_KEY, scopePerCurrentUrl);
String keyPerScopeGroups = CatalogueUtilMethods
.concatenateSessionKeyScope(SessionCatalogueAttributes.CKAN_GROUPS_MEMBER, scopePerCurrentUrl);
// check if this information was already into session(true means the user has at least in one org
// check if this information was already into session(true means the user has at
// least in one org
// the role editor), false that he is just a member so he cannot publish
RolesCkanGroupOrOrg role = (RolesCkanGroupOrOrg) httpSession.getAttribute(keyPerScopeRole);
@ -720,16 +722,20 @@ public class CKANPublisherServicesImpl extends RemoteServiceServlet implements C
try {
GroupManager gm = new LiferayGroupManager();
String groupName = gm.getGroup(gm.getGroupIdFromInfrastructureScope(scopePerCurrentUrl)).getGroupName();
String groupName = gm.getGroup(gm.getGroupIdFromInfrastructureScope(scopePerCurrentUrl))
.getGroupName();
// we build up also a list that keeps track of the scopes (orgs) in which the user has role ADMIN/EDITOR
// we build up also a list that keeps track of the scopes (orgs) in which the
// user has role ADMIN/EDITOR
List<OrganizationBean> orgsInWhichAtLeastEditorRole = new ArrayList<OrganizationBean>();
String gatewayURL = GenericUtils.getGatewayClientHostname(getThreadLocalRequest());
logger.info("The Gateway URL is: " + gatewayURL);
role = CatalogueRoleManager.getHighestRole(scopePerCurrentUrl, username, groupName, this, orgsInWhichAtLeastEditorRole, gatewayURL);
role = CatalogueRoleManager.getHighestRole(scopePerCurrentUrl, username, groupName, this,
orgsInWhichAtLeastEditorRole, gatewayURL);
// if he is an admin/editor preload:
// 1) organizations in which he can publish (the widget will find these info in session)
// 1) organizations in which he can publish (the widget will find these info in
// session)
if (!role.equals(RolesCkanGroupOrOrg.MEMBER)) {
httpSession.setAttribute(keyPerScopeOrganizations, orgsInWhichAtLeastEditorRole);
String orgName = scopePerCurrentUrl.split("/")[scopePerCurrentUrl.split("/").length - 1];