added report and hastags evaluation. Partially revised the SocialCommunication class

git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/widgets/grsf-manage-widget@162944 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Costantino Perciante 2018-02-05 16:16:14 +00:00
parent 1d388e0c57
commit 2aa9b3dd42
23 changed files with 735 additions and 597 deletions

View File

@ -20,7 +20,6 @@
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="${webappDirectory}/WEB-INF/classes" path="src/main/resources">
@ -28,7 +27,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>

View File

@ -1,13 +1,13 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.compiler.source=1.7

View File

@ -4,10 +4,6 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>
<dependent-module archiveName="ckan-util-library-2.4.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/ckan-util-library/ckan-util-library">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="context-root" value="grsf-manage-widget"/>
<property name="java-output-path" value="/grsf-manage-widget/target/grsf-manage-widget-1.0.0-SNAPSHOT/WEB-INF/classes"/>
</wb-module>

View File

@ -3,5 +3,5 @@
<fixed facet="wst.jsdt.web"/>
<installed facet="jst.web" version="2.3"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="java" version="1.8"/>
<installed facet="java" version="1.7"/>
</faceted-project>

View File

@ -117,18 +117,18 @@
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope-maps</artifactId>
<scope>compile</scope>
<scope>provided</scope>
<!-- put at provided for deploying -->
</dependency>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-encryption</artifactId>
<scope>compile</scope>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-client</artifactId>
<scope>compile</scope>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@ -12,8 +12,7 @@ public class GRSFManageWidget implements EntryPoint {
*/
public void onModuleLoad(){
// HandlerManager eventBus = new HandlerManager(null);
//RootPanel.get("manageDiv").add(new ManageProductWidget("fffb6167-b570-42a8-92b9-5be28549c3b8", eventBus));
// RootPanel.get("manageDiv").add(new ManageRevertOperationWidget(
// "random-url-here", eventBus));
// RootPanel.get("manageDiv").add(new ManageProductWidget("fffb6167-b570-42a8-92b9-5be28549c3b8", eventBus));
// RootPanel.get("manageDiv").add(new ManageRevertOperationWidget("random-url-here", eventBus));
}
}

View File

@ -26,7 +26,7 @@ public interface GRSFManageWidgetService extends RemoteService {
/**
* Notify product update
*/
String notifyProductUpdate(ManageProductBean bean) throws Exception;
void notifyProductUpdate(ManageProductBean bean) throws Exception;
/**
* Identifier of the record (UUID)

View File

@ -15,7 +15,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
public interface GRSFManageWidgetServiceAsync {
void notifyProductUpdate(ManageProductBean bean,
AsyncCallback<String> callback);
AsyncCallback<Void> callback);
void getProductBeanById(String identifier,
AsyncCallback<ManageProductBean> callback);

View File

@ -2,7 +2,9 @@ package org.gcube.datacatalogue.grsf_manage_widget.client.view;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.gcube.datacatalogue.common.enums.Status;
import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetService;
@ -12,6 +14,8 @@ import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.Connect
import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SimilarGRSFRecordWidget;
import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SourceWidget;
import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SuggestMerges;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ConnectedBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.HashTagsOnUpdate;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord;
import org.gcube.datacatalogue.grsf_manage_widget.shared.SourceRecord;
@ -31,7 +35,6 @@ import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
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.ClickEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.uibinder.client.UiBinder;
@ -173,7 +176,7 @@ public class ManageProductWidget extends Composite{
// show modal
manageProductModal.addStyleName("management-metadata-modal-style");
manageProductModal.getElement().getStyle().setWidth(60, Unit.PCT);
// manageProductModal.getElement().getStyle().setWidth(60, Unit.PCT);
manageProductModal.show();
// async request to fetch the product
@ -222,7 +225,7 @@ public class ManageProductWidget extends Composite{
infoBlock.setVisible(false);
// top: more or less fixed information
GRSFNameTexBox.setText(bean.getGrsfName());
GRSFNameTexBox.setText(bean.getTitle());
shortNameTextBox.setText(bean.getShortName());
semanticIdentifierTextBox.setText(bean.getSemanticIdentifier());
productGrsfType.setText(bean.getGrsfType());
@ -244,7 +247,7 @@ public class ManageProductWidget extends Composite{
similarGRSFRecordGroup.setVisible(false);
// further suggested merges
suggestedMergesPanel = new SuggestMerges(service);
suggestedMergesPanel = new SuggestMerges(service, bean.getDomain());
panelForFurtherMerges.add(suggestedMergesPanel);
// prepare "connect" panel
@ -309,11 +312,19 @@ public class ManageProductWidget extends Composite{
@UiHandler("confirmButton")
void onSaveButton(ClickEvent ce){
String report = "";
Set<String> hashtags = new HashSet<>();
// if the status has not be changed ...
if(listBoxStatus.getSelectedIndex() <= 0)
if(listBoxStatus.getSelectedIndex() <= 0){
bean.setNewStatus(bean.getCurrentStatus());
else
report = "-The Status is unchanged";
}
else{
bean.setNewStatus(Status.fromString(listBoxStatus.getSelectedItemText()));
report = "-The Status has been changed to " + bean.getNewStatus().getOrigName();
hashtags.add(bean.getNewStatus().getOrigName());
}
manageProductModal.setCloseVisible(false);
cancelButton.setEnabled(false);
@ -323,9 +334,26 @@ public class ManageProductWidget extends Composite{
// get short name
bean.setShortNameUpdated(shortNameTextBox.getText());
if(bean.getShortName() != bean.getShortNameUpdated()){
report += "\n- The GRSF Short Name has been changed to '" + bean.getShortNameUpdated() + "'";
hashtags.add(HashTagsOnUpdate.SHORTNAME_UPDATED.getString());
}
// evaluate the connections and the actions on them
bean.setConnections(connectWidget.getConnectList());
// add the connections for the report
if(!bean.getConnections().isEmpty()){
report += "\n- Suggested connections:";
hashtags.add(HashTagsOnUpdate.CONNECT.getString());
for(ConnectedBean cb: bean.getConnections()){
if(cb.isRemove())
report += "\n\t - remove connection with record " + cb.getKnowledgeBaseId() + ";";
else if(cb.isConnect())
report += "\n\t - add connection with record " + cb.getKnowledgeBaseId() + ";";
}
}
// update similar records and to connect
if(similarRecordPanel != null)
bean.setSimilarGrsfRecords(similarRecordPanel.getSimilarRecords());
@ -337,33 +365,51 @@ public class ManageProductWidget extends Composite{
// set the merge operator on the bean if there is at least one merge to be done
for(SimilarGRSFRecord sR: bean.getSimilarGrsfRecords()){
report += "\n- Suggested merges:";
if(sR.isSuggestedMerge()){
bean.setMergesInvolved(true);
break;
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());
// traceability flag
bean.setTraceabilityFlag(traceabilityFlag.getValue());
if(bean.getAnnotation() != null && !bean.getAnnotation().isEmpty())
report += "\n- Annotation message is: " + bean.getAnnotation();
service.notifyProductUpdate(bean, new AsyncCallback<String>() {
// traceability flag
Boolean traceabilityNewValue = traceabilityFlag.getValue();
boolean currentTraceabilitFlag = bean.isTraceabilityFlag();
if(!traceabilityNewValue.equals(currentTraceabilitFlag)){
report += "\n- Traceability flag has been changed to: " + traceabilityNewValue;
if(traceabilityNewValue)
hashtags.add(HashTagsOnUpdate.TRACEABILITY_FLAG_SET.getString());
else
hashtags.add(HashTagsOnUpdate.TRACEABILITY_FLAG_UNSET.getString());
}
bean.setTraceabilityFlag(traceabilityNewValue);
// set the report
bean.setReport(report);
GWT.log("Report is:\n" + report);
service.notifyProductUpdate(bean, new AsyncCallback<Void>() {
@Override
public void onSuccess(String result) {
if(result == null){
showInfo(STATUS_UPDATE_SUCCESS, AlertType.SUCCESS);
confirmButton.removeFromParent();
formUpdate.setVisible(false);
}else{
showInfo(STATUS_UPDATE_ERROR + "(" + result + ")", AlertType.ERROR);
confirmButton.setEnabled(true);
}
public void onSuccess(Void v) {
showInfo(STATUS_UPDATE_SUCCESS, AlertType.SUCCESS);
confirmButton.removeFromParent();
formUpdate.setVisible(false);
manageProductModal.setCloseVisible(true);
cancelButton.setEnabled(true);
loaderIcon.setVisible(false);

View File

@ -17,7 +17,6 @@ import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@ -76,15 +75,12 @@ public class ManageRevertOperationWidget extends Composite {
private static GRSFManageWidgetServiceAsync service = GWT.create(GRSFManageWidgetService.class);
private HandlerManager eventBus;
public static final String LOADING_IMAGE_URL = GWT.getModuleBaseURL() + "../images/loader.gif";
private RevertableOperationInfo revertableOperation = null;
public ManageRevertOperationWidget(String encryptedUrlOperation, HandlerManager eventBus) {
public ManageRevertOperationWidget(String encryptedUrlOperation) {
initWidget(uiBinder.createAndBindUi(this));
this.eventBus = eventBus;
GWT.log("Encrypted url is " + encryptedUrlOperation);
if(encryptedUrlOperation == null || encryptedUrlOperation.isEmpty())
@ -99,6 +95,8 @@ public class ManageRevertOperationWidget extends Composite {
// revertOperationModal.getElement().getStyle().setWidth(60, Unit.PCT);
revertOperationModal.show();
moreInfoAboutOperation.getElement().getStyle().setMarginBottom(50, Unit.PX);
// async request to fetch the product
loadModalContent(encryptedUrlOperation);
@ -106,7 +104,6 @@ public class ManageRevertOperationWidget extends Composite {
/**
* Validate the parameters of the url and ask the editor/reviewer what he/she wants to do.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
* @param encryptedUrlOperation
*/
private void loadModalContent(String encryptedUrlOperation) {
@ -123,7 +120,7 @@ public class ManageRevertOperationWidget extends Composite {
if(result != null){
revertableOperation = result;
String dateString = DateTimeFormat.getFormat("MM/dd/yyyy HH:mm:ss").format(new Date(revertableOperation.getTimestamp()));
requestAuthor.setText(revertableOperation.getAdmin());
requestAuthor.setText(revertableOperation.getFullNameOriginalAdmin() + "(" + revertableOperation.getUserNameOriginalAdmin() + ")");
requestTypeBox.setText(revertableOperation.getOperation().toString().toUpperCase());
requestRecordUUID.setText(revertableOperation.getUuid());
requestTimestamp.setText(dateString);
@ -133,7 +130,7 @@ public class ManageRevertOperationWidget extends Composite {
viewRecord.getElement().getStyle().setFontWeight(FontWeight.BOLD);
viewRecord.setHref(revertableOperation.getRecordUrl());
viewRecord.setTarget("_blank");
viewRecord.getElement().getStyle().setMarginBottom(20, Unit.PX);
moreInfoAboutOperation.add(viewRecord);
moreInfoAboutOperation.setVisible(true);
revertButton.setEnabled(true);

View File

@ -16,10 +16,6 @@
<b:Image ui:field="loadingImage" styleName="{style.loader-image}"
visible="true"></b:Image>
<!-- Alert blocks for info/errors -->
<b:AlertBlock type="INFO" close="false" animation="true"
visible="false" ui:field="infoBlock"></b:AlertBlock>
<g:VerticalPanel ui:field="moreInfoAboutOperation"
visible="false" width="100%">
@ -75,6 +71,10 @@
</b:Form>
</g:VerticalPanel>
<!-- Alert blocks for info/errors -->
<b:AlertBlock type="INFO" close="false" animation="true"
visible="false" ui:field="infoBlock"></b:AlertBlock>
</g:VerticalPanel>
<b:ModalFooter>
<b:Icon type="GEAR" spin="true" ui:field="loaderIcon"

View File

@ -9,25 +9,18 @@ import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetService
import org.gcube.datacatalogue.grsf_manage_widget.shared.ConnectedBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean;
import com.github.gwtbootstrap.client.ui.AppendButton;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.CheckBox;
import com.github.gwtbootstrap.client.ui.Icon;
import com.github.gwtbootstrap.client.ui.Paragraph;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.ButtonType;
import com.github.gwtbootstrap.client.ui.constants.IconType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style.Float;
import com.google.gwt.dom.client.Style.FontWeight;
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;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
@ -47,8 +40,6 @@ public class ConnectToWidget extends Composite{
private static ConnectToWidgetUiBinder uiBinder = GWT
.create(ConnectToWidgetUiBinder.class);
private static final String REGEX_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
interface ConnectToWidgetUiBinder extends UiBinder<Widget, ConnectToWidget> {
}
@ -92,9 +83,9 @@ public class ConnectToWidget extends Composite{
}
// manage the button for manual suggestion
final String acceptedDomain = bean.getGrsfDomain().equalsIgnoreCase(Product_Type.STOCK.getOrigName()) ?
final String acceptedDomain = bean.getDomain().equalsIgnoreCase(Product_Type.STOCK.getOrigName()) ?
Product_Type.FISHERY.getOrigName() : Product_Type.STOCK.getOrigName();
suggestRecord.setTitle("Connect this " + bean.getGrsfDomain() + " record to a " + acceptedDomain + " record ");
suggestRecord.setTitle("Connect this " + bean.getDomain() + " record to a " + acceptedDomain + " record ");
suggestRecord.setText("Add Connection");
suggestRecord.setType(ButtonType.LINK);
suggestRecord.getElement().getStyle().setFontWeight(FontWeight.BOLD);
@ -190,54 +181,44 @@ public class ConnectToWidget extends Composite{
private Tuple buildWidgetConnect(final ConnectedBean cb, final String acceptedDomain){
VerticalPanel main = new VerticalPanel();
main.setWidth("100%");
HorizontalPanel hp = new HorizontalPanel();
main.setWidth("100%");
hp.setWidth("100%");
VerticalPanel vpLeft = new VerticalPanel();
vpLeft.getElement().getStyle().setMarginLeft(15, Unit.PX);
vpLeft.setWidth("80%");
Paragraph semanticIdentifier = new Paragraph("UUID:");
final TextBox box = new TextBox();
final Icon icon = new Icon(IconType.OK_SIGN);
icon.setVisible(false);
icon.getElement().getStyle().setMarginLeft(10, Unit.PX);
icon.getElement().getStyle().setMarginTop(5, Unit.PX);
Paragraph identifier = new Paragraph("Record UUID:");
// view link
final Anchor view = new Anchor();
view.setText("View");
view.setTitle("Click to inspect the record");
view.setTarget("_blank");
view.getElement().getStyle().setFontWeight(FontWeight.BOLD);
view.setVisible(false);
// add a couple of handlers
box.addKeyPressHandler(new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
GWT.log("onKeyPress " + event.getNativeEvent().getKeyCode());
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
box.setFocus(false);
}
});
}
});
box.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
GWT.log("onChange");
validateUUID(box, cb, icon, view, acceptedDomain);
}
});
// a textbox with a validate button on the right side
AppendButton uuidAndValidateButton = new AppendButton();
final Button validateUUIDButton = new Button("Validate");
validateUUIDButton.setEnabled(false);
final PasteAwareTextBox box = new PasteAwareTextBox(validateUUIDButton);
box.setWidth("512px");
box.setPlaceholder("Copy and Paste the Identifier (UUID) of the record to connect here");
vpLeft.add(semanticIdentifier);
vpLeft.add(box);
box.setPlaceholder("Copy and Paste the Identifier (UUID) of the record to connect here, then validate");
validateUUIDButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
validateUUID(box, cb, view, validateUUIDButton, acceptedDomain);
}
});
uuidAndValidateButton.add(box);
uuidAndValidateButton.add(validateUUIDButton);
vpLeft.add(identifier);
vpLeft.add(uuidAndValidateButton);
vpLeft.add(view);
VerticalPanel vpRight = new VerticalPanel();
vpRight.setWidth("20%");
@ -274,66 +255,53 @@ public class ConnectToWidget extends Composite{
return new Tuple(cb, main, box);
}
protected void validateUUID(final TextBox box, final ConnectedBean c, final Icon icon, final Anchor view, final String acceptedDomain) {
if(!box.isEnabled())
return;
protected void validateUUID(final TextBox box, final ConnectedBean c, final Anchor view, final Button validateUUIDButton, final String acceptedDomain) {
validateUUIDButton.setText("Validating...");
validateUUIDButton.setEnabled(false);
box.setEnabled(false);
view.setVisible(false);
final String currentText = box.getText().trim();
c.setKnowledgeBaseId(null);
c.setConnect(false);
icon.setVisible(false);
view.setVisible(false);
icon.setSpin(false);
if(currentText == null || currentText.isEmpty())
return;
if(!currentText.matches(REGEX_UUID)){
icon.setType(IconType.BAN_CIRCLE);
icon.setTitle("Not a valid UUID");
icon.setVisible(true);
view.setVisible(false);
return;
}
// else check at server side if it exists
GWT.log("Text changed to " + currentText);
box.setEnabled(false);
icon.setIcon(IconType.ROTATE_RIGHT);
icon.setSpin(true);
service.checkIdentifierExistsInDomain(currentText, acceptedDomain, new AsyncCallback<String>() {
@Override
public void onSuccess(String result) {
icon.setSpin(false);
if(result != null){
c.setKnowledgeBaseId(currentText);
c.setConnect(true);
icon.setType(IconType.OK_CIRCLE);
icon.setTitle("Accepted");
view.setHref(result);
view.setVisible(true);
box.setEnabled(false);
validateUUIDButton.setText("Accepted");
validateUUIDButton.setType(ButtonType.SUCCESS);
validateUUIDButton.setEnabled(false);
}
else{
icon.setType(IconType.BAN_CIRCLE);
icon.setTitle("Not a valid UUID");
view.setVisible(false);
box.setEnabled(true);
validateUUIDButton.setText("Invalid");
validateUUIDButton.setType(ButtonType.DANGER);
validateUUIDButton.setEnabled(true);
}
icon.setVisible(true);
}
@Override
public void onFailure(Throwable caught) {
box.setEnabled(true);
icon.setSpin(false);
view.setVisible(false);
icon.setType(IconType.BAN_CIRCLE);
icon.setTitle(caught.getMessage());
validateUUIDButton.setText("Invalid");
validateUUIDButton.setTitle("Error is " + caught);
validateUUIDButton.setType(ButtonType.DANGER);
view.setVisible(false);
box.setEnabled(true);
}
});

View File

@ -0,0 +1,62 @@
package org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.Event;
/**
* A paste aware textbox widget.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class PasteAwareTextBox extends TextBox {
private Button toBeEnabled;
private static final String REGEX_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
public PasteAwareTextBox(Button b) {
super();
toBeEnabled = b;
sinkEvents(Event.ONPASTE);
sinkEvents(Event.ONCHANGE);
sinkEvents(Event.ONKEYPRESS);
}
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
switch (event.getTypeInt()) {
case Event.ONPASTE:
onEvent(getClipboardData(event));
break;
case Event.ONCHANGE:
case Event.ONKEYPRESS:
onEvent(this.getText());
break;
}
}
private void onEvent(String clipboardData) {
GWT.log("Current text is:" + clipboardData);
toBeEnabled.setEnabled(false);
if(clipboardData != null && !clipboardData.isEmpty()){
final String currentText = clipboardData.trim();
if(!currentText.matches(REGEX_UUID))
return;
else
toBeEnabled.setEnabled(true);
}
}
/**
* In case of PASTE event
* @param event
* @return
*/
private static native String getClipboardData(Event event) /*-{
return event.clipboardData.getData('text/plain');
}-*/;
}

View File

@ -7,22 +7,17 @@ import java.util.List;
import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetServiceAsync;
import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord;
import com.github.gwtbootstrap.client.ui.AppendButton;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.Icon;
import com.github.gwtbootstrap.client.ui.Paragraph;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.ButtonType;
import com.github.gwtbootstrap.client.ui.constants.IconType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Float;
import com.google.gwt.dom.client.Style.FontWeight;
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;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
@ -46,14 +41,12 @@ public class SuggestMerges extends Composite {
private List<Tuple> extraSimilarRecordsList = new ArrayList<Tuple>(0);
private static final String REGEX_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
interface SuggestMergesUiBinder extends UiBinder<Widget, SuggestMerges> {
}
private GRSFManageWidgetServiceAsync service;
public SuggestMerges(GRSFManageWidgetServiceAsync service) {
public SuggestMerges(GRSFManageWidgetServiceAsync service, final String acceptedDomain) {
initWidget(uiBinder.createAndBindUi(this));
this.service = service;
@ -69,7 +62,7 @@ public class SuggestMerges extends Composite {
@Override
public void onClick(ClickEvent arg0) {
SimilarGRSFRecord s = new SimilarGRSFRecord();
Widget w = buildWidgetForExtraSimilarRecord(s);
Widget w = buildWidgetForExtraSimilarRecord(s, acceptedDomain);
extraSimilarRecordsList.add(new Tuple(s, w, null));
similarGrsfRecordsSuggestedPanel.add(w);
}
@ -81,7 +74,7 @@ public class SuggestMerges extends Composite {
* @param w the widget
* @param s the similar record.
*/
private Widget buildWidgetForExtraSimilarRecord(final SimilarGRSFRecord s){
private Widget buildWidgetForExtraSimilarRecord(final SimilarGRSFRecord s, final String acceptedDomain){
VerticalPanel main = new VerticalPanel();
main.getElement().getStyle().setMarginTop(10, Unit.PX);
@ -95,12 +88,9 @@ public class SuggestMerges extends Composite {
HorizontalPanel textBoxIconContainer = new HorizontalPanel();
textBoxIconContainer.setWidth("100%");
Paragraph identifier = new Paragraph("UUID:");
final TextBox box = new TextBox();
final Icon icon = new Icon(IconType.OK_SIGN);
icon.setVisible(false);
icon.getElement().getStyle().setMarginLeft(10, Unit.PX);
icon.getElement().getStyle().setMarginTop(5, Unit.PX);
Paragraph identifier = new Paragraph("Record UUID:");
// view link
final Anchor view = new Anchor();
view.setText("View");
view.setTitle("Click to inspect the record");
@ -108,28 +98,26 @@ public class SuggestMerges extends Composite {
view.getElement().getStyle().setFontWeight(FontWeight.BOLD);
view.setVisible(false);
// add a couple of handlers
box.addKeyPressHandler(new KeyPressHandler() {
// a textbox with a validate button on the right side
AppendButton uuidAndValidateButton = new AppendButton();
final Button validateUUIDButton = new Button("Validate");
validateUUIDButton.setEnabled(false);
final PasteAwareTextBox box = new PasteAwareTextBox(validateUUIDButton);
box.setWidth("512px");
box.setPlaceholder("Copy and Paste the Identifier (UUID) of the record to merge, then validate");
validateUUIDButton.addClickHandler(new ClickHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
validateUUID(box, s, icon, view);
public void onClick(ClickEvent event) {
validateUUID(box, s, view, validateUUIDButton, acceptedDomain);
}
});
box.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
GWT.log("onChange");
validateUUID(box, s, icon, view);
}
});
box.setWidth("511px");
box.setPlaceholder("Insert the Identifier (UUID) of the record to be merged");
uuidAndValidateButton.add(box);
uuidAndValidateButton.add(validateUUIDButton);
vpLeft.add(identifier);
textBoxIconContainer.add(box);
textBoxIconContainer.add(icon);
vpLeft.add(textBoxIconContainer);
vpLeft.add(uuidAndValidateButton);
vpLeft.add(view);
// the right side
@ -179,68 +167,53 @@ public class SuggestMerges extends Composite {
* @param icon
* @param view
*/
protected void validateUUID(final TextBox box, final SimilarGRSFRecord s, final Icon icon, final Anchor view) {
protected void validateUUID(final TextBox box, final SimilarGRSFRecord s, final Anchor view, final Button validateUUIDButton, final String acceptedDomain) {
if(!box.isEnabled())
return;
validateUUIDButton.setText("Validating...");
validateUUIDButton.setEnabled(false);
box.setEnabled(false);
view.setVisible(false);
final String currentText = box.getText().trim();
s.setKnowledgeBaseId(null);
s.setSuggestedMerge(false);
icon.setVisible(false);
view.setVisible(false);
icon.setSpin(false);
if(currentText == null || currentText.isEmpty())
return;
if(!currentText.matches(REGEX_UUID)){
icon.setType(IconType.BAN_CIRCLE);
icon.setTitle("Not a valid UUID");
icon.setVisible(true);
return;
}
// else check at server side if it exists
GWT.log("Text changed to " + currentText);
box.setEnabled(false);
icon.setVisible(true);
icon.setIcon(IconType.ROTATE_RIGHT);
icon.setTitle("Checking...");
icon.setSpin(true);
service.checkIdentifierExistsInDomain(currentText, s.getDomain(), new AsyncCallback<String>() {
service.checkIdentifierExistsInDomain(currentText, acceptedDomain, new AsyncCallback<String>() {
@Override
public void onSuccess(String result) {
icon.setSpin(false);
if(result != null){
s.setKnowledgeBaseId(currentText);
s.setSuggestedMerge(true);
icon.setType(IconType.OK_CIRCLE);
icon.setTitle("Accepted");
view.setHref(result);
view.setVisible(true);
box.setEnabled(false);
validateUUIDButton.setText("Accepted");
validateUUIDButton.setType(ButtonType.SUCCESS);
validateUUIDButton.setEnabled(false);
}
else{
icon.setType(IconType.BAN_CIRCLE);
icon.setTitle("Not a valid UUID");
view.setVisible(false);
box.setEnabled(true);
validateUUIDButton.setText("Invalid");
validateUUIDButton.setType(ButtonType.DANGER);
validateUUIDButton.setEnabled(true);
}
icon.setVisible(true);
}
@Override
public void onFailure(Throwable caught) {
box.setEnabled(true);
icon.setSpin(false);
icon.setType(IconType.BAN_CIRCLE);
icon.setVisible(true);
view.setVisible(false);
icon.setTitle(caught.getMessage());
validateUUIDButton.setText("Invalid");
validateUUIDButton.setTitle("Error is " + caught);
validateUUIDButton.setType(ButtonType.DANGER);
view.setVisible(false);
box.setEnabled(true);
}
});
@ -257,7 +230,8 @@ public class SuggestMerges extends Composite {
SimilarGRSFRecord similarRecord = ((SimilarGRSFRecord)p.getO());
if(similarRecord.getKnowledgeBaseId() == null || similarRecord.getKnowledgeBaseId().isEmpty())
continue;
toReturn.add((SimilarGRSFRecord) p.getO());
similarRecord.setSuggestedMerge(true);
toReturn.add(similarRecord);
}
return toReturn;

View File

@ -28,6 +28,7 @@ import org.gcube.datacatalogue.grsf_manage_widget.shared.SourceRecord;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ex.NoGRSFRecordException;
import org.gcube.vomanagement.usermanagement.RoleManager;
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;
@ -85,6 +86,8 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
if(!Utils.isIntoPortal()){
Thread.sleep(2000);
toReturn = new ManageProductBean();
toReturn.setCatalogueIdentifier(UUID.randomUUID().toString());
List<ConnectedBean> connectTo = new ArrayList<>();
@ -112,12 +115,12 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
"Fishery"
));
toReturn.setSuggestedByKnowledgeBaseConnections(suggestionsForConnections);
toReturn.setGrsfDomain("Stock");
toReturn.setDomain("Stock");
toReturn.setGrsfType("Assessment Unit");
toReturn.setKnowledgeBaseIdentifier("91f1e413-dc9f-3b4e-b1c5-0e8560177253");
toReturn.setKnowledgeBaseId("91f1e413-dc9f-3b4e-b1c5-0e8560177253");
toReturn.setShortName("Widow rockfish - US West Coast");
toReturn.setShortNameUpdated("Widow rockfish - US West Coast");
toReturn.setGrsfName("sebastes entomelas FAO 77 FAO 67");
toReturn.setTitle("sebastes entomelas FAO 77 FAO 67");
toReturn.setTraceabilityFlag(true);
toReturn.setCurrentStatus(Status.Pending);
toReturn.setSemanticIdentifier("asfis:WRO+fao:67;FAO");
@ -217,6 +220,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
Map<String, List<String>> extrasWithoutNamespaces = Utils.replaceFieldsKey(extrasAsPairs, fieldsNamespacesMap);
String catalogueIdentifier = record.getId();
String description = record.getNotes();
Status status = Status.fromString(extrasWithoutNamespaces.get(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY).get(0));
String uuidKB = extrasWithoutNamespaces.get(Constants.UUID_KB_CUSTOM_KEY).get(0);
String grsfDomain = extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0);
@ -295,7 +299,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
// set the values
toReturn = new ManageProductBean(
semanticId, catalogueIdentifier, uuidKB, grsfType,
grsfDomain, grsfName, shortName, traceabilityFlag,
grsfDomain, shortName, description, grsfName,traceabilityFlag,
status, recordUrl, sources, similarRecords,
connectedBeans, suggestedConnectionsByKnowledgeBase);
@ -340,9 +344,13 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
}
@Override
public String notifyProductUpdate(ManageProductBean bean) throws Exception{
public void notifyProductUpdate(ManageProductBean bean) throws Exception{
logger.info("Creating notification for the bean " + bean + " to send to the knowledge base");
if(!Utils.isIntoPortal()){
Thread.sleep(2500);
return;
}
try{
String context = Utils.getScopeFromClientUrl(getThreadLocalRequest());
@ -364,8 +372,8 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
String sessionProductKey = ScopeProvider.instance.get() + bean.getCatalogueIdentifier();
threadRequest.getSession().removeAttribute(sessionProductKey);
return Utils.updateRecord(baseUrl, bean, catalogue, username, administratorFullName, threadRequest,
PortalContext.getConfiguration().getCurrentGroupId(threadRequest), context, token, bean.getReport());
Utils.updateRecord(baseUrl, bean, catalogue, username, administratorFullName, threadRequest,
PortalContext.getConfiguration().getCurrentGroupId(threadRequest), context, token);
}catch(Exception e){
logger.error("Unable to update the product", e);
@ -377,12 +385,22 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
public RevertableOperationInfo validateRevertOperation(String encryptedUrl) throws Exception {
if(!Utils.isIntoPortal()){
Thread.sleep(2000);
// random result
boolean throwException = Math.random() > 0.5;
if(throwException)
throw new Exception("Unable to parse the inserted url");
String baseUrl = "url of the record here";
String fullName = "Andrea Rossi";
String uuid = UUID.randomUUID().toString();
String adminInUrl = "costantino.perciante";
String adminInUrlFullName = "Costantino Perciante";
long timestamp = System.currentTimeMillis() - 1000 * ((long)(Math.random() * 10 * 60 * 60));
return new RevertableOperationInfo(baseUrl, fullName, uuid, adminInUrl, timestamp, RevertableOperations.MERGE);
return new RevertableOperationInfo(
baseUrl, fullName, uuid, adminInUrlFullName, adminInUrl, timestamp, RevertableOperations.MERGE);
}
PortalContext pContext = PortalContext.getConfiguration();
@ -403,31 +421,32 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
// decrypt the url
RevertOperationUrl decryptedUrl = new RevertOperationUrl(encryptedUrl);
String adminInUrl = decryptedUrl.getAdmin();
String userNameadminInUrl = decryptedUrl.getAdmin(); // this is the username
String fullNameadminInUrl = new LiferayUserManager().getUserByUsername(userNameadminInUrl).getFullname(); // this is the fullname
String uuid = decryptedUrl.getUuid();
logger.info("User " + username + " has requested to invert an operation on record with id " + uuid + " and admin in url is " + adminInUrl);
logger.info("User " + username + " has requested to invert an operation on record with id " + uuid + " and admin in url is " + userNameadminInUrl);
// we need to check the timestamp (it has 24h validity)
boolean isValidTimestamp = decryptedUrl.isTimestampValid();
if(!isValidTimestamp)
throw new Exception("This operation can no longer be reverted (link expired)!");
DataCatalogue catalogue = getCatalogue(context);
String recordUrl = catalogue.getDataset(uuid, catalogue.getApiKeyFromUsername(username)).getExtrasAsHashMap().get(Constants.ITEM_URL_FIELD);
// check if it is a reviewer, than he can do what he wants (no matter the admin)
if(isReviewer){
return new RevertableOperationInfo(recordUrl,
fullName, uuid, adminInUrl, decryptedUrl.getTimestamp(), decryptedUrl.getOperation());
fullName, uuid, fullNameadminInUrl, userNameadminInUrl, decryptedUrl.getTimestamp(), decryptedUrl.getOperation());
}else{
if(!username.equals(adminInUrl))
if(!username.equals(userNameadminInUrl))
throw new Exception("You are not the editor allowed to perform this operation!");
else
return new RevertableOperationInfo(recordUrl,
fullName, uuid, adminInUrl, decryptedUrl.getTimestamp(), decryptedUrl.getOperation());
fullName, uuid, fullNameadminInUrl, userNameadminInUrl, decryptedUrl.getTimestamp(), decryptedUrl.getOperation());
}
}
@ -435,25 +454,25 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
@Override
public Boolean performRevertOperation(RevertableOperationInfo rInfo)
throws Exception {
if(!Utils.isIntoPortal()){
// random result
boolean toReturn = Math.random() > 0.5;
if(toReturn){
boolean throwException = Math.random() > 0.5;
if(throwException)
throw new Exception("Unable to execute request for XYZ");
}
return toReturn;
}
HttpServletRequest threadRequest = getThreadLocalRequest();
String context = Utils.getScopeFromClientUrl(threadRequest);
String token = SecurityTokenProvider.instance.get();
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
String keyPerContext = UtilMethods.concatenateSessionKeyScope(Constants.GRSF_UPDATER_SERVICE, context);
@ -465,9 +484,10 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
if(baseUrl == null || baseUrl.isEmpty())
throw new Exception("Unable to discover grsf-updater service!");
Utils.revertOperation(httpClient, baseUrl, rInfo, token, context, PortalContext.getConfiguration().getCurrentGroupId(threadRequest));
Utils.revertOperation(httpClient, baseUrl, threadRequest, rInfo, token, context,
PortalContext.getConfiguration().getCurrentGroupId(threadRequest));
}
catch(Exception e){
logger.error("Unable to revert operation ", e);

View File

@ -98,7 +98,7 @@ public class GRSFUpdaterServiceClient {
JSONObject obj = new JSONObject();
obj.put(Constants.ADMINISTRATOR_FULLNAME, fullName);
obj.put(Constants.CATALOGUE_ID, bean.getCatalogueIdentifier());
obj.put(Constants.KB_ID, bean.getKnowledgeBaseIdentifier());
obj.put(Constants.KB_ID, bean.getKnowledgeBaseId());
obj.put(Constants.NEW_STATUS, bean.getNewStatus().toString().toLowerCase());
obj.put(Constants.OLD_STATUS, bean.getCurrentStatus().toString().toLowerCase());
obj.put(Constants.TRACEABILITY_FLAG, bean.isTraceabilityFlag());
@ -122,9 +122,9 @@ public class GRSFUpdaterServiceClient {
for(ConnectedBean c: connections){
JSONObject cc = new JSONObject();
if(c.isRemove() || (c.isConnect() && !c.isRemove())){ // do not send it if it needs to be unconnected but not removed
cc.put(Constants.SOURCE_KNOWLEDGE_BASE_ID, bean.getKnowledgeBaseIdentifier());
cc.put(Constants.SOURCE_KNOWLEDGE_BASE_ID, bean.getKnowledgeBaseId());
cc.put(Constants.DEST_KNOWLEDGE_BASE_ID, c.getKnowledgeBaseId());
cc.put(Constants.SOURCE_DOMAIN, bean.getGrsfDomain());
cc.put(Constants.SOURCE_DOMAIN, bean.getDomain());
cc.put(Constants.CONNECTION_TO_REMOVE, c.isRemove());
}
connectionsJson.add(cc);

View File

@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@ -15,6 +16,7 @@ import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.common.Constants;
import org.gcube.datacatalogue.grsf_manage_widget.shared.HashTagsOnUpdate;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.RevertableOperationInfo;
import org.gcube.datacatalogue.grsf_manage_widget.shared.RevertableOperations;
@ -34,6 +36,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpEntity;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.CloseableHttpResponse;
import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost;
import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity;
import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient;
@ -77,76 +80,79 @@ public class SocialCommunications {
+ "<br>your request for the record 'PRODUCT_TITLE' has been accepted."
+ "<br>It is available here LINK_RECORD.";
private static final String ADD_REPORT = "<br>This is a summary of the actions proposed:<br>REPORT_UPDATE<br>";
// revert link
private static final String REVERT_LINK_PIECE = "<br>The request involves a merge operation. You can reject the merge by exploiting this link LINK in the following 24 hours.";
// on revert operation
private static final String EMAIL_REVIEWER_REVERT = "Dear GRSF Reviewer,"
+ "<br>a revert operation (undo merge) has been requested on record RECORD_URL, by USERNAME.";
+ "<br>a revert operation (undo merge) has been requested on record RECORD_URL, by ADMIN_WHO_CHANGED.";
private static final String EMAIL_EDITOR_REVERT = "Dear USER_FULLNAME,"
+"<br> a revert operation (undo merge) has been requested on this RECORD_URL you managed.";
private static final String EMAIL_EDITOR_REVERT = "Dear ORIGINAL_USER,"
+"<br> a revert operation (undo merge) has been requested on this RECORD_URL you managed by ADMIN_WHO_CHANGED.";
// post on revert
private static final String POST_ON_REVERT = "Dear members,"
+ "<br>a merge operation has been reverted on this record RECORD_URL by ADMIN_WHO_CHANGED. The merge was originally proposed by ORIGINAL_USER.";
private static final String SOCIAL_NETWORKING_BASE_URL_SESSION_KEY = "SOCIAL_NETWORKING_SESSION_KEY";
/**
*
* @param httpServletRequest
* @param context
* @return
*/
private static String getBaseUrlSocialService(String context){
public static String getBaseUrlSocialService(HttpServletRequest httpServletRequest){
if(context == null || context.isEmpty())
throw new IllegalArgumentException("A valid context is needed to discover the service");
String context = ScopeProvider.instance.get();
String oldContext = ScopeProvider.instance.get();
ScopeProvider.instance.set(context);
String keyPerContext = SOCIAL_NETWORKING_BASE_URL_SESSION_KEY + context;
String basePath = (String) httpServletRequest.getSession().getAttribute(keyPerContext);
String basePath = null;
try{
if(basePath == null){
try{
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'",serviceClass));
query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'");
query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'",serviceName));
query.setResult("$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""+resource+"\"]/text()");
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'",serviceClass));
query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'");
query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'",serviceName));
query.setResult("$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""+resource+"\"]/text()");
DiscoveryClient<String> client = client();
List<String> endpoints = client.submit(query);
if (endpoints == null || endpoints.isEmpty())
throw new Exception("Cannot retrieve the GCoreEndpoint serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
DiscoveryClient<String> client = client();
List<String> endpoints = client.submit(query);
if (endpoints == null || endpoints.isEmpty())
throw new Exception("Cannot retrieve the GCoreEndpoint serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
basePath = endpoints.get(0);
if(basePath==null)
throw new Exception("Endpoint:"+resource+", is null for serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
basePath = endpoints.get(0);
if(basePath==null)
throw new Exception("Endpoint:"+resource+", is null for serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
}catch(Exception e){
logger.error("Unable to retrieve such service endpoint information!", e);
}finally{
if(oldContext != null && !oldContext.equals(context))
ScopeProvider.instance.set(oldContext);
httpServletRequest.getSession().setAttribute(keyPerContext, basePath);
}catch(Exception e){
logger.error("Unable to retrieve such service endpoint information!", e);
}
}
logger.info("Found base path " + basePath + " for the service");
return basePath;
}
/**
* Notify the users about the required changes.
* @param bean
* @param url
* @param username
* @param fullName
* @param hashtags
* @param enablePostNotification
* @throws Exception
* Require a proper application token for writing a post and send messages.
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static void writeProductPost(ManageProductBean bean, String username, String fullName, String report, boolean enablePostNotification) throws Exception{
private static String requireApplicationToken(String serviceUrl) throws Exception{
// discover service endpoint for the social networking library
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) + "***************");
String basePath = getBaseUrlSocialService(currentScope);
String basePath = serviceUrl;
if(basePath == null){
@ -161,7 +167,9 @@ public class SocialCommunications {
// ask token application
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
StringEntity input = new StringEntity("{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
JSONObject requestToken = new JSONObject();
requestToken.put("app_id", APPLICATION_ID_CATALOGUE_MANAGER);
StringEntity input = new StringEntity(requestToken.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
HttpResponse response = client.execute(postRequest);
@ -182,39 +190,144 @@ public class SocialCommunications {
}else{
String applicationToken = (String)mapResponseGeneratedToken.get("result");
return (String)mapResponseGeneratedToken.get("result");
// replace
String message = POST_MESSAGE.replace("PRODUCT_TITLE", bean.getGrsfName()).replace("PRODUCT_URL", bean.getRecordUrl()).replace("USER_FULLNAME", fullName);
// evaluate hashtags from the report ... TODO
// if(hashtags != null && !hashtags.isEmpty())
// for (String hashtag : hashtags) {
// String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_"); // no empty spaces allowed
// if(modifiedHashtag.endsWith("_"))
// modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1);
// message += " #" + modifiedHashtag;
// }
logger.info("The post that is going to be written is -> " + message);
postRequest = new HttpPost(basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + applicationToken);
JSONObject object = new JSONObject();
object.put("text", message);
object.put("enable_notification", enablePostNotification);
input = new StringEntity(object.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201)
throw new RuntimeException("Failed to write application post : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}
}catch(Exception e){
logger.error("Failed to create a post", e);
throw e;
}
}
}
/**
* Notify the users about the required changes.
* @param bean
* @param url
* @param username
* @param fullName
* @param hashtags
* @param enablePostNotification
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static void writePostOnRevert(String serviceUrl, RevertableOperationInfo rInfo, boolean enablePostNotification) throws Exception{
// discover service endpoint for the social networking library
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) + "***************");
String basePath = serviceUrl;
if(basePath == null){
logger.error("Unable to write a post because there is no social networking service available");
throw new Exception("Unable to discover the social networking service");
}else{
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// require url
String applicationToken = requireApplicationToken(serviceUrl);
// replace
String message = POST_ON_REVERT.replace("RECORD_URL", rInfo.getRecordUrl()).replace("ADMIN_WHO_CHANGED", rInfo.getFullNameCurrentAdmin()).replace("ORIGINAL_USER", rInfo.getFullNameOriginalAdmin());
// add hashtag
message +="<br><br>";
message += " #" + HashTagsOnUpdate.REVERTED_MERGE.getString();
logger.info("The post that is going to be written is -> " + message);
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + applicationToken);
JSONObject object = new JSONObject();
object.put("text", message);
object.put("enable_notification", enablePostNotification);
StringEntity input = new StringEntity(object.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
CloseableHttpResponse response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201)
throw new RuntimeException("Failed to write application post : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}catch(Exception e){
logger.error("Failed to create a post", e);
}
}
}
/**
* Notify the users about the required changes.
* @param bean
* @param url
* @param username
* @param fullName
* @param hashtags
* @param enablePostNotification
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static void writeProductPost(String serviceUrl, ManageProductBean bean, String username, String fullName, boolean enablePostNotification) throws Exception{
// discover service endpoint for the social networking library
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) + "***************");
String basePath = serviceUrl;
if(basePath == null){
logger.error("Unable to write a post because there is no social networking service available");
throw new Exception("Unable to discover the social networking service");
}else{
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// require url
String applicationToken = requireApplicationToken(serviceUrl);
// replace
String message = POST_MESSAGE.replace("PRODUCT_TITLE", bean.getTitle()).replace("PRODUCT_URL", bean.getUrl()).
replace("USER_FULLNAME", fullName);
if(bean.getReport() != null)
message += ADD_REPORT.replace("REPORT_UPDATE", bean.getReport());
Set<String> hashtags = bean.getHashtags();
if(hashtags != null && !hashtags.isEmpty()){
message +="<br><br>";
for (String hashtag : hashtags) {
message += " #" + hashtag;
}
}
logger.info("The post that is going to be written is -> " + message);
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + applicationToken);
JSONObject object = new JSONObject();
object.put("text", message);
object.put("enable_notification", enablePostNotification);
StringEntity input = new StringEntity(object.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
CloseableHttpResponse response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201)
throw new RuntimeException("Failed to write application post : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}catch(Exception e){
logger.error("Failed to create a post", e);
}
@ -233,6 +346,7 @@ public class SocialCommunications {
*/
@SuppressWarnings("unchecked")
public static void sendEmailAdministratorsOnMerge(
String serviceUrl,
ManageProductBean bean,
DataCatalogue catalogue,
String username,
@ -265,7 +379,7 @@ public class SocialCommunications {
String tokenUser = SecurityTokenProvider.instance.get();
logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************");
String basePath = getBaseUrlSocialService(currentScope);
String basePath = serviceUrl;
if(basePath == null){
@ -278,88 +392,69 @@ public class SocialCommunications {
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// ask token application
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
StringEntity input = new StringEntity("{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
/// require url
String applicationToken = requireApplicationToken(serviceUrl);
String revertUrl = getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseId(), httpServletRequest);
String messageToEditor = (EMAIL_MESSAGE_EDITOR +
(isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getTitle()).
replace("LINK_RECORD", bean.getUrl()).replace("LINK", revertUrl);
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
if(bean.getReport() != null){
messageToEditor += ADD_REPORT.replace("REPORT_UPDATE", bean.getReport());
messageToReviewer += ADD_REPORT.replace("REPORT_UPDATE", bean.getReport());
}
// 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);
JSONObject reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToEditor);
JSONArray recipients = new JSONArray();
JSONObject recipient = new JSONObject();
recipient.put("id", username);
recipients.add(recipient);
reqMessage.put("recipients", recipients);
StringEntity input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
HttpResponse response = client.execute(postRequest);
CloseableHttpResponse response = client.execute(postRequest);
logger.debug("Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed to retrieve application token : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}else{
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
Map<String, Object> mapResponseGeneratedToken = getResponseEntityAsJSON(response);
boolean successGeneratedToken = (boolean)mapResponseGeneratedToken.get("success");
if(!successGeneratedToken){
throw new RuntimeException("Failed to generate the token for the application!"
+ " Error message is " + mapResponseGeneratedToken.get("message"));
}else{
String applicationToken = (String)mapResponseGeneratedToken.get("result");
String revertUrl = getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseIdentifier(), httpServletRequest);
String messageToEditor = (EMAIL_MESSAGE_EDITOR +
(isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getGrsfName()).replace("LINK_RECORD", bean.getRecordUrl()).replace("LINK", revertUrl);
String messageToReviewer = (EMAIL_MESSAGE_REVIEWER+
(isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getGrsfName()).replace("LINK_RECORD", bean.getRecordUrl()).replace("LINK", revertUrl);
String subject = "Update request on GRSF Record";
// send email to the editor
logger.info("The message that is going to be send to the editor is\n" + messageToEditor);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
JSONObject reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToEditor);
JSONArray recipients = new JSONArray();
JSONObject recipient = new JSONObject();
recipient.put("id", username);
recipients.add(recipient);
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
// send email to the reviewers
logger.info("The message that is going to be send to the reviewers is\n" + messageToReviewer);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToReviewer);
recipients = new JSONArray();
for(String reviewer: reviewers){
JSONObject recip = new JSONObject();
recip.put("id", reviewer);
recipients.add(recip);
}
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}
// send email to the reviewers
logger.info("The message that is going to be send to the reviewers is\n" + messageToReviewer);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToReviewer);
recipients = new JSONArray();
for(String reviewer: reviewers){
JSONObject recip = new JSONObject();
recip.put("id", reviewer);
recipients.add(recip);
}
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}catch(Exception e){
@ -369,7 +464,9 @@ public class SocialCommunications {
}
@SuppressWarnings("unchecked")
public static void sendEmailAdministratorsOnOperationReverted(
String serviceUrl,
RevertableOperationInfo rInfo,
long groupId
) throws Exception {
@ -386,19 +483,16 @@ public class SocialCommunications {
}
// if the user is a reviewer, then send the email just once
reviewers.remove(rInfo.getAdmin());
reviewers.remove(rInfo.getUserNameOriginalAdmin());
logger.info("List of " + Constants.GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers);
// build the url that allows to revert the operation
RevertableOperations operation = RevertableOperations.MERGE;
// discover service endpoint for the social networking library
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) + "***************");
String basePath = getBaseUrlSocialService(currentScope);
String basePath = serviceUrl;
if(basePath == null){
@ -411,84 +505,59 @@ public class SocialCommunications {
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// ask token application
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
StringEntity input = new StringEntity("{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
String applicationToken = requireApplicationToken(serviceUrl);
String messageToEditor = EMAIL_EDITOR_REVERT.replace("RECORD_URL", rInfo.getRecordUrl()).replace("ORIGINAL_USER", rInfo.getFullNameOriginalAdmin()).
replace("ADMIN_WHO_CHANGED", rInfo.getFullNameCurrentAdmin());
String messageToReviewer = EMAIL_REVIEWER_REVERT.replace("ADMIN_WHO_CHANGED", rInfo.getFullNameCurrentAdmin()).replace("RECORD_URL", rInfo.getRecordUrl()).
replace("ORIGINAL_USER", rInfo.getFullNameOriginalAdmin());
String subject = "Revert merge request on GRSF Record";
// 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);
JSONObject reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToEditor);
JSONArray recipients = new JSONArray();
JSONObject recipient = new JSONObject();
recipient.put("id", rInfo.getUserNameOriginalAdmin());
recipients.add(recipient);
reqMessage.put("recipients", recipients);
StringEntity input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
HttpResponse response = client.execute(postRequest);
CloseableHttpResponse response = client.execute(postRequest);
logger.debug("Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed to retrieve application token : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}else{
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
Map<String, Object> mapResponseGeneratedToken = getResponseEntityAsJSON(response);
boolean successGeneratedToken = (boolean)mapResponseGeneratedToken.get("success");
if(!successGeneratedToken){
throw new RuntimeException("Failed to generate the token for the application!"
+ " Error message is " + mapResponseGeneratedToken.get("message"));
}else{
String applicationToken = (String)mapResponseGeneratedToken.get("result");
String messageToEditor = EMAIL_EDITOR_REVERT.replace("RECORD_URL", rInfo.getRecordUrl()).replace("USER_FULLNAME", rInfo.getFullName());
String messageToReviewer = EMAIL_REVIEWER_REVERT.replace("USER_FULLNAME", rInfo.getFullName()).replace("RECORD_URL", rInfo.getRecordUrl());
String subject = "Revert merge request on GRSF Record";
// send email to the editor
logger.info("The message that is going to be send to the editor is\n" + messageToEditor);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
JSONObject reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToEditor);
JSONArray recipients = new JSONArray();
JSONObject recipient = new JSONObject();
recipient.put("id", rInfo.getAdmin());
recipients.add(recipient);
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
// send email to the reviewers
logger.info("The message that is going to be send to the reviewers is\n" + messageToReviewer);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToReviewer);
recipients = new JSONArray();
for(String reviewer: reviewers){
JSONObject recip = new JSONObject();
recip.put("id", reviewer);
recipients.add(recip);
}
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}
// send email to the reviewers
logger.info("The message that is going to be send to the reviewers is\n" + messageToReviewer);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToReviewer);
recipients = new JSONArray();
for(String reviewer: reviewers){
JSONObject recip = new JSONObject();
recip.put("id", reviewer);
recipients.add(recip);
}
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}catch(Exception e){

View File

@ -178,17 +178,16 @@ public class Utils {
* @param catalogue
* @return true on success, false otherwise
*/
public static String updateRecord(
public static void updateRecord(
String serviceUrl,
ManageProductBean bean,
DataCatalogue catalogue,
String username,
String fullName,
HttpServletRequest httpServletRequest,
long groupId,
String context,
String token,
String report) throws Exception{
final ManageProductBean bean,
final DataCatalogue catalogue,
final String username,
final String fullName,
final HttpServletRequest httpServletRequest,
final long groupId,
final String context,
final String token) throws Exception{
if(serviceUrl == null)
throw new IllegalArgumentException("GRSF Updater service url cannot be null");
@ -205,35 +204,41 @@ public class Utils {
// send update to the knowledge base
GRSFUpdaterServiceClient.updateKB(httpClient, serviceUrl, bean, catalogue, username, fullName);
// require social networking url
final String baseUrlSocial = SocialCommunications.getBaseUrlSocialService(httpServletRequest);
// manage interactions through a separated thread but set there security token and context (and then reset them)
new Thread(()->{
Thread t = new Thread(new Runnable() {
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(token);
try{
@Override
public void run() {
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(token);
try{
// send email to Editors and Reviewers
SocialCommunications.sendEmailAdministratorsOnMerge(bean, catalogue, username, fullName, groupId, httpServletRequest, bean.isMergesInvolved());
// send email to Editors and Reviewers
SocialCommunications.sendEmailAdministratorsOnMerge(baseUrlSocial, bean, catalogue, username, fullName,
groupId, httpServletRequest, bean.isMergesInvolved());
// create a post about the operation
SocialCommunications.writeProductPost(bean, username, fullName, report, true);
// create a post about the operation
SocialCommunications.writeProductPost(baseUrlSocial, bean, username, fullName, false);
}catch(Exception e){
logger.error("Something failed while alerting editors/reviewers", e);
}finally{
ScopeProvider.instance.reset();
SecurityTokenProvider.instance.reset();
}catch(Exception e){
logger.error("Something failed while alerting editors/reviewers", e);
}finally{
ScopeProvider.instance.reset();
SecurityTokenProvider.instance.reset();
}
}
}).start();
});
t.start();
}catch(Exception e){
logger.error("Unable to update this Item ", e);
throw e;
}
return null;
}
/**
* Revert operation and alert admins/vre users
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
@ -242,30 +247,40 @@ public class Utils {
* @param fullName
* @param uuid
*/
public static void revertOperation(CloseableHttpClient httpClient, String baseUrl,
RevertableOperationInfo rInfo, String token, String context, long groupId) throws Exception{
GRSFUpdaterServiceClient.revertOperation(httpClient, baseUrl, rInfo.getFullName(), rInfo.getUuid());
public static void revertOperation(CloseableHttpClient httpClient, String baseUrl, HttpServletRequest httpServletRequest,
final RevertableOperationInfo rInfo, final String token, final String context, final long groupId) throws Exception{
GRSFUpdaterServiceClient.revertOperation(httpClient, baseUrl, rInfo.getFullNameCurrentAdmin(), rInfo.getUuid());
// require social networking url
final String baseUrlSocial = SocialCommunications.getBaseUrlSocialService(httpServletRequest);
// manage interactions through a separated thread but set there security token and context (and then reset them)
new Thread(()->{
Thread t = new Thread(new Runnable() {
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(token);
try{
@Override
public void run() {
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(token);
try{
// create a post about the operation
SocialCommunications.sendEmailAdministratorsOnOperationReverted(rInfo, groupId);
// write post about this
SocialCommunications.writePostOnRevert(baseUrlSocial, rInfo, true);
}catch(Exception e){
logger.error("Something failed while alerting editors/reviewers", e);
}finally{
ScopeProvider.instance.reset();
SecurityTokenProvider.instance.reset();
// alert who's involved
SocialCommunications.sendEmailAdministratorsOnOperationReverted(baseUrlSocial, rInfo, groupId);
}catch(Exception e){
logger.error("Something failed while alerting editors/reviewers", e);
}finally{
ScopeProvider.instance.reset();
SecurityTokenProvider.instance.reset();
}
}
});
t.start();
}).start();
}
/**
@ -290,7 +305,7 @@ public class Utils {
}
// update the current status record
String productId = bean.getKnowledgeBaseIdentifier();
String productId = bean.getKnowledgeBaseId();
Map<String, List<String>> extrasMap = getExtrasAsHashMap(catalogue.getDataset(productId, sysApi).getExtras());
extrasMap.put(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY, Arrays.asList(Status.To_be_Merged.getOrigName()));
catalogue.patchProductCustomFields(productId, sysApi, extrasMap);
@ -445,10 +460,10 @@ public class Utils {
JSONParser parser = new JSONParser();
JSONObject object = (JSONObject)parser.parse(json);
String uuid = getDatasetKnowledgeBaseIdFromUrl((String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_URL));
CkanDataset dataset = ctl.getDataset(uuid, apiKey);
return new SimilarGRSFRecord(
uuid,
(String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_DESCRIPTION),
@ -507,7 +522,7 @@ public class Utils {
String destDomain = extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0);
String shortName = extrasWithoutNamespaces.get(Constants.SHORT_NAME_CUSTOM_KEY).get(0);
String description = destDataset.getNotes();
return new ConnectedBean(
connectedBeanUuid,
description,

View File

@ -0,0 +1,26 @@
package org.gcube.datacatalogue.grsf_manage_widget.shared;
/**
* A list of hastags to send along the update
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum HashTagsOnUpdate {
MERGE("merge"),
REVERTED_MERGE("reverted_merge"),
CONNECT("connect"),
SHORTNAME_UPDATED("shortname_updated"),
TRACEABILITY_FLAG_SET("traceability_flag_set"),
TRACEABILITY_FLAG_UNSET("traceability_flag_unset");
private String string;
HashTagsOnUpdate(String asString){
this.string = asString;
}
public String getString() {
return string;
}
}

View File

@ -1,8 +1,8 @@
package org.gcube.datacatalogue.grsf_manage_widget.shared;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.gcube.datacatalogue.common.enums.Status;
@ -10,16 +10,11 @@ import org.gcube.datacatalogue.common.enums.Status;
* The bean to be managed by GRSF Editors and Reviewers.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class ManageProductBean implements Serializable{
public class ManageProductBean extends GenericRecord{
private static final long serialVersionUID = -4882608487467259326L;
private String semanticIdentifier; // Stock id or Fishery id
private String catalogueIdentifier; // Catalogue id
private String knowledgeBaseIdentifier; // GRSF UUID
private String grsfType; // Fishery or Stock type (e.g., Assessment_Unit, Marine Resource and so on)
private String grsfDomain; // fishery/stock
private String grsfName; // Fishery name or Stock name
private String shortName; // it is editable ...
private String shortNameUpdated; // the updated one, if any
private boolean traceabilityFlag; //from false to true etc
private Status currentStatus;
@ -32,8 +27,8 @@ public class ManageProductBean implements Serializable{
private List<ConnectedBean> currentConnections;
private List<ConnectedBean> connections; // the one to used eventually
private boolean mergesInvolved; // important: in this case an email must be sent to the editors/reviewers
private String recordUrl; // this record url
private String report; // the report that keeps track of the changes
private Set<String> hashtags;
public ManageProductBean() {
super();
@ -44,9 +39,10 @@ public class ManageProductBean implements Serializable{
String catalogueIdentifier,
String knowledgeBaseIdentifier,
String grsfType,
String grsfDomain,
String grsfName,
String grsfDomain,
String shortName,
String description,
String title,
boolean traceabilityFlag,
Status currentStatus,
String recordUrl,
@ -55,14 +51,9 @@ public class ManageProductBean implements Serializable{
List<ConnectedBean> currentConnections,
List<ConnectedBean> suggestedByKnowledgeBaseConnections
) {
super();
this.semanticIdentifier = semanticIdentifier;
super(knowledgeBaseIdentifier, description, shortName, title, recordUrl, semanticIdentifier, grsfDomain);
this.catalogueIdentifier = catalogueIdentifier;
this.knowledgeBaseIdentifier = knowledgeBaseIdentifier;
this.grsfType = grsfType;
this.grsfDomain = grsfDomain;
this.grsfName = grsfName;
this.shortName = shortName;
this.shortNameUpdated = shortName;
this.traceabilityFlag = traceabilityFlag;
this.currentStatus = currentStatus;
@ -70,15 +61,6 @@ public class ManageProductBean implements Serializable{
this.similarGrsfRecords = similarGrsfRecords;
this.currentConnections = currentConnections;
this.suggestedByKnowledgeBaseConnections = suggestedByKnowledgeBaseConnections;
this.recordUrl = recordUrl;
}
public String getSemanticIdentifier() {
return semanticIdentifier;
}
public void setSemanticIdentifier(String semanticIdentifier) {
this.semanticIdentifier = semanticIdentifier;
}
public List<SourceRecord> getSources() {
@ -105,14 +87,6 @@ public class ManageProductBean implements Serializable{
this.catalogueIdentifier = catalogueIdentifier;
}
public String getKnowledgeBaseIdentifier() {
return knowledgeBaseIdentifier;
}
public void setKnowledgeBaseIdentifier(String knowledgeBaseIdentifier) {
this.knowledgeBaseIdentifier = knowledgeBaseIdentifier;
}
public String getGrsfType() {
return grsfType;
}
@ -121,22 +95,6 @@ public class ManageProductBean implements Serializable{
this.grsfType = grsfType;
}
public String getGrsfDomain() {
return grsfDomain;
}
public void setGrsfDomain(String grsfDomain) {
this.grsfDomain = grsfDomain;
}
public String getGrsfName() {
return grsfName;
}
public void setGrsfName(String grsfName) {
this.grsfName = grsfName;
}
public Status getCurrentStatus() {
return currentStatus;
}
@ -169,14 +127,6 @@ public class ManageProductBean implements Serializable{
this.traceabilityFlag = traceabilityFlag;
}
public String getShortName() {
return shortName;
}
public void setShortName(String shortName) {
this.shortName = shortName;
}
public String getShortNameUpdated() {
return shortNameUpdated;
}
@ -219,14 +169,6 @@ public class ManageProductBean implements Serializable{
this.mergesInvolved = mergesInvolved;
}
public String getRecordUrl() {
return recordUrl;
}
public void setRecordUrl(String recordUrl) {
this.recordUrl = recordUrl;
}
public List<ConnectedBean> getConnections() {
return connections;
}
@ -243,23 +185,30 @@ public class ManageProductBean implements Serializable{
this.report = report;
}
public Set<String> getHashtags() {
return hashtags;
}
public void setHashtags(Set<String> hashtags) {
this.hashtags = hashtags;
}
@Override
public String toString() {
return "ManageProductBean [semanticIdentifier=" + semanticIdentifier
+ ", catalogueIdentifier=" + catalogueIdentifier
+ ", knowledgeBaseIdentifier=" + knowledgeBaseIdentifier
+ ", grsfType=" + grsfType + ", grsfDomain=" + grsfDomain
+ ", grsfName=" + grsfName + ", shortName=" + shortName
+ ", shortNameUpdated=" + shortNameUpdated
+ ", traceabilityFlag=" + traceabilityFlag + ", currentStatus="
+ currentStatus + ", newStatus=" + newStatus + ", annotation="
+ annotation + ", sources=" + sources + ", similarGrsfRecords="
+ similarGrsfRecords + ", suggestedByKnowledgeBaseConnections="
+ suggestedByKnowledgeBaseConnections + ", suggestdByAdministratorConnections="
return "ManageProductBean [catalogueIdentifier=" + catalogueIdentifier
+ ", grsfType=" + grsfType + ", shortNameUpdated="
+ shortNameUpdated + ", traceabilityFlag=" + traceabilityFlag
+ ", currentStatus=" + currentStatus + ", newStatus="
+ newStatus + ", annotation=" + annotation + ", sources="
+ sources + ", similarGrsfRecords=" + similarGrsfRecords
+ ", suggestedByKnowledgeBaseConnections="
+ suggestedByKnowledgeBaseConnections
+ ", suggestdByAdministratorConnections="
+ suggestdByAdministratorConnections + ", currentConnections="
+ currentConnections + ", connections=" + connections
+ ", mergesInvolved=" + mergesInvolved + ", recordUrl="
+ recordUrl + ", report=" + report + "]";
+ ", mergesInvolved=" + mergesInvolved + ", report=" + report
+ ", hashtags=" + hashtags + ", GenericRecord=" + super.toString()
+ "]";
}
}

View File

@ -6,35 +6,33 @@ public class RevertableOperationInfo implements Serializable{
private static final long serialVersionUID = 5274434342849474800L;
private String recordUrl;
private String fullName;
private String fullNameCurrentAdmin; // the one who is thinking to revert it
private String uuid;
private String admin;
private String fullNameOriginalAdmin; // the original admin in the link (his/her Full Name)
private String userNameOriginalAdmin; // the original admin's username
private long timestamp;
private RevertableOperations operation;
public RevertableOperationInfo() {
super();
}
public RevertableOperationInfo(String recordUrl, String fullName,
String uuid, String admin, long timestamp, RevertableOperations operation) {
public RevertableOperationInfo(
String recordUrl,
String fullNameCurrentAdmin,
String uuid,
String fullNameOriginalAdmin,
String userNameOriginalAdmin,
long timestamp,
RevertableOperations operation) {
super();
this.recordUrl = recordUrl;
this.fullName = fullName;
this.fullNameCurrentAdmin = fullNameCurrentAdmin;
this.uuid = uuid;
this.admin = admin;
this.fullNameOriginalAdmin = fullNameOriginalAdmin;
this.timestamp = timestamp;
this.operation = operation;
}
public String getAdmin() {
return admin;
}
public void setAdmin(String admin) {
this.admin = admin;
}
public long getTimestamp() {
return timestamp;
}
@ -57,23 +55,43 @@ public class RevertableOperationInfo implements Serializable{
public void setRecordUrl(String recordUrl) {
this.recordUrl = recordUrl;
}
public String getFullName() {
return fullName;
public String getFullNameCurrentAdmin() {
return fullNameCurrentAdmin;
}
public void setFullName(String fullName) {
this.fullName = fullName;
public void setFullNameCurrentAdmin(String fullNameCurrentAdmin) {
this.fullNameCurrentAdmin = fullNameCurrentAdmin;
}
public String getFullNameOriginalAdmin() {
return fullNameOriginalAdmin;
}
public void setFullNameOriginalAdmin(String fullNameOriginalAdmin) {
this.fullNameOriginalAdmin = fullNameOriginalAdmin;
}
public String getUserNameOriginalAdmin() {
return userNameOriginalAdmin;
}
public void setUserNameOriginalAdmin(String userNameOriginalAdmin) {
this.userNameOriginalAdmin = userNameOriginalAdmin;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@Override
public String toString() {
return "RevertableOperationInfo [recordUrl=" + recordUrl + ", fullName="
+ fullName + ", uuid=" + uuid + ", admin=" + admin
return "RevertableOperationInfo [recordUrl=" + recordUrl
+ ", fullNameCurrentAdmin=" + fullNameCurrentAdmin + ", uuid="
+ uuid + ", fullNameOriginalAdmin=" + fullNameOriginalAdmin
+ ", userNameOriginalAdmin=" + userNameOriginalAdmin
+ ", timestamp=" + timestamp + ", operation=" + operation + "]";
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

View File

Before

Width:  |  Height:  |  Size: 554 B

After

Width:  |  Height:  |  Size: 554 B