diff --git a/doc/release-notes/12258-publish-submit-contains-files.md b/doc/release-notes/12258-publish-submit-contains-files.md new file mode 100644 index 00000000000..dd6e6d7153c --- /dev/null +++ b/doc/release-notes/12258-publish-submit-contains-files.md @@ -0,0 +1,2 @@ +## Bug: Publish and Submit for review must contain files +When `requireFilesToPublishDataset` is set on a Dataverse a Dataset must contain files to be published or submitted for review. This fix make sure the dataset version contains files, and not just the dataset. It also adds this check to the `Submit for Review` functionality. diff --git a/doc/sphinx-guides/source/api/changelog.rst b/doc/sphinx-guides/source/api/changelog.rst index df7a6097c67..08f1fe38c68 100644 --- a/doc/sphinx-guides/source/api/changelog.rst +++ b/doc/sphinx-guides/source/api/changelog.rst @@ -10,6 +10,10 @@ This API changelog is experimental and we would love feedback on its usefulness. v6.11 ----- +- The following API will now return ``403`` if the ``requireFilesToPublishDataset`` flag is set and the dataset version contains 0 files. + + - **/api/datasets/{Id}/submitForReview** + - The Croissant :ref:`metadata export format ` has been updated from version 1.0 to 1.1, which is reflected in the ``conformsTo`` property. The unused ``wd`` property has been dropped. v6.10 diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index d8da7b8df26..917a62a0072 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -1299,7 +1299,7 @@ The following attributes are supported: * ``description`` Description * ``affiliation`` Affiliation * ``filePIDsEnabled`` ("true" or "false") Restricted to use by superusers and only when the :ref:`:AllowEnablingFilePIDsPerCollection <:AllowEnablingFilePIDsPerCollection>` setting is true. Enables or disables registration of file-level PIDs in datasets within the collection (overriding the instance-wide setting). -* ``requireFilesToPublishDataset`` ("true" or "false") Restricted to use by superusers. Defines if Dataset needs files in order to be published. If not set the determination will be made through inheritance by checking the owners of this collection. Publishing by a superusers will not be blocked. +* ``requireFilesToPublishDataset`` ("true" or "false") Restricted to use by superusers. Defines if Dataset version needs files in order to be published or submitted for review. If not set the determination will be made through inheritance by checking the owners of this collection. Publishing by a superusers will not be blocked. * ``allowedDatasetTypes`` Restricted to use by superusers. By default "dataset" is implied. Pass a comma-separated list of dataset types (e.g. "dataset,software"). You cannot unset this attribute so if you want to delete a dataset type, set ``allowedDatasetTypes`` to a dataset type you won't be deleting. See also :ref:`dataset-types`. See also :ref:`update-dataverse-api`. diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java index 0988439d800..dc09d8948a8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetServiceBean.java @@ -835,6 +835,18 @@ public String getReminderString(Dataset dataset, boolean canPublishDataset, bool String reminderString; + if (dataset.getOwner().getEffectiveRequiresFilesToPublishDataset()) { + List files = dataset.getLatestVersion().getFileMetadatas(); + if (files.size() < 1) { + if (canPublishDataset) { + reminderString = BundleUtil.getStringFromBundle("dataset.mayNotPublish.FilesRequired"); + } else { + reminderString = BundleUtil.getStringFromBundle("dataset.mayNotSubmitForReview.FilesRequired"); + } + return reminderString; + } + } + if (canPublishDataset) { reminderString = BundleUtil.getStringFromBundle("dataset.message.publish.warning"); } else { diff --git a/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java b/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java index 2c6f8ff2fb1..4821d0c7289 100644 --- a/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java +++ b/src/main/java/edu/harvard/iq/dataverse/PermissionsWrapper.java @@ -12,6 +12,7 @@ import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.impl.*; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.logging.Logger; import jakarta.ejb.EJB; @@ -253,9 +254,38 @@ public boolean canIssueDeleteDatasetCommand(DvObject dvo){ // PUBLISH DATASET public boolean canIssuePublishDatasetCommand(DvObject dvo){ + User u = session.getUser(); + if (u != null && u.isSuperuser()) { + return true; + } + // Return false if dataset has 0 files and user want to 'publish' or 'submit for review' and 'publish dataset requires files' flag is set + if (dvo.isInstanceofDataset()) { + Dataverse dv =((Dataset)dvo).getOwner(); + if (dv != null) { + List metadataList = ((Dataset) dvo).getLatestVersion().getFileMetadatas(); + if (metadataList.size() == 0 && dv.getEffectiveRequiresFilesToPublishDataset()) { + return false; + } + } + } return canIssueCommand(dvo, PublishDatasetCommand.class); } - + + // SUBMIT DATASET FOR REVIEW + public boolean canIssueSubmitDatasetForReviewCommand(DvObject dvo){ + // Return false if dataset has 0 files and user want to 'publish' or 'submit for review' and 'publish dataset requires files' flag is set + if (dvo.isInstanceofDataset()) { + Dataverse dv =((Dataset)dvo).getOwner(); + if (dv != null) { + List metadataList = ((Dataset) dvo).getLatestVersion().getFileMetadatas(); + if (metadataList.size() == 0 && dv.getEffectiveRequiresFilesToPublishDataset()) { + return false; + } + } + } + return canIssueCommand(dvo, SubmitDatasetForReviewCommand.class); + } + // For the dataverse_header fragment (and therefore, most of the pages), // we need to know if authenticated users can add dataverses and datasets to the // root collection. For the "Add Data" menu further in the search include fragment diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java index 15faaad5d52..2d09b22925f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/AbstractDatasetCommand.java @@ -315,4 +315,14 @@ protected void registerExternalVocabValuesIfAny(CommandContext ctxt, DatasetVers } } } + + // To block Publishing dataset or Submitting dataset for review + protected boolean getEffectiveRequiresFilesToPublishDataset() { + if (getUser().isSuperuser()) { + return false; + } else { + Dataverse dv = getDataset().getOwner(); + return dv != null && dv.getEffectiveRequiresFilesToPublishDataset(); + } + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java index b0a5b9cd3a0..df7cbc94c8d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/PublishDatasetCommand.java @@ -1,8 +1,6 @@ package edu.harvard.iq.dataverse.engine.command.impl; -import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.DatasetLock; -import edu.harvard.iq.dataverse.Dataverse; +import edu.harvard.iq.dataverse.*; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.engine.command.CommandContext; @@ -17,6 +15,7 @@ import jakarta.persistence.OptimisticLockException; +import java.util.List; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -233,19 +232,12 @@ private void verifyCommandArguments(CommandContext ctxt) throws IllegalCommandEx throw new IllegalCommandException("Cannot release as minor version. Re-try as major release.", this); } - if (getDataset().getFiles().isEmpty() && getEffectiveRequiresFilesToPublishDataset()) { + List files = getDataset().getLatestVersion().getFileMetadatas(); + if ((files == null || files.isEmpty()) && getEffectiveRequiresFilesToPublishDataset()) { throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataset.mayNotPublish.FilesRequired"), this); } } } - private boolean getEffectiveRequiresFilesToPublishDataset() { - if (getUser().isSuperuser()) { - return false; - } else { - Dataverse dv = getDataset().getOwner(); - return dv != null && dv.getEffectiveRequiresFilesToPublishDataset(); - } - } @Override public boolean onSuccess(CommandContext ctxt, Object r) { diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SubmitDatasetForReviewCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SubmitDatasetForReviewCommand.java index 77a4bf5b8ba..3ff53efa0e7 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SubmitDatasetForReviewCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/SubmitDatasetForReviewCommand.java @@ -1,25 +1,17 @@ package edu.harvard.iq.dataverse.engine.command.impl; -import edu.harvard.iq.dataverse.Dataset; -import edu.harvard.iq.dataverse.DatasetLock; -import edu.harvard.iq.dataverse.DatasetVersionUser; -import edu.harvard.iq.dataverse.UserNotification; +import edu.harvard.iq.dataverse.*; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; -import edu.harvard.iq.dataverse.batch.util.LoggingUtil; -import edu.harvard.iq.dataverse.engine.command.AbstractCommand; import edu.harvard.iq.dataverse.engine.command.CommandContext; import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.engine.command.RequiredPermissions; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; import edu.harvard.iq.dataverse.engine.command.exception.IllegalCommandException; import edu.harvard.iq.dataverse.util.BundleUtil; -import java.io.IOException; import java.sql.Timestamp; import java.util.Date; import java.util.List; -import java.util.concurrent.Future; -import org.apache.solr.client.solrj.SolrServerException; @RequiredPermissions(Permission.EditDataset) public class SubmitDatasetForReviewCommand extends AbstractDatasetCommand { @@ -41,6 +33,11 @@ public Dataset execute(CommandContext ctxt) throws CommandException { throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataset.submit.failure.inReview"), this); } + List files = getDataset().getLatestVersion().getFileMetadatas(); + if ((files == null || files.isEmpty()) && getEffectiveRequiresFilesToPublishDataset()) { + throw new IllegalCommandException(BundleUtil.getStringFromBundle("dataset.mayNotSubmitForReview.FilesRequired"), this); + } + //SEK 9-1 Add Lock before saving dataset DatasetLock inReviewLock = new DatasetLock(DatasetLock.Reason.InReview, getRequest().getAuthenticatedUser()); ctxt.engine().submit(new AddLockCommand(getRequest(), getDataset(), inReviewLock)); diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties index 1597467a536..52d500fe23b 100644 --- a/src/main/java/propertyFiles/Bundle.properties +++ b/src/main/java/propertyFiles/Bundle.properties @@ -1637,6 +1637,7 @@ dataset.mayNotPublish.both= This dataset cannot be published until {0} is publis dataset.mayNotPublish.twoGenerations= This dataset cannot be published until {0} and {1} are published. dataset.mayNotBePublished.both.button=Yes, Publish Both dataset.mayNotPublish.FilesRequired=Published datasets should contain at least one data file. +dataset.mayNotSubmitForReview.FilesRequired=The dataset must contain at least one data file in order to be submitted for review. dataset.viewVersion.unpublished=View Unpublished Version dataset.viewVersion.published=View Published Version dataset.link.title=Link Dataset diff --git a/src/main/webapp/dataset.xhtml b/src/main/webapp/dataset.xhtml index 57c6d0c1d25..1fdd5af2591 100644 --- a/src/main/webapp/dataset.xhtml +++ b/src/main/webapp/dataset.xhtml @@ -27,7 +27,8 @@ - + @@ -56,7 +57,8 @@ and !DatasetPage.datasetLockedInWorkflow and DatasetPage.dataset.latestVersion.versionState=='DRAFT' and canUpdateDataset - and !canIssuePublishDatasetCommand}"/> + and !canIssuePublishDatasetCommand + and canIssueSubmitDatasetForReviewCommand}"/> +
@@ -372,7 +374,7 @@ - #{showPublishLink ? bundle['dataset.publishBtn'] : (latestVersionInReview ? bundle['dataset.disabledSubmittedBtn'] : bundle['dataset.submitBtn'])} + #{showPublishLink ? bundle['dataset.publishBtn'] : (latestVersionInReview ? bundle['dataset.disabledSubmittedBtn'] : bundle['dataset.submitBtn'])}