diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java index 8152617..9ae14c6 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java @@ -35,8 +35,11 @@ import com.github.gwtbootstrap.client.ui.Modal; import com.github.gwtbootstrap.client.ui.TextArea; import com.github.gwtbootstrap.client.ui.TextBox; import com.github.gwtbootstrap.client.ui.constants.AlertType; +import com.github.gwtbootstrap.client.ui.event.HiddenEvent; +import com.github.gwtbootstrap.client.ui.event.HiddenHandler; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.SelectElement; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; @@ -45,6 +48,7 @@ import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; +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.HTML; @@ -160,6 +164,8 @@ public class ManageProductWidget extends Composite{ private SuggestMerges suggestedMergesPanel; private ConnectToWidget connectWidget; + private boolean updateSucceeded = false; + /** * Build a ManageProduct widget for the product with the specified id. * @param productIdentifier @@ -178,12 +184,23 @@ public class ManageProductWidget extends Composite{ loadingImage.setUrl(LOADING_IMAGE_URL); loadingImage.setVisible(true); formUpdate.setVisible(false); + loaderIcon.getElement().getStyle().setMarginRight(10, Unit.PX); // show modal manageProductModal.addStyleName("management-metadata-modal-style"); // manageProductModal.getElement().getStyle().setWidth(60, Unit.PCT); manageProductModal.show(); + manageProductModal.addHiddenHandler(new HiddenHandler() { + + @Override + public void onHidden(HiddenEvent hiddenEvent) { + if(updateSucceeded) + Window.Location.reload(); + + } + }); + // async request to fetch the product retrieveProductBean(productIdentifier); @@ -246,27 +263,27 @@ public class ManageProductWidget extends Composite{ GRSFNameTexBox.setText(bean.getTitle()); shortNameTextBox.setText(bean.getShortName()); shortNameTextBox.addChangeHandler(new ChangeHandler() { - + @Override public void onChange(ChangeEvent event) { eventBus.fireEvent(new EnableConfirmButtonEvent()); } }); - + semanticIdentifierTextBox.setText(bean.getSemanticIdentifier()); productGrsfType.setText(bean.getGrsfType()); currentStatus.setText(bean.getCurrentStatus().toString()); traceabilityFlag.setValue(bean.isTraceabilityFlag()); traceabilityFlag.setText("Traceability"); traceabilityFlag.setTitle("Current value for this flag in the Knowledge Base is " + bean.isTraceabilityFlag()); - + traceabilityFlag.addClickHandler(new ClickHandler() { - + @Override public void onClick(ClickEvent event) { - + eventBus.fireEvent(new EnableConfirmButtonEvent()); - + } }); @@ -315,17 +332,17 @@ public class ManageProductWidget extends Composite{ } }); - + annotationArea.addChangeHandler(new ChangeHandler() { - + @Override public void onChange(ChangeEvent event) { - + eventBus.fireEvent(new EnableConfirmButtonEvent()); - + } }); - + formUpdate.setVisible(true); } @@ -374,11 +391,11 @@ public class ManageProductWidget extends Composite{ // if the status has not be changed ... if(listBoxStatus.getSelectedIndex() <= 0){ bean.setNewStatus(bean.getCurrentStatus()); - report = "-The Status is unchanged"; + report = "- The Status is unchanged"; } else{ bean.setNewStatus(Status.fromString(listBoxStatus.getSelectedItemText())); - report = "-The Status has been changed to " + bean.getNewStatus().getOrigName(); + report = "- The Status has been changed to " + bean.getNewStatus().getOrigName(); hashtags.add(bean.getNewStatus().getOrigName()); } @@ -401,13 +418,19 @@ public class ManageProductWidget extends Composite{ // add the connections for the report if(!bean.getConnections().isEmpty()){ report += "\n- Suggested connections:"; - hashtags.add(HashTagsOnUpdate.CONNECT.getString()); + boolean addConnectionHashtag = false; for(ConnectedBean cb: bean.getConnections()){ if(cb.isRemove()) report += "\n\t - remove connection with record " + cb.getKnowledgeBaseId() + ";"; - else if(cb.isConnect()) + else if(cb.isConnect()){ + addConnectionHashtag = true; report += "\n\t - add connection with record " + cb.getKnowledgeBaseId() + ";"; + }else + report += "\n\t - keep this suggestion " + cb.getKnowledgeBaseId() + ";"; } + + if(addConnectionHashtag) + hashtags.add(HashTagsOnUpdate.CONNECT.getString()); } // update similar records and to connect @@ -420,19 +443,21 @@ public class ManageProductWidget extends Composite{ bean.getSimilarGrsfRecords().addAll(suggestedMergesPanel.getSimilarRecords()); // set the merge operator on the bean if there is at least one merge to be done - for(SimilarGRSFRecord sR: bean.getSimilarGrsfRecords()){ + if(!bean.getSimilarGrsfRecords().isEmpty()){ report += "\n- Suggested merges:"; - if(sR.isSuggestedMerge()){ - bean.setMergesInvolved(true); - report += "\n\t - merge the current record with record " + sR.getKnowledgeBaseId() + ";"; - } + for(SimilarGRSFRecord sR: bean.getSimilarGrsfRecords()){ - if(bean.isMergesInvolved()){ - report += "\n- The update involves a merge operation."; - hashtags.add(HashTagsOnUpdate.MERGE.getString()); + if(sR.isSuggestedMerge()){ + bean.setMergesInvolved(true); + report += "\n\t - merge the current record with record " + sR.getKnowledgeBaseId() + ";"; + } + + if(bean.isMergesInvolved()){ + report += "\n- The update involves a merge operation."; + hashtags.add(HashTagsOnUpdate.MERGE.getString()); + } } } - // set new values bean.setAnnotation(new HTML(annotationArea.getText().trim()).getText()); @@ -456,6 +481,9 @@ public class ManageProductWidget extends Composite{ // set the report bean.setReport(report); + // set hashtags + bean.setHashtags(hashtags); + GWT.log("Report is:\n" + report); service.notifyProductUpdate(bean, new AsyncCallback() { @@ -469,6 +497,7 @@ public class ManageProductWidget extends Composite{ manageProductModal.setCloseVisible(true); cancelButton.setEnabled(true); loaderIcon.setVisible(false); + updateSucceeded = true; } @Override @@ -486,6 +515,9 @@ public class ManageProductWidget extends Composite{ @UiHandler("cancelButton") void onCancelButton(ClickEvent ce){ manageProductModal.hide(); + + if(updateSucceeded) + Window.Location.reload(); } /** diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml index 9ba1cf0..f72746a 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml @@ -16,10 +16,6 @@ - - - @@ -158,13 +154,18 @@ + + + Cancel - Confirm + Confirm diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFUpdaterServiceClient.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFUpdaterServiceClient.java index db43d33..8cac604 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFUpdaterServiceClient.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFUpdaterServiceClient.java @@ -81,7 +81,7 @@ public class GRSFUpdaterServiceClient { } return toReturn; } - + /** * Send updates to the knowledge base * @param httpClient @@ -125,8 +125,8 @@ public class GRSFUpdaterServiceClient { cc.put(Constants.DEST_KNOWLEDGE_BASE_ID, c.getKnowledgeBaseId()); cc.put(Constants.SOURCE_DOMAIN, bean.getDomain()); cc.put(Constants.CONNECTION_TO_REMOVE, c.isRemove()); + connectionsJson.add(cc); } - connectionsJson.add(cc); } obj.put(Constants.CONNECTIONS, connectionsJson); @@ -143,6 +143,8 @@ public class GRSFUpdaterServiceClient { logger.info("Update request looks like " + obj.toJSONString()); + logger.info("Sending request to " + serviceUrl + Constants.SERVICE_POST_UPDATER_METHOD); + HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_UPDATER_METHOD); request.setHeader("Accept", "application/json"); request.setHeader("Content-type", "application/json"); @@ -160,7 +162,7 @@ public class GRSFUpdaterServiceClient { throw new Exception("There was a problem while performing this operation at knowledge base side"); if(response.getStatusLine().getStatusCode() == 200){ - logger.info("Record updated " + bean); + logger.info("Record updated "); }else if(!(boolean) parsedJSON.get(Constants.UPDATE_RESULT)) throw new IllegalArgumentException( "Update failed for the following reason " + parsedJSON.get(Constants.ERROR_MESSAGE)); diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/SocialCommunications.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/SocialCommunications.java index efc4afa..494e8ba 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/SocialCommunications.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/SocialCommunications.java @@ -23,10 +23,9 @@ import org.gcube.datacatalogue.grsf_manage_widget.shared.RevertableOperations; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.api.SimpleQuery; import org.gcube.vomanagement.usermanagement.RoleManager; -import org.gcube.vomanagement.usermanagement.UserManager; import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager; import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; -import org.gcube.vomanagement.usermanagement.model.GCubeTeam; +import org.gcube.vomanagement.usermanagement.model.GCubeUser; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.slf4j.Logger; @@ -59,9 +58,9 @@ public class SocialCommunications { private static final String serviceClass = "Portal"; // social operations - private static final String SOCIAL_SERVICE_APPLICATION_TOKEN = "/2/tokens/generate-application-token/"; - private static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST = "/2/posts/write-post-app/"; - private static final String SOCIAL_SEND_EMAIL = "/2/messages/write-message/"; + private static final String SOCIAL_SERVICE_APPLICATION_TOKEN = "2/tokens/generate-application-token"; + private static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST = "2/posts/write-post-app"; + private static final String SOCIAL_SEND_EMAIL = "2/messages/write-message"; private static final String MEDIATYPE_JSON = "application/json"; // for writing a post in the GRSF admin context @@ -70,17 +69,17 @@ public class SocialCommunications { // emails to be sent to editors and reviewers and post to be written into the grsf admin vre private static final String POST_MESSAGE = "Dear members," + "
The record 'PRODUCT_TITLE' has been just updated by USER_FULLNAME." - + "
You can inspect it here: PRODUCT_URL
"; + + "
You can inspect it here: LINK_RECORD."; private static final String EMAIL_MESSAGE_REVIEWER = "Dear GRSF Reviewer," + "
an update on the record named 'PRODUCT_TITLE' has been requested by USER_FULLNAME." - + "
It is available here LINK_RECORD."; + + "
You can inspect it here: LINK_RECORD."; private static final String EMAIL_MESSAGE_EDITOR = "Dear USER_FULLNAME," + "
your request for the record 'PRODUCT_TITLE' has been accepted." - + "
It is available here LINK_RECORD."; + + "
You can inspect it here: LINK_RECORD."; - private static final String ADD_REPORT = "
This is a summary of the actions proposed:
REPORT_UPDATE
"; + private static final String ADD_REPORT = "

This is a summary of the actions proposed:
REPORT_UPDATE
"; // revert link private static final String REVERT_LINK_PIECE = "
The request involves a merge operation. You can reject the merge by exploiting this link LINK in the following 24 hours."; @@ -151,7 +150,9 @@ public class SocialCommunications { String currentScope = ScopeProvider.instance.get(); String tokenUser = SecurityTokenProvider.instance.get(); - logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************"); + //return "b159b50c-c0f8-4a4c-bac9-b6149d6b81fc-98187548"; + + logger.info("Current scope for requireApplicationToken is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************"); String basePath = serviceUrl; if(basePath == null){ @@ -168,6 +169,7 @@ public class SocialCommunications { // ask token application HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser); JSONObject requestToken = new JSONObject(); + // requestToken.put("app_id", APPLICATION_ID_CATALOGUE_MANAGER.split("\\.")[APPLICATION_ID_CATALOGUE_MANAGER.split("\\.").length - 1]); // TODO requestToken.put("app_id", APPLICATION_ID_CATALOGUE_MANAGER); StringEntity input = new StringEntity(requestToken.toJSONString()); input.setContentType(MEDIATYPE_JSON); @@ -189,9 +191,7 @@ public class SocialCommunications { + " Error message is " + mapResponseGeneratedToken.get("message")); }else{ - return (String)mapResponseGeneratedToken.get("result"); - } } @@ -219,7 +219,7 @@ public class SocialCommunications { String currentScope = ScopeProvider.instance.get(); String tokenUser = SecurityTokenProvider.instance.get(); - logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************"); + logger.info("Current scope for writePostOnRevert is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************"); String basePath = serviceUrl; if(basePath == null){ @@ -300,12 +300,14 @@ public class SocialCommunications { String applicationToken = requireApplicationToken(serviceUrl); // replace - String message = POST_MESSAGE.replace("PRODUCT_TITLE", bean.getTitle()).replace("PRODUCT_URL", bean.getUrl()). + String message = POST_MESSAGE.replace("PRODUCT_TITLE", bean.getTitle()).replace("LINK_RECORD", bean.getUrl()). replace("USER_FULLNAME", fullName); - if(bean.getReport() != null) + + if(bean.getReport() != null && !bean.getReport().isEmpty()) message += ADD_REPORT.replace("REPORT_UPDATE", bean.getReport()); Set hashtags = bean.getHashtags(); + logger.debug("Hashtags are " + hashtags); if(hashtags != null && !hashtags.isEmpty()){ message +="

"; for (String hashtag : hashtags) { @@ -345,30 +347,30 @@ public class SocialCommunications { * @throws Exceptio */ @SuppressWarnings("unchecked") - public static void sendEmailAdministratorsOnMerge( + public static void sendEmailAdministrators( String serviceUrl, ManageProductBean bean, DataCatalogue catalogue, String username, String fullName, long groupId, - HttpServletRequest httpServletRequest, + String clientCurrenturl, boolean isMergeInvolved) throws Exception { // get the list of GRSF Reviewers to alert them as well RoleManager roleManager = new LiferayRoleManager(); - List teamRoles = roleManager.listTeamsByGroup(groupId); - List reviewers = new ArrayList<>(); - UserManager um = new LiferayUserManager(); + long teamRoleId = roleManager.getTeam(groupId, Constants.GRSF_CATALOGUE_REVIEWER_ROLE).getTeamId(); + List reviewersGcube = new LiferayUserManager().listUsersByTeam(teamRoleId); + logger.debug("Reviewers are " + reviewersGcube); - for(GCubeTeam tr: teamRoles){ - if(tr.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE)) - reviewers.add(um.getUserById(tr.getUserId()).getUsername()); + List reviewers = new ArrayList(reviewersGcube.size()); + + for(GCubeUser gU: reviewersGcube){ + // if the user is a reviewer, then send the email just once + if(!gU.getUsername().equals(username)) + reviewers.add(gU.getUsername()); } - // if the user is a reviewer, then send the email just once - reviewers.remove(username); - logger.info("List of " + Constants.GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers); // build the url that allows to revert the operation @@ -394,7 +396,10 @@ public class SocialCommunications { /// require url String applicationToken = requireApplicationToken(serviceUrl); - String revertUrl = getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseId(), httpServletRequest); + + String revertUrl = ""; + if(isMergeInvolved) + revertUrl = getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseId(), clientCurrenturl); String messageToEditor = (EMAIL_MESSAGE_EDITOR + (isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getTitle()). @@ -402,6 +407,8 @@ public class SocialCommunications { String messageToReviewer = (EMAIL_MESSAGE_REVIEWER+ (isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getTitle()). replace("LINK_RECORD", bean.getUrl()).replace("LINK", revertUrl); + + String subject = "Update request on GRSF Record"; // append report @@ -410,6 +417,9 @@ public class SocialCommunications { messageToReviewer += ADD_REPORT.replace("REPORT_UPDATE", bean.getReport()); } + messageToEditor = messageToEditor.replace("
", "\n"); + messageToReviewer = messageToReviewer.replace("
", "\n"); + // send email to the editor logger.info("The message that is going to be send to the editor is\n" + messageToEditor); HttpPost postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken); @@ -424,6 +434,9 @@ public class SocialCommunications { StringEntity input = new StringEntity(reqMessage.toJSONString()); input.setContentType(MEDIATYPE_JSON); postRequest.setEntity(input); + + logger.debug("Whole editor message is going to be " + reqMessage.toJSONString()); + CloseableHttpResponse response = client.execute(postRequest); Map mapResponseWritePost = getResponseEntityAsJSON(response); @@ -449,11 +462,14 @@ public class SocialCommunications { input = new StringEntity(reqMessage.toJSONString()); input.setContentType(MEDIATYPE_JSON); postRequest.setEntity(input); + + logger.debug("Whole reviewers message is going to be " + reqMessage.toJSONString()); + response = client.execute(postRequest); mapResponseWritePost = getResponseEntityAsJSON(response); if (response.getStatusLine().getStatusCode() != 201){ - logger.error("Failed to send message to editor : HTTP error code : " + logger.error("Failed to send message to reviewers : HTTP error code : " + response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message")); } @@ -473,18 +489,18 @@ public class SocialCommunications { // get the list of GRSF Reviewers to alert them as well RoleManager roleManager = new LiferayRoleManager(); - List teamRoles = roleManager.listTeamsByGroup(groupId); - List reviewers = new ArrayList<>(); - UserManager um = new LiferayUserManager(); + long teamRoleId = roleManager.getTeam(groupId, Constants.GRSF_CATALOGUE_REVIEWER_ROLE).getTeamId(); + List reviewersGcube = new LiferayUserManager().listUsersByTeam(teamRoleId); + logger.debug("Reviewers are " + reviewersGcube); - for(GCubeTeam tr: teamRoles){ - if(tr.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE)) - reviewers.add(um.getUserById(tr.getUserId()).getUsername()); + List reviewers = new ArrayList(reviewersGcube.size()); + + for(GCubeUser gU: reviewersGcube){ + // if the user is a reviewer, then send the email just once + if(!gU.getUsername().equals(rInfo.getUserNameOriginalAdmin())) + reviewers.add(gU.getUsername()); } - // if the user is a reviewer, then send the email just once - reviewers.remove(rInfo.getUserNameOriginalAdmin()); - logger.info("List of " + Constants.GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers); // discover service endpoint for the social networking library @@ -574,9 +590,9 @@ public class SocialCommunications { * @return * @throws Exception */ - public static String getEncodedUrlManage(RevertableOperations operation, String administrator, long timestamp, String uuid, HttpServletRequest httpServletRequest) throws Exception{ - String clientUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters - RevertOperationUrl operationUrl = new RevertOperationUrl(clientUrl, administrator, timestamp, uuid, operation); + public static String getEncodedUrlManage(RevertableOperations operation, String administrator, long timestamp, String uuid, String clientCurrenturl) throws Exception{ + logger.info("Request for revert link. Client current url is " + clientCurrenturl); + RevertOperationUrl operationUrl = new RevertOperationUrl(clientCurrenturl, administrator, timestamp, uuid, operation); String shortUrl = operationUrl.getShortUrl(); return shortUrl; } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java index 00f8252..f163c8c 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java @@ -207,6 +207,9 @@ public class Utils { // require social networking url final String baseUrlSocial = SocialCommunications.getBaseUrlSocialService(httpServletRequest); + // and the user current browser url + final String currentBrowserUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters + // manage interactions through a separated thread but set there security token and context (and then reset them) Thread t = new Thread(new Runnable() { @@ -217,10 +220,10 @@ public class Utils { try{ // send email to Editors and Reviewers - SocialCommunications.sendEmailAdministratorsOnMerge(baseUrlSocial, bean, catalogue, username, fullName, - groupId, httpServletRequest, bean.isMergesInvolved()); + SocialCommunications.sendEmailAdministrators(baseUrlSocial, bean, catalogue, username, fullName, + groupId, currentBrowserUrl, bean.isMergesInvolved()); - // create a post about the operation + // create a post about the operation SocialCommunications.writeProductPost(baseUrlSocial, bean, username, fullName, false); }catch(Exception e){ @@ -277,7 +280,7 @@ public class Utils { SecurityTokenProvider.instance.reset(); } } - + }); t.start();