/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package edu.harvard.iq.dataverse.engine.command.impl; import edu.harvard.iq.dataverse.DataFile; import edu.harvard.iq.dataverse.Dataset; import edu.harvard.iq.dataverse.DatasetField; import edu.harvard.iq.dataverse.DatasetFieldConstant; import edu.harvard.iq.dataverse.DatasetVersionUser; import edu.harvard.iq.dataverse.DatasetVersion; import edu.harvard.iq.dataverse.Dataverse; import edu.harvard.iq.dataverse.RoleAssignment; import edu.harvard.iq.dataverse.UserNotification; import edu.harvard.iq.dataverse.authorization.Permission; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; 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.export.ExportException; import edu.harvard.iq.dataverse.export.ExportService; import edu.harvard.iq.dataverse.privateurl.PrivateUrl; import edu.harvard.iq.dataverse.search.IndexResponse; import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import static edu.harvard.iq.dataverse.util.json.JsonPrinter.jsonAsDatasetDto; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import javax.json.JsonObjectBuilder; /** * * @author skraffmiller */ @RequiredPermissions(Permission.PublishDataset) public class PublishDatasetCommand extends AbstractCommand<Dataset> { private static final Logger logger = Logger.getLogger(PublishDatasetCommand.class.getCanonicalName()); boolean minorRelease = false; Dataset theDataset; /** * @todo Is there any use case where this command should allow the * publication of a "V0" version? Shouldn't the first published version of a * dataset be "V1"? Before a fix/workaround was introduced, it was possible * to use this command to create a published "V0" version. For details, see * https://github.com/IQSS/dataverse/issues/1392 */ public PublishDatasetCommand(Dataset datasetIn, DataverseRequest aRequest, boolean minor) { super(aRequest, datasetIn); minorRelease = minor; theDataset = datasetIn; } @Override public Dataset execute(CommandContext ctxt) throws CommandException { if (!theDataset.getOwner().isReleased()) { throw new IllegalCommandException("This dataset may not be published because its host dataverse (" + theDataset.getOwner().getAlias() + ") has not been published.", this); } if (theDataset.getLatestVersion().isReleased()) { throw new IllegalCommandException("Latest version of dataset " + theDataset.getIdentifier() + " is already released. Only draft versions can be released.", this); } if (minorRelease && !theDataset.getLatestVersion().isMinorUpdate()) { throw new IllegalCommandException("Cannot release as minor version. Re-try as major release.", this); } /* make an attempt to register if not registered */ String nonNullDefaultIfKeyNotFound = ""; String protocol = theDataset.getProtocol(); String doiProvider = ctxt.settings().getValueForKey(SettingsServiceBean.Key.DoiProvider, nonNullDefaultIfKeyNotFound); String authority = theDataset.getAuthority(); if (theDataset.getGlobalIdCreateTime() == null) { if (protocol.equals("doi") && (doiProvider.equals("EZID") || doiProvider.equals("DataCite"))) { String doiRetString = ""; if (doiProvider.equals("EZID")) { doiRetString = ctxt.doiEZId().createIdentifier(theDataset); if (doiRetString.contains(theDataset.getIdentifier())) { theDataset.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } else if (doiRetString.contains("identifier already exists")) { theDataset.setIdentifier(ctxt.datasets().generateIdentifierSequence(protocol, authority, theDataset.getDoiSeparator())); doiRetString = ctxt.doiEZId().createIdentifier(theDataset); if (!doiRetString.contains(theDataset.getIdentifier())) { throw new IllegalCommandException("This dataset may not be published because its identifier is already in use by another dataset. Please contact Dataverse Support for assistance.", this); } else { theDataset.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } } else { throw new IllegalCommandException("This dataset may not be published because it has not been registered. Please contact Dataverse Support for assistance.", this); } } if (doiProvider.equals("DataCite")) { try { if (!ctxt.doiDataCite().alreadyExists(theDataset)) { ctxt.doiDataCite().createIdentifier(theDataset); theDataset.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } else { theDataset.setIdentifier(ctxt.datasets().generateIdentifierSequence(protocol, authority, theDataset.getDoiSeparator())); if (!ctxt.doiDataCite().alreadyExists(theDataset)) { ctxt.doiDataCite().createIdentifier(theDataset); theDataset.setGlobalIdCreateTime(new Timestamp(new Date().getTime())); } else { throw new IllegalCommandException("This dataset may not be published because its identifier is already in use by another dataset. Please contact Dataverse Support for assistance.", this); } } } catch (Exception e) { throw new CommandException(ResourceBundle.getBundle("Bundle").getString("dataset.publish.error.datacite"), this); } } } else { throw new IllegalCommandException("This dataset may not be published because its DOI provider is not supported. Please contact Dataverse Support for assistance.", this); } } if (theDataset.getPublicationDate() == null) { //Before setting dataset to released send notifications to users with download file List<RoleAssignment> ras = ctxt.roles().directRoleAssignments(theDataset); for (RoleAssignment ra : ras) { if (ra.getRole().permissions().contains(Permission.DownloadFile)) { for (AuthenticatedUser au : ctxt.roleAssignees().getExplicitUsers(ctxt.roleAssignees().getRoleAssignee(ra.getAssigneeIdentifier()))) { ctxt.notifications().sendNotification(au, new Timestamp(new Date().getTime()), UserNotification.Type.ASSIGNROLE, theDataset.getId()); } } } theDataset.setPublicationDate(new Timestamp(new Date().getTime())); theDataset.setReleaseUser((AuthenticatedUser) getUser()); if (!minorRelease) { theDataset.getEditVersion().setVersionNumber(new Long(1)); theDataset.getEditVersion().setMinorVersionNumber(new Long(0)); } else { theDataset.getEditVersion().setVersionNumber(new Long(0)); theDataset.getEditVersion().setMinorVersionNumber(new Long(1)); } } else if (!minorRelease) { theDataset.getEditVersion().setVersionNumber(new Long(theDataset.getVersionNumber() + 1)); theDataset.getEditVersion().setMinorVersionNumber(new Long(0)); } else { theDataset.getEditVersion().setVersionNumber(new Long(theDataset.getVersionNumber())); theDataset.getEditVersion().setMinorVersionNumber(new Long(theDataset.getMinorVersionNumber() + 1)); } Timestamp updateTime = new Timestamp(new Date().getTime()); theDataset.getEditVersion().setReleaseTime(updateTime); theDataset.getEditVersion().setLastUpdateTime(updateTime); theDataset.setModificationTime(updateTime); //set inReview to False because it is now published theDataset.getEditVersion().setInReview(false); theDataset.getEditVersion().setVersionState(DatasetVersion.VersionState.RELEASED); for (DataFile dataFile : theDataset.getFiles()) { if (dataFile.getPublicationDate() == null) { // this is a new, previously unpublished file, so publish by setting date dataFile.setPublicationDate(updateTime); // check if any prexisting roleassignments have file download and send notifications List<RoleAssignment> ras = ctxt.roles().directRoleAssignments(dataFile); for (RoleAssignment ra : ras) { if (ra.getRole().permissions().contains(Permission.DownloadFile)) { for (AuthenticatedUser au : ctxt.roleAssignees().getExplicitUsers(ctxt.roleAssignees().getRoleAssignee(ra.getAssigneeIdentifier()))) { ctxt.notifications().sendNotification(au, new Timestamp(new Date().getTime()), UserNotification.Type.GRANTFILEACCESS, theDataset.getId()); } } } } // set the files restriction flag to the same as the latest version's if (dataFile.getFileMetadata() != null && dataFile.getFileMetadata().getDatasetVersion().equals(theDataset.getLatestVersion())) { dataFile.setRestricted(dataFile.getFileMetadata().isRestricted()); } } theDataset.setFileAccessRequest(theDataset.getLatestVersion().getTermsOfUseAndAccess().isFileAccessRequest()); /* Attempting to run metadata export, for all the formats for which we have metadata Exporters: */ try { ExportService instance = ExportService.getInstance(); instance.exportAllFormats(theDataset); } catch (ExportException ex) { // Something went wrong! // Just like with indexing, a failure to export is not a fatal // condition. We'll just log the error as a warning and keep // going: logger.log(Level.WARNING, "Exception while exporting:" + ex.getMessage()); } Dataset savedDataset = ctxt.em().merge(theDataset); // set the subject of the parent (all the way up) Dataverses DatasetField subject = null; for (DatasetField dsf : savedDataset.getLatestVersion().getDatasetFields()) { if (dsf.getDatasetFieldType().getName().equals(DatasetFieldConstant.subject)) { subject = dsf; break; } } if (subject != null) { Dataverse dv = savedDataset.getOwner(); while (dv != null) { if (dv.getDataverseSubjects().addAll(subject.getControlledVocabularyValues())) { ctxt.index().indexDataverse(dv); // need to reindex to capture the new subjects } dv = dv.getOwner(); } } DatasetVersionUser ddu = ctxt.datasets().getDatasetVersionUser(savedDataset.getLatestVersion(), this.getUser()); if (ddu != null) { ddu.setLastUpdateDate(updateTime); ctxt.em().merge(ddu); } else { DatasetVersionUser datasetDataverseUser = new DatasetVersionUser(); datasetDataverseUser.setDatasetVersion(savedDataset.getLatestVersion()); datasetDataverseUser.setLastUpdateDate((Timestamp) updateTime); String id = getUser().getIdentifier(); id = id.startsWith("@") ? id.substring(1) : id; AuthenticatedUser au = ctxt.authentication().getAuthenticatedUser(id); datasetDataverseUser.setAuthenticatedUser(au); ctxt.em().merge(datasetDataverseUser); } if (protocol.equals("doi") && doiProvider.equals("EZID")) { ctxt.doiEZId().publicizeIdentifier(savedDataset); } if (protocol.equals("doi") && doiProvider.equals("DataCite")) { try { ctxt.doiDataCite().publicizeIdentifier(savedDataset); } catch (IOException io) { throw new CommandException(ResourceBundle.getBundle("Bundle").getString("dataset.publish.error.datacite"), this); } catch (Exception e) { if (e.toString().contains("Internal Server Error")) { throw new CommandException(ResourceBundle.getBundle("Bundle").getString("dataset.publish.error.datacite"), this); } throw new CommandException(ResourceBundle.getBundle("Bundle").getString("dataset.publish.error.datacite"), this); } } PrivateUrl privateUrl = ctxt.engine().submit(new GetPrivateUrlCommand(getRequest(), savedDataset)); if (privateUrl != null) { logger.fine("Deleting Private URL for dataset id " + savedDataset.getId()); ctxt.engine().submit(new DeletePrivateUrlCommand(getRequest(), savedDataset)); } /* MoveIndexing to after DOI update so that if command exception is thrown the re-index will not */ boolean doNormalSolrDocCleanUp = true; ctxt.index().indexDataset(savedDataset, doNormalSolrDocCleanUp); /** * @todo consider also ctxt.solrIndex().indexPermissionsOnSelfAndChildren(theDataset); */ /** * @todo what should we do with the indexRespose? */ IndexResponse indexResponse = ctxt.solrIndex().indexPermissionsForOneDvObject(savedDataset); return savedDataset; } }