736 lines
28 KiB
PHP
736 lines
28 KiB
PHP
<?php
|
|
/**
|
|
* @file classes/publication/Repository.php
|
|
*
|
|
* Copyright (c) 2014-2020 Simon Fraser University
|
|
* Copyright (c) 2000-2020 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class Repository
|
|
*
|
|
* @brief A repository to find and manage publications.
|
|
*/
|
|
|
|
namespace PKP\publication;
|
|
|
|
use APP\core\Application;
|
|
use APP\core\Request;
|
|
use APP\core\Services;
|
|
use APP\facades\Repo;
|
|
use APP\file\PublicFileManager;
|
|
use APP\publication\DAO;
|
|
use APP\publication\Publication;
|
|
use APP\submission\Submission;
|
|
use Illuminate\Support\Enumerable;
|
|
use Illuminate\Support\LazyCollection;
|
|
use PKP\context\Context;
|
|
use PKP\core\Core;
|
|
use PKP\core\PKPApplication;
|
|
use PKP\db\DAORegistry;
|
|
use PKP\file\TemporaryFileManager;
|
|
use PKP\log\event\PKPSubmissionEventLogEntry;
|
|
use PKP\observers\events\PublicationPublished;
|
|
use PKP\observers\events\PublicationUnpublished;
|
|
use PKP\plugins\Hook;
|
|
use PKP\security\Validation;
|
|
use PKP\services\PKPSchemaService;
|
|
use PKP\submission\Genre;
|
|
use PKP\submission\PKPSubmission;
|
|
use PKP\userGroup\UserGroup;
|
|
use PKP\validation\ValidatorFactory;
|
|
|
|
abstract class Repository
|
|
{
|
|
/** @var DAO */
|
|
public $dao;
|
|
|
|
/** @var string $schemaMap The name of the class to map this entity to its schema */
|
|
public $schemaMap = maps\Schema::class;
|
|
|
|
/** @var Request */
|
|
protected $request;
|
|
|
|
/** @var PKPSchemaService<Publication> */
|
|
protected $schemaService;
|
|
|
|
public function __construct(DAO $dao, Request $request, PKPSchemaService $schemaService)
|
|
{
|
|
$this->dao = $dao;
|
|
$this->request = $request;
|
|
$this->schemaService = $schemaService;
|
|
}
|
|
|
|
/** @copydoc DAO::newDataObject() */
|
|
public function newDataObject(array $params = []): Publication
|
|
{
|
|
$object = $this->dao->newDataObject();
|
|
if (!empty($params)) {
|
|
$object->setAllData($params);
|
|
}
|
|
return $object;
|
|
}
|
|
|
|
/** @copydoc DAO::exists() */
|
|
public function exists(int $id, int $submissionId = null): bool
|
|
{
|
|
return $this->dao->exists($id, $submissionId);
|
|
}
|
|
|
|
/** @copydoc DAO::get() */
|
|
public function get(int $id, int $submissionId = null): ?Publication
|
|
{
|
|
return $this->dao->get($id, $submissionId);
|
|
}
|
|
|
|
/** @copydoc DAO::getCollector() */
|
|
public function getCollector(): Collector
|
|
{
|
|
return app(Collector::class);
|
|
}
|
|
|
|
/**
|
|
* Get an instance of the map class for mapping
|
|
* publications to their schema
|
|
*
|
|
* @param LazyCollection<int,UserGroup> $userGroups
|
|
* @param Genre[] $genres
|
|
*/
|
|
public function getSchemaMap(Submission $submission, LazyCollection $userGroups, array $genres): maps\Schema
|
|
{
|
|
return app('maps')->withExtensions(
|
|
$this->schemaMap,
|
|
[
|
|
'submission' => $submission,
|
|
'userGroups' => $userGroups,
|
|
'genres' => $genres,
|
|
]
|
|
);
|
|
}
|
|
|
|
/** @copydoc DAO:: getIdsBySetting()*/
|
|
public function getIdsBySetting(string $settingName, $settingValue, int $contextId): Enumerable
|
|
{
|
|
return $this->dao->getIdsBySetting($settingName, $settingValue, $contextId);
|
|
}
|
|
|
|
/** @copydoc DAO:: getDateBoundaries()*/
|
|
public function getDateBoundaries(Collector $query): object
|
|
{
|
|
return $this->dao->getDateBoundaries($query);
|
|
}
|
|
|
|
/**
|
|
* Validate properties for a publication
|
|
*
|
|
* Perform validation checks on data used to add or edit a publication.
|
|
*
|
|
* @param Publication|null $publication The publication being edited. Pass `null` if creating a new publication
|
|
* @param array $props A key/value array with the new data to validate
|
|
*
|
|
* @return array A key/value array with validation errors. Empty if no errors
|
|
*/
|
|
public function validate(?Publication $publication, array $props, Submission $submission, Context $context): array
|
|
{
|
|
$allowedLocales = $context->getSupportedSubmissionLocales();
|
|
$primaryLocale = $submission->getLocale();
|
|
|
|
$errors = [];
|
|
|
|
$validator = ValidatorFactory::make(
|
|
$props,
|
|
$this->schemaService->getValidationRules($this->dao->schema, $allowedLocales),
|
|
$this->getErrorMessageOverrides(),
|
|
);
|
|
|
|
ValidatorFactory::required(
|
|
$validator,
|
|
$publication,
|
|
$this->schemaService->getRequiredProps($this->dao->schema),
|
|
$this->schemaService->getMultilingualProps($this->dao->schema),
|
|
$allowedLocales,
|
|
$primaryLocale
|
|
);
|
|
|
|
ValidatorFactory::allowedLocales($validator, $this->schemaService->getMultilingualProps($this->dao->schema), $allowedLocales);
|
|
|
|
// The submissionId must match an existing submission
|
|
if (isset($props['submissionId'])) {
|
|
$validator->after(function ($validator) use ($props) {
|
|
if (!$validator->errors()->get('submissionId')) {
|
|
$submission = Repo::submission()->get($props['submissionId']);
|
|
if (!$submission) {
|
|
$validator->errors()->add('submissionId', __('publication.invalidSubmission'));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// A title must be provided if the submission is not still in progress
|
|
if (!$submission->getData('submissionProgress')) {
|
|
$validator->after(function ($validator) use ($props, $publication, $primaryLocale) {
|
|
$title = isset($props['title']) && isset($props['title'][$primaryLocale])
|
|
? $props['title'][$primaryLocale]
|
|
: $publication?->getData('title', $primaryLocale);
|
|
if (empty($title)) {
|
|
$validator->errors()->add('title.' . $primaryLocale, __('validator.required'));
|
|
}
|
|
});
|
|
}
|
|
|
|
// The urlPath must not be used in a publication attached to
|
|
// any submission other than this publication's submission
|
|
if (strlen($props['urlPath'] ?? '')) {
|
|
$validator->after(function ($validator) use ($publication, $props) {
|
|
if (!$validator->errors()->get('urlPath')) {
|
|
if (ctype_digit((string) $props['urlPath'])) {
|
|
$validator->errors()->add('urlPath', __('publication.urlPath.numberInvalid'));
|
|
return;
|
|
}
|
|
|
|
// If there is no submissionId the validator will throw it back anyway
|
|
if (is_null($publication) && !empty($props['submissionId'])) {
|
|
$submission = Repo::submission()->get($props['submissionId']);
|
|
} elseif (!is_null($publication)) {
|
|
$submission = Repo::submission()->get($publication->getData('submissionId'));
|
|
}
|
|
|
|
// If there's no submission we can't validate but the validator should
|
|
// fail anyway, so we can return without setting a separate validation
|
|
// error.
|
|
if (!$submission) {
|
|
return;
|
|
}
|
|
|
|
if ($this->dao->isDuplicateUrlPath($props['urlPath'], $submission->getId(), $submission->getData('contextId'))) {
|
|
$validator->errors()->add('urlPath', __('publication.urlPath.duplicate'));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// If a new file has been uploaded, check that the temporary file exists and
|
|
// the current user owns it
|
|
$user = Application::get()->getRequest()->getUser();
|
|
ValidatorFactory::temporaryFilesExist(
|
|
$validator,
|
|
['coverImage'],
|
|
['coverImage'],
|
|
$props,
|
|
$allowedLocales,
|
|
$user ? $user->getId() : null
|
|
);
|
|
|
|
if ($validator->fails()) {
|
|
$errors = $this->schemaService->formatValidationErrors($validator->errors());
|
|
}
|
|
|
|
Hook::call('Publication::validate', [&$errors, $publication, $props, $allowedLocales, $primaryLocale]);
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/**
|
|
* Validate a publication against publishing requirements
|
|
*
|
|
* This validation check should return zero errors before
|
|
* publishing a publication.
|
|
*
|
|
* It should not be necessary to repeat validation rules from
|
|
* self::validate(). These rules should be applied during all add
|
|
* or edit actions.
|
|
*
|
|
* This additional check should be used when a journal or press
|
|
* wants to enforce particular publishing requirements, such as
|
|
* requiring certain metadata or other information.
|
|
*
|
|
* @param array $allowedLocales The context's supported submission locales
|
|
* @param string $primaryLocale The submission's primary locale
|
|
*/
|
|
public function validatePublish(Publication $publication, Submission $submission, array $allowedLocales, string $primaryLocale): array
|
|
{
|
|
$errors = [];
|
|
|
|
// Don't allow declined submissions to be published
|
|
if ($submission->getData('status') === PKPSubmission::STATUS_DECLINED) {
|
|
$errors['declined'] = __('publication.required.declined');
|
|
}
|
|
|
|
// Don't allow a publication to be published before passing the review stage
|
|
if ($submission->getData('stageId') <= WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
|
|
$errors['reviewStage'] = __('publication.required.reviewStage');
|
|
}
|
|
|
|
Hook::call('Publication::validatePublish', [&$errors, $publication, $submission, $allowedLocales, $primaryLocale]);
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/** @copydoc DAO::insert() */
|
|
public function add(Publication $publication): int
|
|
{
|
|
$publication->stampModified();
|
|
$publicationId = $this->dao->insert($publication);
|
|
$publication = Repo::publication()->get($publicationId);
|
|
$submission = Repo::submission()->get($publication->getData('submissionId'));
|
|
|
|
// Move uploaded files into place and update the settings
|
|
if ($publication->getData('coverImage')) {
|
|
$userId = $this->request->getUser() ? $this->request->getUser()->getId() : null;
|
|
|
|
$submissionContext = $this->request->getContext();
|
|
if ($submissionContext->getId() !== $submission->getData('contextId')) {
|
|
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
|
|
}
|
|
|
|
$supportedLocales = $submissionContext->getSupportedSubmissionLocales();
|
|
foreach ($supportedLocales as $localeKey) {
|
|
if (!array_key_exists($localeKey, $publication->getData('coverImage'))) {
|
|
continue;
|
|
}
|
|
$value[$localeKey] = $this->_saveFileParam($publication, $submission, $publication->getData('coverImage', $localeKey), 'coverImage', $userId, $localeKey, true);
|
|
}
|
|
|
|
$this->edit($publication, ['coverImage' => $value]);
|
|
}
|
|
|
|
Hook::call('Publication::add', [&$publication]);
|
|
|
|
// Update a submission's status based on the status of its publications
|
|
Repo::submission()->updateStatus($submission);
|
|
|
|
return $publication->getId();
|
|
}
|
|
|
|
/**
|
|
* Create a new version of a publication
|
|
*
|
|
* Makes a copy of an existing publication, without the datePublished,
|
|
* and makes copies of all associated objects.
|
|
*/
|
|
public function version(Publication $publication): int
|
|
{
|
|
$newPublication = clone $publication;
|
|
$newPublication->setData('id', null);
|
|
$newPublication->setData('datePublished', null);
|
|
$newPublication->setData('status', Submission::STATUS_QUEUED);
|
|
$newPublication->setData('version', $publication->getData('version') + 1);
|
|
$newPublication->stampModified();
|
|
|
|
$request = Application::get()->getRequest();
|
|
$context = $request->getContext();
|
|
|
|
if ($context->getData(Context::SETTING_DOI_VERSIONING)) {
|
|
$newPublication->setData('doiId', null);
|
|
}
|
|
$newId = $this->add($newPublication);
|
|
$newPublication = Repo::publication()->get($newId);
|
|
|
|
$authors = $publication->getData('authors');
|
|
if (!empty($authors)) {
|
|
foreach ($authors as $author) {
|
|
$newAuthor = clone $author;
|
|
$newAuthor->setData('id', null);
|
|
$newAuthor->setData('publicationId', $newPublication->getId());
|
|
$newAuthorId = Repo::author()->add($newAuthor);
|
|
|
|
if ($author->getId() === $publication->getData('primaryContactId')) {
|
|
$this->edit($newPublication, ['primaryContactId' => $newAuthorId]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($newPublication->getData('citationsRaw'))) {
|
|
$citationDao = DAORegistry::getDAO('CitationDAO'); /** @var \PKP\citation\CitationDAO $citationDao */
|
|
$citationDao->importCitations($newPublication->getId(), $newPublication->getData('citationsRaw'));
|
|
}
|
|
|
|
$newPublication = Repo::publication()->get($newPublication->getId());
|
|
|
|
Hook::call('Publication::version', [&$newPublication, $publication]);
|
|
|
|
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
|
|
|
|
$eventLog = Repo::eventLog()->newDataObject([
|
|
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
|
|
'assocId' => $submission->getId(),
|
|
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_CREATE_VERSION,
|
|
'userId' => Validation::loggedInAs() ?? $request->getUser()?->getId(),
|
|
'message' => 'publication.event.versionCreated',
|
|
'isTranslated' => false,
|
|
'dateLogged' => Core::getCurrentDate(),
|
|
]);
|
|
Repo::eventLog()->add($eventLog);
|
|
|
|
return $newPublication->getId();
|
|
}
|
|
|
|
/** @copydoc DAO::update() */
|
|
public function edit(Publication $publication, array $params): Publication
|
|
{
|
|
$submission = Repo::submission()->get($publication->getData('submissionId'));
|
|
$userId = $this->request->getUser()?->getId();
|
|
|
|
// Move uploaded files into place and update the params
|
|
if (array_key_exists('coverImage', $params)) {
|
|
$submissionContext = $this->request->getContext();
|
|
if ($submissionContext->getId() !== $submission->getData('contextId')) {
|
|
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
|
|
}
|
|
|
|
$supportedLocales = $submissionContext->getSupportedSubmissionLocales();
|
|
foreach ($supportedLocales as $localeKey) {
|
|
if (!array_key_exists($localeKey, $params['coverImage'])) {
|
|
continue;
|
|
}
|
|
$params['coverImage'][$localeKey] = $this->_saveFileParam($publication, $submission, $params['coverImage'][$localeKey], 'coverImage', $userId, $localeKey, true);
|
|
}
|
|
}
|
|
|
|
$newPublication = Repo::publication()->newDataObject(array_merge($publication->_data, $params));
|
|
$newPublication->stampModified();
|
|
|
|
Hook::call('Publication::edit', [&$newPublication, $publication, $params, $this->request]);
|
|
|
|
$this->dao->update($newPublication, $publication);
|
|
|
|
$newPublication = Repo::publication()->get($newPublication->getId());
|
|
|
|
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
|
|
|
|
// Log an event when publication data is updated
|
|
$eventLog = Repo::eventLog()->newDataObject([
|
|
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
|
|
'assocId' => $submission->getId(),
|
|
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_UPDATE,
|
|
'userId' => Validation::loggedInAs() ?? $userId,
|
|
'message' => 'submission.event.general.metadataUpdated',
|
|
'isTranslated' => false,
|
|
'dateLogged' => Core::getCurrentDate(),
|
|
]);
|
|
Repo::eventLog()->add($eventLog);
|
|
|
|
return $newPublication;
|
|
}
|
|
|
|
/**
|
|
* Publish a publication
|
|
*
|
|
* This method performs all actions needed when publishing an item, such
|
|
* as setting metadata, logging events, updating the search index, etc.
|
|
*
|
|
* @throws \Exception
|
|
*
|
|
* @see self::setStatusOnPublish()
|
|
*/
|
|
public function publish(Publication $publication)
|
|
{
|
|
$newPublication = clone $publication;
|
|
$newPublication->stampModified();
|
|
|
|
$this->setStatusOnPublish($newPublication);
|
|
|
|
// Set the copyright and license information
|
|
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
|
|
|
|
$itsPublished = ($newPublication->getData('status') === PKPSubmission::STATUS_PUBLISHED);
|
|
|
|
if ($itsPublished && !$newPublication->getData('copyrightHolder')) {
|
|
$newPublication->setData(
|
|
'copyrightHolder',
|
|
$submission->_getContextLicenseFieldValue(
|
|
null,
|
|
PKPSubmission::PERMISSIONS_FIELD_COPYRIGHT_HOLDER,
|
|
$newPublication
|
|
)
|
|
);
|
|
}
|
|
|
|
if ($itsPublished && !$newPublication->getData('copyrightYear')) {
|
|
$newPublication->setData(
|
|
'copyrightYear',
|
|
$submission->_getContextLicenseFieldValue(
|
|
null,
|
|
PKPSubmission::PERMISSIONS_FIELD_COPYRIGHT_YEAR,
|
|
$newPublication
|
|
)
|
|
);
|
|
}
|
|
|
|
if ($itsPublished && !$newPublication->getData('licenseUrl')) {
|
|
$newPublication->setData(
|
|
'licenseUrl',
|
|
$submission->_getContextLicenseFieldValue(
|
|
null,
|
|
PKPSubmission::PERMISSIONS_FIELD_LICENSE_URL,
|
|
$newPublication
|
|
)
|
|
);
|
|
}
|
|
|
|
Hook::call('Publication::publish::before', [&$newPublication, $publication]);
|
|
|
|
$this->dao->update($newPublication);
|
|
|
|
$newPublication = Repo::publication()->get($newPublication->getId());
|
|
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
|
|
|
|
// Update a submission's status based on the status of its publications
|
|
if ($newPublication->getData('status') !== $publication->getData('status')) {
|
|
Repo::submission()->updateStatus($submission);
|
|
$submission = Repo::submission()->get($submission->getId());
|
|
}
|
|
|
|
$msg = ($newPublication->getData('status') === Submission::STATUS_SCHEDULED) ? 'publication.event.scheduled' : 'publication.event.published';
|
|
|
|
// Log an event when publication is published. Adjust the message depending
|
|
// on whether this is the first publication or a subsequent version
|
|
if (count($submission->getData('publications')) > 1) {
|
|
$msg = ($newPublication->getData('status') === Submission::STATUS_SCHEDULED) ? 'publication.event.versionScheduled' : 'publication.event.versionPublished';
|
|
}
|
|
|
|
$eventLog = Repo::eventLog()->newDataObject([
|
|
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
|
|
'assocId' => $submission->getId(),
|
|
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_PUBLISH,
|
|
'userId' => Validation::loggedInAs() ?? $this->request->getUser()?->getId(),
|
|
'message' => $msg,
|
|
'isTranslated' => false,
|
|
'dateLogged' => Core::getCurrentDate()
|
|
]);
|
|
Repo::eventLog()->add($eventLog);
|
|
|
|
// Mark DOIs stale (if applicable).
|
|
if ($newPublication->getData('status') === Submission::STATUS_PUBLISHED) {
|
|
$staleDoiIds = Repo::doi()->getDoisForSubmission($newPublication->getData('submissionId'));
|
|
Repo::doi()->markStale($staleDoiIds);
|
|
}
|
|
|
|
Hook::call(
|
|
'Publication::publish',
|
|
[
|
|
&$newPublication,
|
|
$publication,
|
|
$submission
|
|
]
|
|
);
|
|
|
|
$context = $submission->getData('contextId') === Application::get()->getRequest()->getContext()?->getId()
|
|
? Application::get()->getRequest()->getContext()
|
|
: Services::get('context')->get($submission->getData('contextId'));
|
|
|
|
event(new PublicationPublished($newPublication, $publication, $submission, $context));
|
|
}
|
|
|
|
/**
|
|
* Set the status when an item is published
|
|
*
|
|
* Each application may handle publishing in a different way. Implement this method
|
|
* in an app-specific child class by assigning `status` and `datePublished` for this
|
|
* publication.
|
|
*
|
|
* This method should be called by self::publish().
|
|
*/
|
|
abstract protected function setStatusOnPublish(Publication $publication);
|
|
|
|
/**
|
|
* Unpublish a publication
|
|
*
|
|
* This method performs all actions needed when unpublishing an item, such
|
|
* as changing the status, logging events, updating the search index, etc.
|
|
*
|
|
* @see self::setStatusOnPublish()
|
|
*/
|
|
public function unpublish(Publication $publication)
|
|
{
|
|
$newPublication = clone $publication;
|
|
$newPublication->setData('status', Submission::STATUS_QUEUED);
|
|
$newPublication->stampModified();
|
|
|
|
Hook::call(
|
|
'Publication::unpublish::before',
|
|
[
|
|
&$newPublication,
|
|
$publication
|
|
]
|
|
);
|
|
|
|
$this->dao->update($newPublication);
|
|
|
|
$newPublication = Repo::publication()->get($newPublication->getId());
|
|
$submission = Repo::submission()->get($newPublication->getData('submissionId'));
|
|
|
|
// Update a submission's status based on the status of its publications
|
|
if ($newPublication->getData('status') !== $publication->getData('status')) {
|
|
Repo::submission()->updateStatus($submission);
|
|
$submission = Repo::submission()->get($submission->getId());
|
|
}
|
|
|
|
// Log an event when publication is unpublished. Adjust the message depending
|
|
// on whether this is the first publication or a subsequent version
|
|
$msg = 'publication.event.unpublished';
|
|
|
|
if (count($submission->getData('publications')) > 1) {
|
|
$msg = 'publication.event.versionUnpublished';
|
|
}
|
|
|
|
// Mark DOIs stable (if applicable).
|
|
if ($submission->getData('status') !== Submission::STATUS_PUBLISHED) {
|
|
$staleDoiIds = Repo::doi()->getDoisForSubmission($newPublication->getData('submissionId'));
|
|
Repo::doi()->markStale($staleDoiIds);
|
|
}
|
|
|
|
$eventLog = Repo::eventLog()->newDataObject([
|
|
'assocType' => PKPApplication::ASSOC_TYPE_SUBMISSION,
|
|
'assocId' => $submission->getId(),
|
|
'eventType' => PKPSubmissionEventLogEntry::SUBMISSION_LOG_METADATA_UNPUBLISH,
|
|
'userId' => Validation::loggedInAs() ?? $this->request->getUser()?->getId(),
|
|
'message' => $msg,
|
|
'isTranslated' => false,
|
|
'dateLogged' => Core::getCurrentDate()
|
|
]);
|
|
Repo::eventLog()->add($eventLog);
|
|
|
|
Hook::call(
|
|
'Publication::unpublish',
|
|
[
|
|
&$newPublication,
|
|
$publication,
|
|
$submission
|
|
]
|
|
);
|
|
|
|
$context = $submission->getData('contextId') === Application::get()->getRequest()->getContext()->getId()
|
|
? Application::get()->getRequest()->getContext()
|
|
: Services::get('context')->get($submission->getData('contextId'));
|
|
|
|
event(new PublicationUnpublished($newPublication, $publication, $submission, $context));
|
|
}
|
|
|
|
/** @copydoc DAO::delete() */
|
|
public function delete(Publication $publication)
|
|
{
|
|
Hook::call('Publication::delete::before', [&$publication]);
|
|
|
|
$submission = Repo::submission()->get($publication->getData('submissionId'));
|
|
$sectionId = $publication->getData(Application::getSectionIdPropName());
|
|
$section = $sectionId ? Repo::section()->get($sectionId) : null;
|
|
|
|
$this->dao->delete($publication);
|
|
|
|
// Update a submission's status based on the status of its remaining publications
|
|
$submission = Repo::submission()->get($publication->getData('submissionId'));
|
|
Repo::submission()->updateStatus($submission, null, $section);
|
|
|
|
Hook::call('Publication::delete', [&$publication]);
|
|
}
|
|
|
|
/**
|
|
* Handle a publication setting for an uploaded file
|
|
*
|
|
* - Moves the temporary file to the public directory
|
|
* - Resets the param value to what is expected to be stored in the db
|
|
* - If a null value is passed, deletes any existing file
|
|
*
|
|
* This method is protected because all operations which edit publications should
|
|
* go through the add and edit methods in order to ensure that
|
|
* the appropriate hooks are fired.
|
|
*
|
|
* @param Publication $publication The publication being edited
|
|
* @param Submission $submission The submission this publication is part of
|
|
* @param mixed $value The param value to be saved. Contains the temporary
|
|
* file ID if a new file has been uploaded.
|
|
* @param string $settingName The name of the setting to save, typically used
|
|
* in the filename.
|
|
* @param int $userId ID of the user who owns the temporary file
|
|
* @param string $localeKey Optional. Pass if the setting is multilingual
|
|
* @param bool $isImage Optional. For image files which include alt text in value
|
|
*
|
|
* @return string|array|bool New param value or false on failure
|
|
*/
|
|
protected function _saveFileParam(
|
|
Publication $publication,
|
|
Submission $submission,
|
|
$value,
|
|
string $settingName,
|
|
int $userId,
|
|
string $localeKey = '',
|
|
bool $isImage = false
|
|
) {
|
|
// If the value is null, delete any existing unused file in the system
|
|
if (is_null($value)) {
|
|
$oldPublication = Repo::publication()->get($publication->getId());
|
|
$oldValue = $oldPublication->getData($settingName, $localeKey);
|
|
$fileName = $oldValue['uploadName'] ?? null;
|
|
if ($fileName) {
|
|
// File may be in use by other publications
|
|
$fileInUse = false;
|
|
foreach ($submission->getData('publications') as $iPublication) {
|
|
if ($publication->getId() === $iPublication->getId()) {
|
|
continue;
|
|
}
|
|
$iValue = $iPublication->getData($settingName, $localeKey);
|
|
if (!empty($iValue['uploadName']) && $iValue['uploadName'] === $fileName) {
|
|
$fileInUse = true;
|
|
continue;
|
|
}
|
|
}
|
|
if (!$fileInUse) {
|
|
$publicFileManager = new PublicFileManager();
|
|
$publicFileManager->removeContextFile($submission->getData('contextId'), $fileName);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Check if there is something to upload
|
|
if (empty($value['temporaryFileId'])) {
|
|
return $value;
|
|
}
|
|
|
|
// Get the submission context
|
|
$submissionContext = $this->request->getContext();
|
|
if ($submissionContext->getId() !== $submission->getData('contextId')) {
|
|
$submissionContext = Services::get('context')->get($submission->getData('contextId'));
|
|
}
|
|
|
|
$temporaryFileManager = new TemporaryFileManager();
|
|
$temporaryFile = $temporaryFileManager->getFile((int) $value['temporaryFileId'], $userId);
|
|
$fileNameBase = join('_', ['submission', $submission->getId(), $publication->getId(), $settingName]); // eg - submission_1_1_coverImage
|
|
$fileName = Services::get('context')->moveTemporaryFile($submissionContext, $temporaryFile, $fileNameBase, $userId, $localeKey);
|
|
|
|
if ($fileName) {
|
|
if ($isImage) {
|
|
return [
|
|
'altText' => !empty($value['altText']) ? $value['altText'] : '',
|
|
'dateUploaded' => Core::getCurrentDate(),
|
|
'uploadName' => $fileName,
|
|
];
|
|
} else {
|
|
return [
|
|
'dateUploaded' => Core::getCurrentDate(),
|
|
'uploadName' => $fileName,
|
|
];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get error message overrides for the validator
|
|
*/
|
|
protected function getErrorMessageOverrides(): array
|
|
{
|
|
return [
|
|
'locale.regex' => __('validator.localeKey'),
|
|
'datePublished.date_format' => __('publication.datePublished.errorFormat'),
|
|
'urlPath.regex' => __('validator.alpha_dash_period'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Create all DOIs associated with the publication.
|
|
*/
|
|
abstract protected function createDois(Publication $newPublication): void;
|
|
}
|