diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java index cba68fb1ff7..8ec2289d38e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetPage.java @@ -309,6 +309,14 @@ public enum DisplayMode { private Boolean hasRsyncScript = false; private Boolean hasTabular = false; + + /** + * If the dataset version has at least one tabular file. The "hasTabular" + * boolean is for the dataset level ("has ever had a tabular file") but + * sometimes you want to know about the current version ("no tabular files + * currently"). Like all files, tabular files can be deleted. + */ + private boolean versionHasTabular = false; private boolean showIngestSuccess; @@ -2037,7 +2045,18 @@ private String init(boolean initFull) { displayLockInfo(dataset); + for (FileMetadata fmd : workingVersion.getFileMetadatas()) { + if (fmd.getDataFile().isTabularData()) { + versionHasTabular = true; + break; + } + } for(DataFile f : dataset.getFiles()) { + // TODO: Consider uncommenting this optimization. +// if (versionHasTabular) { +// hasTabular = true; +// break; +// } if(f.isTabularData()) { hasTabular = true; break; @@ -2257,8 +2276,11 @@ private DefaultTreeNode createFileTreeNode(FileMetadata fileMetadata, TreeNode p public boolean isHasTabular() { return hasTabular; } - - + + public boolean isVersionHasTabular() { + return versionHasTabular; + } + public boolean isReadOnly() { return readOnly; } @@ -2886,8 +2908,43 @@ public List getSelectedNonDownloadableFiles() { public void setSelectedNonDownloadableFiles(List selectedNonDownloadableFiles) { this.selectedNonDownloadableFiles = selectedNonDownloadableFiles; } - - + + private List selectedNonDownloadallableFiles; + + public List getSelectedNonDownloadallableFiles() { + return selectedNonDownloadallableFiles; + } + + public void setSelectedNonDownloadallableFiles(List selectedNonDownloadallableFiles) { + this.selectedNonDownloadallableFiles = selectedNonDownloadallableFiles; + } + + public String getSizeOfDataset() { + boolean original = false; + return DatasetUtil.getDownloadSize(workingVersion, original); + } + + public String getSizeOfDatasetOrig() { + boolean original = true; + return DatasetUtil.getDownloadSize(workingVersion, original); + } + + public void validateAllFilesForDownloadArchival() { + boolean guestbookRequired = isDownloadPopupRequired(); + boolean downloadOriginal = false; + validateFilesForDownloadAll(guestbookRequired, downloadOriginal); + } + + /** + * Can result in "requested optional service" error. For non-tabular files + * it's safer to use validateAllFilesForDownloadArchival. + */ + public void validateAllFilesForDownloadOriginal() { + boolean guestbookRequired = isDownloadPopupRequired(); + boolean downloadOriginal = true; + validateFilesForDownloadAll(guestbookRequired, downloadOriginal); + } + public void validateFilesForDownload(boolean guestbookRequired, boolean downloadOriginal){ setSelectedDownloadableFiles(new ArrayList<>()); setSelectedNonDownloadableFiles(new ArrayList<>()); @@ -2951,7 +3008,77 @@ public void validateFilesForDownload(boolean guestbookRequired, boolean download } } - + + /** + * This method borrows heavily from validateFilesForDownload but does not + * use the selectedFiles field. + */ + public void validateFilesForDownloadAll(boolean guestbookRequired, boolean downloadOriginal) { + setSelectedNonDownloadallableFiles(new ArrayList<>()); + List downloadableFiles = new ArrayList<>(); + for (FileMetadata fmd : workingVersion.getFileMetadatas()) { + if (this.fileDownloadHelper.canDownloadFile(fmd)) { + downloadableFiles.add(fmd); + } else { + getSelectedNonDownloadallableFiles().add(fmd); + } + } + + // If some of the files were restricted and we had to drop them off the + // list, and NONE of the files are left on the downloadable list + // - we show them a "you're out of luck" popup: + if (downloadableFiles.isEmpty() && !getSelectedNonDownloadallableFiles().isEmpty()) { + //RequestContext requestContext = RequestContext.getCurrentInstance(); + PrimeFaces.current().executeScript("PF('downloadInvalid').show()"); + return; + } + + // Note that the GuestbookResponse object may still have information from + // the last download action performed by the user. For example, it may + // still have the non-null Datafile in it, if the user has just downloaded + // a single file; or it may still have the format set to "original" - + // even if that's not what they are trying to do now. + // So make sure to reset these values: + guestbookResponse.setDataFile(null); + // Inline getSelectedDownloadableFilesIdsString() that doesn't use selectedDownloadableFiles + String downloadIdString = ""; + for (FileMetadata fmd : downloadableFiles) { + if (!StringUtil.isEmpty(downloadIdString)) { + downloadIdString += ","; + } + downloadIdString += fmd.getDataFile().getId(); + } + guestbookResponse.setSelectedFileIds(downloadIdString); + if (downloadOriginal) { + guestbookResponse.setFileFormat("original"); + } else { + guestbookResponse.setFileFormat(""); + } + guestbookResponse.setDownloadtype("Download"); + + // If we have a bunch of files that we can download, AND there were no files + // that we had to take off the list, because of permissions - we can + // either send the user directly to the download API (if no guestbook/terms + // popup is required), or send them to the download popup: + if (!downloadableFiles.isEmpty() && getSelectedNonDownloadallableFiles().isEmpty()) { + if (guestbookRequired) { + openDownloadPopupForDownloadAll(); + } else { + startMultipleFileDownload(); + } + return; + } + + // ... and if some files were restricted, but some are downloadable, + // we are showing them this "you are somewhat in luck" popup; that will + // then direct them to the download, or popup, as needed: + if (!downloadableFiles.isEmpty() && !getSelectedNonDownloadallableFiles().isEmpty()) { + //RequestContext requestContext = RequestContext.getCurrentInstance(); + PrimeFaces.current().executeScript("PF('downloadAllMixed').show()"); + } + + } + private boolean selectAllFiles; public boolean isSelectAllFiles() { @@ -4073,6 +4200,28 @@ public void openDownloadPopupForMultipleFileDownload() { //RequestContext requestContext = RequestContext.getCurrentInstance(); PrimeFaces.current().executeScript("PF('downloadPopup').show();handleResizeDialog('downloadPopup');"); } + + /** + * This method borrows heavily from + * openDownloadPopupForMultipleFileDownload. It does not use the + * selectedFiles field. + */ + public void openDownloadPopupForDownloadAll() { + // This is commented out because "download all" doesn't use selectedFiles. +// if (this.selectedFiles.isEmpty()) { +// //RequestContext requestContext = RequestContext.getCurrentInstance(); +// PrimeFaces.current().executeScript("PF('selectFilesForDownload').show()"); +// return; +// } + + // There's a chance that this is not really a batch download - i.e., + // there may only be one file on the downloadable list. But the fileDownloadService + // method below will check for that, and will redirect to the single download, if + // that's the case. -- L.A. + this.guestbookResponse.setDownloadtype("Download"); + //RequestContext requestContext = RequestContext.getCurrentInstance(); + PrimeFaces.current().executeScript("PF('downloadPopup').show();handleResizeDialog('downloadPopup');"); + } public void initGuestbookMultipleResponse(String selectedFileIds){ initGuestbookResponse(null, "download", selectedFileIds); diff --git a/src/main/java/edu/harvard/iq/dataverse/dataset/DatasetUtil.java b/src/main/java/edu/harvard/iq/dataverse/dataset/DatasetUtil.java index f6de6b0c3f5..a672d2fd413 100644 --- a/src/main/java/edu/harvard/iq/dataverse/dataset/DatasetUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/dataset/DatasetUtil.java @@ -34,6 +34,7 @@ import static edu.harvard.iq.dataverse.dataaccess.DataAccess.getStorageIO; import static edu.harvard.iq.dataverse.dataaccess.DataAccess.getStorageIO; import static edu.harvard.iq.dataverse.dataaccess.DataAccess.getStorageIO; +import edu.harvard.iq.dataverse.datasetutility.FileSizeChecker; public class DatasetUtil { @@ -440,4 +441,24 @@ public static List getDatasetSummaryFields(DatasetVersion datasetV return datasetFields; } + /** + * Given a dataset version, return it's size in human readable units such as + * 42.9 MB.There is a GetDatasetStorageSizeCommand but it's overly complex + * for the use case. + * + * @param original Use the original file size rather than the archival file + * size for tabular files. + */ + public static String getDownloadSize(DatasetVersion dsv, boolean original) { + long bytes = 0l; + for (FileMetadata fileMetadata : dsv.getFileMetadatas()) { + DataFile dataFile = fileMetadata.getDataFile(); + if (original && dataFile.isTabularData()) { + bytes += dataFile.getOriginalFileSize(); + } else { + bytes += dataFile.getFilesize(); + } + } + return FileSizeChecker.bytesToHumanReadable(bytes); + } } diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 2a10076c90d..23c0a689f2c 100755 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -1219,6 +1219,7 @@ dataset.accessBtn=Access Dataset dataset.accessBtn.header.download=Download Options dataset.accessBtn.header.explore=Explore Options dataset.accessBtn.header.compute=Compute Options +dataset.accessBtn.download.size=ZIP ({0}) dataset.linkBtn=Link Dataset dataset.contactBtn=Contact Owner dataset.shareBtn=Share diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index 658b429768e..d8809842d43 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -31,11 +31,7 @@ and !permissionsWrapper.canIssuePublishDatasetCommand(DatasetPage.dataset)}"/> - - - @@ -143,17 +139,38 @@