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

[pkp-lib][main] #10669 Change Version support for publications #10810

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
74 changes: 73 additions & 1 deletion api/v1/submissions/PKPSubmissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
use PKP\notification\NotificationSubscriptionSettingsDAO;
use PKP\plugins\Hook;
use PKP\plugins\PluginRegistry;
use PKP\publication\enums\VersionStage;
use PKP\publication\helpers\VersionDataResource;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\authorization\DecisionWritePolicy;
use PKP\security\authorization\internal\SubmissionCompletePolicy;
Expand Down Expand Up @@ -112,7 +114,9 @@ class PKPSubmissionController extends PKPBaseController
'getPublicationIdentifierForm',
'getPublicationLicenseForm',
'getPublicationTitleAbstractForm',
'getChangeLanguageMetadata'
'getChangeLanguageMetadata',
'changeVersionData',
'getNextAvailableVersionData',
];

/** @var array Handlers that must be authorized to write to a publication */
Expand All @@ -123,6 +127,7 @@ class PKPSubmissionController extends PKPBaseController
'editContributor',
'saveContributorsOrder',
'changeLocale',
'changeVersionData'
];

/** @var array Handlers that must be authorized to access a submission's production stage */
Expand Down Expand Up @@ -237,6 +242,14 @@ public function getGroupRoutes(): void
Route::put('{submissionId}/publications/{publicationId}/changeLocale', $this->changeLocale(...))
->name('submission.publication.changeLocale')
->whereNumber(['submissionId', 'publicationId']);

Route::put('{submissionId}/publications/{publicationId}/changeVersionData', $this->changeVersionData(...))
->name('submission.publication.changeVersionData')
->whereNumber(['submissionId', 'publicationId']);

Route::get('{submissionId}/getNextAvailableVersionData', $this->getNextAvailableVersionData(...))
->name('submission.getNextAvailableVersionData')
->whereNumber(['submissionId']);
});

Route::middleware([
Expand Down Expand Up @@ -944,6 +957,65 @@ public function changeLocale(Request $illuminateRequest): JsonResponse
return $this->edit($illuminateRequest);
}

/**
* Change version data for publication
*/
public function changeVersionData(Request $illuminateRequest): JsonResponse
{
$request = $this->getRequest();
$publication = Repo::publication()->get((int) $illuminateRequest->route('publicationId'));

if (!$publication) {
return response()->json([
'error' => __('api.404.resourceNotFound'),
], Response::HTTP_NOT_FOUND);
}

$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);

if ($submission->getId() !== $publication->getData('submissionId')) {
return response()->json([
'error' => __('api.publications.403.submissionsDidNotMatch'),
], Response::HTTP_FORBIDDEN);
}

$params = $this->convertStringsToSchema(PKPSchemaService::SCHEMA_PUBLICATION, $illuminateRequest->input());

$submissionContext = $request->getContext();

$errors = Repo::publication()->validate($publication, $params, $submission, $submissionContext);

if (!empty($errors)) {
return response()->json($errors, Response::HTTP_BAD_REQUEST);
}

$versionStage = $params['versionStage'];
$versionStageIsMinor = (bool) $params['versionIsMinor'];

Repo::publication()->updateVersionData($publication, VersionStage::from($versionStage), $versionStageIsMinor);

return $this->edit($illuminateRequest);
}

/**
* Get next potential version for submission
*/
public function getNextAvailableVersionData(Request $illuminateRequest): JsonResponse
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);

$params = $illuminateRequest->input();
$potentialVersionStage = VersionStage::from($params['versionStage']);
$potentialIsMinor = ($params['versionIsMinor'] === 'false') ? false : (bool) $params['versionIsMinor'];

$potentialVersionStage = Repo::submission()->getNextAvailableVersionData($submission, $potentialVersionStage, $potentialIsMinor);

return response()->json(
(new VersionDataResource($potentialVersionStage))->toArray($illuminateRequest),
Response::HTTP_OK
);
}

/**
* Get the decisions recorded on a submission
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

/**
* @file classes/migration/upgrade/v3_5_0/I4860_MigratePublicationVersion.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class I4860_MigratePublicationVersion
*
* @brief Add additional columns for publication versioning and migrate existing data
*/

namespace PKP\migration\upgrade\v3_5_0;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use PKP\migration\Migration;
use PKP\publication\enums\VersionStage;

class I4860_MigratePublicationVersion extends Migration
{
/**
* Run the migration.
*/
public function up(): void
{
Schema::table('publications', function (Blueprint $table) {
// Adding the enum column for VersionStage
$table->enum('version_stage', array_column(VersionStage::cases(), 'value'))
->nullable();

// Adding version_minor and version_major as integers
$table->integer('version_minor')
->nullable();

$table->integer('version_major')
->nullable();
});

// Update the version_major column based on the version column
DB::table('publications')->update([
'version_major' => DB::raw('version'), // Copy version to version_major
'version_minor' => 0, // Set version_minor to 0
'version_stage' => VersionStage::VERSION_OF_RECORD, // Set version_stage to VERSION_OF_RECORD
]);

// remove the `version` column
Schema::table('publications', function (Blueprint $table) {
$table->dropColumn('version');
});
}

/**
* Reverses the migration
*/
public function down(): void
{
// Re-add the `version` column
Schema::table('publications', function (Blueprint $table) {
$table->integer('version')->nullable();
});

// Update the `version` column based on `version_major`
DB::table('publications')->update([
'version' => DB::raw('version_major')
]);

// Drop the added columns
Schema::table('publications', function (Blueprint $table) {
$table->dropColumn(['version_stage', 'version_minor', 'version_major']);
});
}
}
2 changes: 1 addition & 1 deletion classes/publication/Collector.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public function getQueryBuilder(): Builder
$qb->offset($this->offset);
}

$qb->orderBy('p.version', 'asc');
$qb->orderBy('p.publication_id', 'asc');

// Add app-specific query statements
Hook::call('Publication::Collector', [&$qb, $this]);
Expand Down
31 changes: 31 additions & 0 deletions classes/publication/PKPPublication.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
use PKP\core\Core;
use PKP\core\PKPString;
use PKP\facades\Locale;
use PKP\publication\enums\VersionStage;
use PKP\publication\helpers\VersionData;
use PKP\services\PKPSchemaService;
use PKP\userGroup\UserGroup;

Expand Down Expand Up @@ -466,6 +468,35 @@ public function getLanguages(?array ...$additionalLocales): array
->values()
->toArray();
}

/**
* Get the current version data
*/
public function getCurrentVersionData(): ?VersionData
{
$versionStageStr = $this->getData('versionStage');
if (!isset($versionStageStr)) {
return null;
}

$versionStage = new VersionData();
$versionStage->stage = VersionStage::from($versionStageStr);
$versionStage->majorNumbering = $this->getData('versionMajor');
$versionStage->minorNumbering = $this->getData('versionMinor');

return $versionStage;
}

/**
* Set the current version of the publication
* given a VersionData object
*/
public function setVersionData(VersionData $versionData): void
{
$this->setData('versionStage', $versionData->stage->value);
$this->setData('versionMajor', $versionData->majorNumbering);
$this->setData('versionMinor', $versionData->minorNumbering);
}
}
if (!PKP_STRICT_MODE) {
class_alias('\PKP\publication\PKPPublication', '\PKPPublication');
Expand Down
93 changes: 89 additions & 4 deletions classes/publication/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
use PKP\context\Context;
use PKP\core\Core;
use PKP\core\PKPApplication;
use PKP\core\PKPString;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\file\TemporaryFileManager;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\observers\events\PublicationPublished;
use PKP\observers\events\PublicationUnpublished;
use PKP\orcid\OrcidManager;
use PKP\plugins\Hook;
use PKP\publication\enums\VersionStage;
use PKP\security\Validation;
use PKP\services\PKPSchemaService;
use PKP\submission\Genre;
Expand Down Expand Up @@ -327,13 +330,31 @@ public function add(Publication $publication): int
*
* @hook Publication::version [[&$newPublication, $publication]]
*/
public function version(Publication $publication): int
public function version(Publication $publication, ?VersionStage $versionStage = null, bool $isMinorVersion = true): 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);

$submission = Repo::submission()->get($publication->getData('submissionId'));

// VersionStage Update
$newVersionStage = $versionStage;
$newIsMinorVersion = $isMinorVersion;

if (!isset($newVersionStage)) {
$currentVersionData = $newPublication->getCurrentVersionData();
if (isset($currentVersionData)) {
$newVersionStage = $currentVersionData->stage;
}
}

if (isset($newVersionStage)) {
$newVersionStage = Repo::submission()->getNextAvailableVersionData($submission, $newVersionStage, $newIsMinorVersion);
$newPublication->setVersionData($newVersionStage);
}

$newPublication->stampModified();

$request = Application::get()->getRequest();
Expand Down Expand Up @@ -379,8 +400,6 @@ public function version(Publication $publication): int

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(),
Expand Down Expand Up @@ -500,6 +519,12 @@ public function publish(Publication $publication)
);
}

// Update publication version data
$currentVersionData = $newPublication->getCurrentVersionData();
if (!isset($currentVersionData)) {
$this->updateVersionData($newPublication, VersionStage::VERSION_OF_RECORD, false);
}

Hook::call('Publication::publish::before', [&$newPublication, $publication]);

$this->dao->update($newPublication);
Expand Down Expand Up @@ -661,6 +686,66 @@ public function delete(Publication $publication)
Hook::call('Publication::delete', [&$publication]);
}

/**
* Given a Version Stage and a flag of whether the Version isMinor,
* the publication's related data is being updated
*
* @hook 'Publication::updateVersionData::before' [[ &$newPublication, $publication ]]
*/
public function updateVersionData(Publication $publication, VersionStage $versioningStage, bool $isMinor = true): Publication
{
$submission = Repo::submission()->get($publication->getData('submissionId'));
$nextAvailableVersionStage = Repo::submission()->getNextAvailableVersionData($submission, $versioningStage, $isMinor);

$newPublication = clone $publication;
$newPublication->setData('versionIsMinor', $isMinor);
$newPublication->setVersionData($nextAvailableVersionStage);

$newPublication->stampModified();
Hook::call(
'Publication::updateVersionData::before',
[
&$newPublication,
$publication
]
);

$this->dao->update($newPublication);

$newPublication = Repo::publication()->get($newPublication->getId());

return $newPublication;
}

/**
* Get the string that describes the
* given publication's version.
*/
public function getVersionDataDisplay(Publication $publication, ?Submission $submission = null, ?Context $submissionContext = null): string
{
$currentVersionStage = $publication->getCurrentVersionData();

if (!isset($currentVersionStage)) {
if (!isset($submissionContext)) {
if (!isset($submission)) {
$submission = Repo::submission()->get($publication->getData('submissionId'));
}

$submissionContext = app()->get('context')->get($submission->getData('contextId'));
}

$dateFormatShort = PKPString::convertStrftimeFormat($submissionContext->getLocalizedDateFormatShort());

return __('publication.versionStage.unassignedVersion', [
'publicationCreatedDate' => (new \Carbon\Carbon($publication->getData('lastModified')))
->locale(Locale::getLocale())
->translatedFormat($dateFormatShort),
]);
}

return $currentVersionStage->display();
}

/**
* Handle a publication setting for an uploaded file
*
Expand Down
Loading