Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3657 modular explore #4407

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5ae8418
stub out modular explore #3657 #4249
pdurbin Jan 3, 2018
488b604
Update the description for the Data Explorer
Jan 4, 2018
bd17812
Merge pull request #4397 from kevinworthington/patch-2
pdurbin Jan 4, 2018
61c4936
get test passing, {siteUrl} is now a valid reserved word #3657
pdurbin Jan 5, 2018
6538b93
differentiate external tools under own dropdown for now #3657
pdurbin Jan 5, 2018
b3be37e
make external explore tools available on dataset page too #3657
pdurbin Jan 5, 2018
e873c6e
Data Explorer expects `fileId` not `fileid` #4249 #3657
pdurbin Jan 5, 2018
233cdc1
add `type` to `externaltool` table for "explore" vs "configure" #3657
pdurbin Jan 8, 2018
bcca40b
externaltool type enum is stored in ALL CAPS #3657
pdurbin Jan 8, 2018
5d18067
put external tools under Explore button dropdown #3657
pdurbin Jan 8, 2018
0e1c1e9
have external tools respect downloadPopupRequired #3657
pdurbin Jan 8, 2018
79161d0
mention external tools in Data Exploration Guide #3657
pdurbin Jan 8, 2018
f460d5b
get TwoRavens working again (FIXME for external tools) #3657
pdurbin Jan 10, 2018
ef87fde
get external tool popup working on dataset page #3657
pdurbin Jan 10, 2018
4204279
only show explore tools for tabular data #3657
pdurbin Jan 11, 2018
0f55916
Merge branch 'develop' into 3657-modular-explore #3657
pdurbin Jan 11, 2018
4a91c7d
Merge branch 'develop' into 3657-modular-explore #3657
pdurbin Jan 12, 2018
9c1502d
get validation working on external tools #3657
pdurbin Jan 11, 2018
515c351
move constants from ExternalToolHandler to ExternalTool #3657
pdurbin Jan 12, 2018
eded8ef
simplify SQL update script (no UPDATE) #3657
pdurbin Jan 12, 2018
04be093
type as param, consolidate after switch from handler to tool #3657
pdurbin Jan 12, 2018
f9d11d9
remove cruft #3657
pdurbin Jan 12, 2018
05dd4bf
move ReservedWord enum to ExternalTool #3657
pdurbin Jan 17, 2018
b502c21
consolidate logic into getCachedToolsForDataFile #3657
pdurbin Jan 17, 2018
6f48df7
for null API token, don't pass token string #3657
pdurbin Jan 17, 2018
332c358
add comments to null exploreTool workaround #3657
pdurbin Jan 17, 2018
c6d62e6
4.8.5 has been released, bump version in sql script #3657
pdurbin Jan 18, 2018
5826fea
Merge branch 'develop' into 3657-modular-explore #3657
pdurbin Jan 18, 2018
5dee126
only show explore tools if file can be downloaded #3657
pdurbin Jan 19, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"displayName": "Awesome Tool",
"description": "The most awesome tool.",
"type": "explore",
"toolUrl": "https://awesometool.com",
"toolParameters": {
"queryParameters": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"displayName": "Data Explorer",
"description": "The Data Explorer provides a GUI which lists the variables in a tabular data file allowing searching, charting and cross tabulation analysis.",
"type": "explore",
"toolUrl": "https://scholarsportal.github.io/Dataverse-Data-Explorer/",
"toolParameters": {
"queryParameters": [
{
"fileId": "{fileId}"
},
{
"siteUrl": "{siteUrl}"
},
{
"key": "{apiToken}"
}
]
}
}
5 changes: 4 additions & 1 deletion doc/sphinx-guides/source/installation/external-tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ External tools must be expressed in an external tool manifest file, a specific J

.. literalinclude:: ../_static/installation/files/root/external-tools/awesomeTool.json

``type`` is required and must be ``explore`` or ``configure``.

In the example above, a mix of required and optional reserved words appear that can be used to insert dynamic values into tools. The supported values are:

- ``{fileId}`` (required) - The Dataverse database ID of a file the external tool has been launched on.
- ``{apiToken}`` (optional) - The Dataverse API token of the user launching the external tool.
- ``{siteUrl}`` (optional) - The URL of the Dataverse installation that hosts the file with the fileId above.
- ``{apiToken}`` (optional) - The Dataverse API token of the user launching the external tool, if available.

Making an External Tool Available in Dataverse
----------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions doc/sphinx-guides/source/user/data-exploration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
Data Exploration Guide
=======================================================

Note that the installation of Dataverse you are using may have additional or different tools configured. Developers interested in creating tools should refer to the :doc:`/installation/external-tools` section of the Installation Guide.

Contents:

.. toctree::
Expand Down
2 changes: 2 additions & 0 deletions scripts/database/upgrades/upgrade_v4.8.5_to_v4.9.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE externaltool ADD COLUMN type character varying(255);
ALTER TABLE externaltool ALTER COLUMN type SET NOT NULL;
58 changes: 39 additions & 19 deletions src/main/java/edu/harvard/iq/dataverse/DatasetPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,10 @@ public enum DisplayMode {

private Boolean hasRsyncScript = false;

List<ExternalTool> allTools = new ArrayList<>();
Map<Long,List<ExternalTool>> queriedFileTools = new HashMap<>();
List<ExternalTool> configureTools = new ArrayList<>();
List<ExternalTool> exploreTools = new ArrayList<>();
Map<Long, List<ExternalTool>> configureToolsByFileId = new HashMap<>();
Map<Long, List<ExternalTool>> exploreToolsByFileId = new HashMap<>();

public Boolean isHasRsyncScript() {
return hasRsyncScript;
Expand Down Expand Up @@ -1529,9 +1531,10 @@ private String init(boolean initFull) {
BundleUtil.getStringFromBundle("file.rsyncUpload.inProgressMessage.details"));
}
}

allTools = externalToolService.findAll();


configureTools = externalToolService.findByType(ExternalTool.Type.CONFIGURE);
exploreTools = externalToolService.findByType(ExternalTool.Type.EXPLORE);

return null;
}

Expand Down Expand Up @@ -4041,23 +4044,40 @@ public List<DatasetField> getDatasetSummaryFields() {

return DatasetUtil.getDatasetSummaryFields(workingVersion, customFields);
}

public List<ExternalTool> getExternalToolsForDataFile(Long fileId) {
List<ExternalTool> fileTools = queriedFileTools.get(fileId);
if(fileTools != null) { //if already queried before and added to list
return fileTools;

public List<ExternalTool> getConfigureToolsForDataFile(Long fileId) {
return getCachedToolsForDataFile(fileId, ExternalTool.Type.CONFIGURE);
}

public List<ExternalTool> getExploreToolsForDataFile(Long fileId) {
return getCachedToolsForDataFile(fileId, ExternalTool.Type.EXPLORE);
}

public List<ExternalTool> getCachedToolsForDataFile(Long fileId, ExternalTool.Type type) {
Map<Long, List<ExternalTool>> cachedToolsByFileId = new HashMap<>();
List<ExternalTool> externalTools = new ArrayList<>();
switch (type) {
case EXPLORE:
cachedToolsByFileId = exploreToolsByFileId;
externalTools = exploreTools;
break;
case CONFIGURE:
cachedToolsByFileId = configureToolsByFileId;
externalTools = configureTools;
break;
default:
break;
}

DataFile dataFile = datafileService.find(fileId);
fileTools = externalToolService.findExternalToolsByFile(allTools, dataFile);

queriedFileTools.put(fileId, fileTools); //add externalTools to map so we don't have to do the lifting again

return fileTools;
List<ExternalTool> cachedTools = cachedToolsByFileId.get(fileId);
if (cachedTools != null) { //if already queried before and added to list
return cachedTools;
}
DataFile dataFile = datafileService.find(fileId);
cachedTools = ExternalToolServiceBean.findExternalToolsByFile(externalTools, dataFile);
cachedToolsByFileId.put(fileId, cachedTools); //add to map so we don't have to do the lifting again
return cachedTools;
}



Boolean thisLatestReleasedVersion = null;

public boolean isThisLatestReleasedVersion() {
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/edu/harvard/iq/dataverse/FileDownloadHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import edu.harvard.iq.dataverse.authorization.Permission;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.authorization.users.GuestUser;
import edu.harvard.iq.dataverse.externaltools.ExternalTool;
import edu.harvard.iq.dataverse.util.BundleUtil;
import static edu.harvard.iq.dataverse.util.JsfHelper.JH;
import java.util.ArrayList;
Expand Down Expand Up @@ -260,7 +260,21 @@ public String startExploreDownloadLink(GuestbookResponse guestbookResponse, File
requestContext.execute("PF('downloadPopup').hide()");
return retVal;
}


public void explore(GuestbookResponse guestbookResponse, FileMetadata fmd, ExternalTool externalTool) {

RequestContext requestContext = RequestContext.getCurrentInstance();
boolean valid = validateGuestbookResponse(guestbookResponse);

if (!valid) {
return;
}
// Rather that putting "Explore" in the database, we *could* put externalTool.getDisplayName() for "Data Explorer" or whatever.
guestbookResponse.setDownloadtype("Explore");
fileDownloadService.explore(guestbookResponse, fmd, externalTool);
requestContext.execute("PF('downloadPopup').hide()");
}

public String startWorldMapDownloadLink(GuestbookResponse guestbookResponse, FileMetadata fmd){

RequestContext requestContext = RequestContext.getCurrentInstance();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package edu.harvard.iq.dataverse;

import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.Permission;
import edu.harvard.iq.dataverse.authorization.users.ApiToken;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.dataaccess.SwiftAccessIO;
import edu.harvard.iq.dataverse.authorization.users.User;
import edu.harvard.iq.dataverse.datasetutility.TwoRavensHelper;
import edu.harvard.iq.dataverse.datasetutility.WorldMapPermissionHelper;
import edu.harvard.iq.dataverse.engine.command.Command;
import edu.harvard.iq.dataverse.engine.command.exception.CommandException;
import edu.harvard.iq.dataverse.engine.command.impl.CreateGuestbookResponseCommand;
import edu.harvard.iq.dataverse.engine.command.impl.RequestAccessCommand;
import edu.harvard.iq.dataverse.externaltools.ExternalTool;
import edu.harvard.iq.dataverse.externaltools.ExternalToolHandler;
import edu.harvard.iq.dataverse.util.FileUtil;
import java.io.IOException;
import java.sql.Timestamp;
Expand All @@ -19,16 +22,13 @@
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.primefaces.context.RequestContext;

/**
*
Expand Down Expand Up @@ -57,6 +57,8 @@ public class FileDownloadServiceBean implements java.io.Serializable {
DataverseServiceBean dataverseService;
@EJB
UserNotificationServiceBean userNotificationService;
@EJB
AuthenticationServiceBean authService;

@Inject
DataverseSession session;
Expand Down Expand Up @@ -147,8 +149,50 @@ public void startFileDownload(GuestbookResponse guestbookResponse, FileMetadata
callDownloadServlet(format, fileMetadata.getDataFile().getId(), recordsWritten);
logger.fine("issued file download redirect for filemetadata "+fileMetadata.getId()+", datafile "+fileMetadata.getDataFile().getId());
}



public void explore(GuestbookResponse guestbookResponse, FileMetadata fmd, ExternalTool externalTool) {
if (externalTool == null) {
// Must be from the dataset page.
logger.fine("null, must be on dataset page");
externalTool = guestbookResponse.getExternalTool();
} else {
logger.fine("non-null, must be on file page");
}
ApiToken apiToken = null;
User user = session.getUser();
if (user instanceof AuthenticatedUser) {
AuthenticatedUser authenticatedUser = (AuthenticatedUser) user;
apiToken = authService.findApiTokenByUser(authenticatedUser);
}
DataFile dataFile = null;
if (fmd != null) {
dataFile = fmd.getDataFile();
} else {
if (guestbookResponse != null) {
dataFile = guestbookResponse.getDataFile();
}
}
// Note that the API token might be null. You can end up with "key=null" or whatever.
ExternalToolHandler externalToolHandler = new ExternalToolHandler(externalTool, dataFile, apiToken);
String toolUrl = externalToolHandler.getToolUrlWithQueryParams();
logger.fine("Exploring with " + toolUrl);
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(toolUrl);
} catch (IOException ex) {
logger.info("Problem exploring with " + toolUrl + " - " + ex);
}
// fmd is null from the popup
if (guestbookResponse != null && guestbookResponse.isWriteResponse()
&& ((fmd != null && fmd.getDataFile() != null) || guestbookResponse.getDataFile() != null)) {
if (guestbookResponse.getDataFile() == null && fmd != null) {
guestbookResponse.setDataFile(fmd.getDataFile());
}
if (fmd == null || !fmd.getDatasetVersion().isDraft()) {
writeGuestbookResponseRecord(guestbookResponse);
}
}
}

public String startExploreDownloadLink(GuestbookResponse guestbookResponse, FileMetadata fmd){

if (guestbookResponse != null && guestbookResponse.isWriteResponse()
Expand Down
22 changes: 14 additions & 8 deletions src/main/java/edu/harvard/iq/dataverse/FilePage.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public class FilePage implements java.io.Serializable {
private Dataset dataset;
private List<DatasetVersion> datasetVersionsForTab;
private List<FileMetadata> fileMetadatasForTab;
private List<ExternalTool> externalTools;
private List<ExternalTool> configureTools;
private List<ExternalTool> exploreTools;

@EJB
DataFileServiceBean datafileService;
Expand Down Expand Up @@ -161,10 +162,11 @@ public String init() {

// this.getFileDownloadHelper().setGuestbookResponse(guestbookResponse);

List<ExternalTool> allTools = externalToolService.findAll();

externalTools = externalToolService.findExternalToolsByFile(allTools, file);

if (file.isTabularData()) {
configureTools = externalToolService.findByType(ExternalTool.Type.CONFIGURE);
exploreTools = externalToolService.findByType(ExternalTool.Type.EXPLORE);
}

} else {

return permissionsWrapper.notFound();
Expand Down Expand Up @@ -769,8 +771,12 @@ public String getPublicDownloadUrl() {
return FileUtil.getPublicDownloadUrl(systemConfig.getDataverseSiteUrl(), fileId);
}

public List<ExternalTool> getExternalTools() {
return externalTools;
public List<ExternalTool> getConfigureTools() {
return configureTools;
}


public List<ExternalTool> getExploreTools() {
return exploreTools;
}

}
17 changes: 17 additions & 0 deletions src/main/java/edu/harvard/iq/dataverse/GuestbookResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package edu.harvard.iq.dataverse;

import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.externaltools.ExternalTool;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
Expand Down Expand Up @@ -81,6 +82,14 @@ public class GuestbookResponse implements Serializable {
@Transient
private boolean writeResponse = true;

/**
* This transient variable is a place to temporarily retrieve the
* ExternalTool object from the popup when the popup is required on the
* dataset page.
*/
@Transient
private ExternalTool externalTool;

public boolean isWriteResponse() {
return writeResponse;
}
Expand All @@ -106,6 +115,14 @@ public void setFileFormat(String downloadFormat) {
this.fileFormat = downloadFormat;
}

public ExternalTool getExternalTool() {
return externalTool;
}

public void setExternalTool(ExternalTool externalTool) {
this.externalTool = externalTool;
}

public GuestbookResponse(){

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.authorization.users.User;
import edu.harvard.iq.dataverse.externaltools.ExternalTool;
import edu.harvard.iq.dataverse.util.BundleUtil;
import static edu.harvard.iq.dataverse.util.JsfHelper.JH;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
Expand All @@ -24,8 +24,6 @@
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
Expand Down Expand Up @@ -785,6 +783,26 @@ public GuestbookResponse modifyDatafileAndFormat(GuestbookResponse in, FileMetad
return in;
}

/**
* This method was added because on the dataset page when a popup is
* required, ExternalTool is null in the poup itself. The
* modifyDatafileAndFormat method above was copied and a new argument for
* ExternalTool was added.
*/
public GuestbookResponse modifyDatafileAndFormat(GuestbookResponse in, FileMetadata fm, String format, ExternalTool externalTool) {
if (in != null && fm.getDataFile() != null) {
in.setFileFormat(format);
in.setDataFile(fm.getDataFile());
}
if (in != null && fm.getDatasetVersion() != null && fm.getDatasetVersion().isDraft() ) {
in.setWriteResponse(false);
}
if (in != null && externalTool != null) {
in.setExternalTool(externalTool);
}
return in;
}

public Boolean validateGuestbookResponse(GuestbookResponse guestbookResponse, String type) {

boolean valid = true;
Expand Down
Loading