Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e266eea
User can now select customlabels to reserve new certificate identifie…
dxL1nus Feb 10, 2026
c20f2f5
Added Hook to validate the success of a codecheck at publication #32
dxL1nus May 1, 2026
ef34f78
Added feature to block publication, when CODECHECK status is failed #32
dxL1nus May 3, 2026
d8595e5
Added schema for codecheck_submission_status table #119
dxL1nus May 5, 2026
a305325
Basic funtionaility for setting fr publication blocking #121
dxL1nus May 5, 2026
08e6cec
Continued work on the select statuses setting #121
dxL1nus May 8, 2026
6f4f594
Status should no be retrievable from the DB #61, #119
dxL1nus May 11, 2026
1c7f83b
Metadata Form now has Status form #119, #61
dxL1nus May 12, 2026
19b58ea
119, #61 Status can now be changed, Status History can be viewed
dxL1nus May 12, 2026
fc9bb87
Status History: current Status on top, rest scrollable #61
dxL1nus May 18, 2026
8afc703
Automatic status creation is now initially working #61
dxL1nus May 18, 2026
f5c7ecf
Codecheck Status From is now automatically updated after first form s…
dxL1nus May 20, 2026
66c4d01
Some small UI Updates #61
dxL1nus May 21, 2026
8d37886
#61 Change Button onyl shown when User is the Journal Manager
dxL1nus May 21, 2026
f53de0a
#61 UserAccessRights now checked in the frontend when updating status…
dxL1nus May 22, 2026
7bc8caf
Fixed bug, that status couldn't be updated #61
dxL1nus Jun 22, 2026
5b2c7d0
Rebase codecheck status to main #61, #33
dxL1nus Jun 22, 2026
d982981
The feature to block the publiscation, in case of invalid codecheck s…
dxL1nus Jun 23, 2026
81dcf87
Removed build.iife.js from commit
dxL1nus Jun 23, 2026
8f62509
Removed unecessary inputs in API Handler #137
dxL1nus Jun 24, 2026
23d1cd4
Fixed Cypress Component tests after rebase #137
dxL1nus Jun 24, 2026
cfdfc43
Update locale strings for CODECHECK settings
nuest Jun 24, 2026
1cb32b3
Removed testing artifact in CodecheckPlugin.php #137
dxL1nus Jun 25, 2026
dc6b419
Merge branch 'feature/codecheck-status' of github.com:dxL1nus/ojs-cod…
dxL1nus Jun 25, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ node_modules/

# npm release build
public/
public/*

# test results
tests/.phpunit.result.cache
Expand Down
63 changes: 59 additions & 4 deletions CodecheckPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@
use PKP\components\forms\FieldOptions;
use APP\facades\Repo;
use APP\plugins\generic\codecheck\api\v1\CodecheckApiHandler;
use APP\plugins\generic\codecheck\api\v1\CurlApiClient;
use PKP\core\JSONMessage;
use APP\plugins\generic\codecheck\classes\Constants;
use APP\plugins\generic\codecheck\classes\Workflow\CodecheckStatusHandler;
use APP\plugins\generic\codecheck\controllers\page\CodecheckPageHandler;
use APP\plugins\generic\codecheck\classes\CodecheckRoles\CodecheckRoleArray;
use APP\plugins\generic\codecheck\classes\CodecheckRoles\CodecheckRoleManager;
use APP\core\Request;
use APP\plugins\generic\codecheck\classes\Workflow\CodecheckMetadataHandler;
use PKP\core\Request;
use \Github\Client;

class CodecheckPlugin extends GenericPlugin
{
Expand Down Expand Up @@ -71,10 +75,60 @@ public function register($category, $path, $mainContextId = null): bool
Hook::add('Template::SubmissionWizard::Section::Review', function($hookName, $params) use ($codecheckWizard) {
return $codecheckWizard->addToSubmissionWizardReviewTemplate($hookName, $params);
});

// Test if we can hook into the publication to block it if codecheck failed
Hook::add('Publication::validatePublish', $this->validateCodecheckStatus(...));

// Add Localizations to Codecheck Status Preview
Hook::add('TemplateManager::display', $this->addCodecheckStatusLocalizations(...));
}

return $success;
}

public function validateCodecheckStatus(string $hookName, array $args): bool
{
$errors = &$args[0];
$publication = $args[1]; // sometimes passed by reference depending on version
$request = Application::get()->getRequest();
$context = $request->getContext();
$codecheckMetadataHandler = new CodecheckMetadataHandler($request, new Client(), new CurlApiClient());
$codecheckStatus = CodecheckStatusHandler::getCurrentStatusData($codecheckMetadataHandler->getSubmissionId());

CodecheckLogger::debug("Validating CODECHECK before publication!");

$codecheckStatusKeysSelected = $this->getSetting($context->getId(), Constants::CODECHECK_STATUS_KEYS_SELECTED);

if (empty($codecheckStatus)) {
$errors[] = __('plugins.generic.codecheck.status.validation.failed.noStatusSet');
return false;
}

if (!in_array($codecheckStatus->status, $codecheckStatusKeysSelected)) {
$errors[] = __('plugins.generic.codecheck.status.validation.failed', [
'codecheckStatus' => __($codecheckStatus->status)
]);
return false;
}

return true;
}

public function addCodecheckStatusLocalizations($hookName, $args) {
$templateMgr = $args[0];
$templateMgr->addJavaScript(
'codecheck-locale-status',
'pkp.localeKeys = pkp.localeKeys || {};' .
'Object.assign(pkp.localeKeys, ' . json_encode(
array_combine(
Constants::CODECHECK_STATUSES,
array_map(fn($status) => __($status), Constants::CODECHECK_STATUSES)
)
) . ');',
['inline' => true, 'contexts' => ['backend']]
);
return false;
}

/**
* Setup the `CodecheckApiHandler`
Expand Down Expand Up @@ -413,9 +467,10 @@ public function setEnabled($enabled, $contextId = null)
$result = parent::setEnabled($enabled, $contextId);

if ($enabled) {
$migration = new CodecheckSchemaMigration();
$migration->up();
$migration->issueLabelsUp();
$this->migration = new CodecheckSchemaMigration();
$this->migration->up();
$this->migration->issueLabelsUp();
$this->migration->codecheckStatusUp();
}

return $result;
Expand Down
169 changes: 162 additions & 7 deletions api/v1/CodecheckApiHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

use APP\plugins\generic\codecheck\api\v1\JsonResponse;
use APP\core\Request;
use APP\plugins\generic\codecheck\classes\Exceptions\ApiCreateException;
use APP\plugins\generic\codecheck\classes\Exceptions\ApiFetchException;
use APP\plugins\generic\codecheck\classes\Exceptions\NoMatchingIssuesFoundException;
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CodecheckGithubRegisterApiClient;
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CertificateIdentifierList;
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CertificateIdentifier;
Expand All @@ -16,17 +13,15 @@
use APP\plugins\generic\codecheck\classes\Log\CodecheckLogger;
use APP\plugins\generic\codecheck\classes\Constants;
use APP\plugins\generic\codecheck\CodecheckPlugin;

use APP\facades\Repo;
use \Github\Client;
use APP\plugins\generic\codecheck\classes\CodecheckRoles\CodecheckRoleManager;
use APP\plugins\generic\codecheck\classes\Exceptions\RoleExceptions\RoleNotFoundException;
use APP\plugins\generic\codecheck\classes\Exceptions\CurlExceptions\CurlInitException;
use APP\plugins\generic\codecheck\classes\Exceptions\CurlExceptions\CurlReadException;
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CodecheckIssueLabels;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use APP\plugins\generic\codecheck\classes\Workflow\CodecheckStatusHandler;
use Illuminate\Support\Facades\DB;

class CodecheckApiHandler
{
Expand Down Expand Up @@ -85,6 +80,16 @@ public function __construct(CodecheckPlugin $plugin, Request $request, Codecheck
'handler' => [$this, 'getGithubRegisterRepositoryUrl'],
'roles' => $roles->readMetadata(),
],
[
'route' => 'status',
'handler' => [$this, 'getCurrentStatus'],
'roles' => $roles->readMetadata(),
],
[
'route' => 'status/history',
'handler' => [$this, 'getStatusHistory'],
'roles' => $roles->readMetadata(),
],
],
'POST' => [
[
Expand Down Expand Up @@ -117,6 +122,16 @@ public function __construct(CodecheckPlugin $plugin, Request $request, Codecheck
'handler' => [$this, 'validateYamlStructure'],
'roles' => $roles->readMetadata(),
],
[
'route' => 'status/update',
'handler' => [$this, 'updateStatus'],
'roles' => $roles->editMetadata(),
],
[
'route' => 'users/roles/validation',
'handler' => [$this, 'validateUserAccessRightsToStatus'],
'roles' => $roles->readMetadata(),
],
],
];

Expand Down Expand Up @@ -259,6 +274,9 @@ private function getCodecheckIssueLabels(): void
$githubCustomLabels = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_GITHUB_CUSTOM_LABELS);
$codecheckIssueLabels->addLabelArray($githubCustomLabels);

$codecheckStatuses = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_STATUS_KEYS_SELECTED);
error_log(print_r($codecheckStatuses, true));

// Serve the getCodecheckIssueLabels API route
JsonResponse::staticResponse([
'success' => true,
Expand Down Expand Up @@ -929,4 +947,141 @@ public function validateYamlStructure(): void
'success' => true,
], 200);
}

public function getCurrentStatus(): void
{
$submissionId = (int) $this->codecheckMetadataHandler->getSubmissionId();

$statusRecord = CodecheckStatusHandler::getCurrentStatusData($submissionId);

if($statusRecord == null) {
JsonResponse::staticResponse([
'success' => false,
'error' => "There doesn't exist any Status in the OJS Databse for this submission Id yet.",
'statusRecord' => null,
'allStatuses' => Constants::CODECHECK_STATUSES,
], 500);
}

JsonResponse::staticResponse([
'success' => true,
'statusRecord' => $statusRecord,
'allStatuses' => Constants::CODECHECK_STATUSES,
], 200);
}

public function getStatusHistory(): void
{
$submissionId = (int) $this->codecheckMetadataHandler->getSubmissionId();

$statusHistory = CodecheckStatusHandler::getStatusDataHistory($submissionId);

if($statusHistory == null) {
JsonResponse::staticResponse([
'success' => false,
'statusHistory' => $statusHistory,
], 400);
}

JsonResponse::staticResponse([
'success' => true,
'statusHistory' => $statusHistory,
], 200);
}

public function updateStatus(): void
{
$submissionId = (int) $this->codecheckMetadataHandler->getSubmissionId();

$postParams = json_decode(file_get_contents('php://input'), true);
$status = $postParams["status"];
$userId = $postParams["userId"];

if(!is_string($status) || !is_int($userId)) {
JsonResponse::staticResponse([
'success' => false,
'statusRecord' => [
'status' => $status,
'userId' => $userId
],
'allStatuses' => Constants::CODECHECK_STATUSES,
'error' => 'Bad Request: Please provide a Status form of string and a User ID in the form of int.'
], 400);
}

if($userId == -1) {
$submissionMetadata = $this->codecheckMetadataHandler->getMetadata($this->request, $submissionId);
if(array_key_exists("error",$submissionMetadata)) {
JsonResponse::staticResponse([
'success' => false,
'error' => $submissionMetadata["error"],
'allStatuses' => Constants::CODECHECK_STATUSES,
], 400);
}
$statusUpdate = CodecheckStatusHandler::automaticStatusUpdate($submissionMetadata);

if($statusUpdate == null) {
JsonResponse::staticResponse([
'success' => false,
'statusRecord' => $statusUpdate,
'allStatuses' => Constants::CODECHECK_STATUSES,
'error' => "Status doesn't need to be automatically updated."
], 200);
} else {
JsonResponse::staticResponse([
'success' => true,
'statusRecord' => $statusUpdate,
'allStatuses' => Constants::CODECHECK_STATUSES,
], 200);
}
}

$statusUpdate = CodecheckStatusHandler::updateStatus($submissionId, $status, $userId);

if($statusUpdate == false) {
JsonResponse::staticResponse([
'success' => true,
'statusRecord' => [
'status' => $status,
'userId' => $userId
],
'allStatuses' => Constants::CODECHECK_STATUSES,
'error' => "Inserting into the CODECHECK Status Database went wrong."
], 500);
}

JsonResponse::staticResponse([
'success' => true,
'statusRecord' => $statusUpdate,
'allStatuses' => Constants::CODECHECK_STATUSES,
], 200);
}

public function validateUserAccessRightsToStatus(): void
{
$postParams = json_decode(file_get_contents('php://input'), true);
$user = $postParams["user"];

if(!is_array($user["roles"])) {
JsonResponse::staticResponse([
'success' => false,
'error' => 'Bad Request: Please provide the current User in your request.'
], 400);
}

$userRoles = $user["roles"];
$allowedToAccess = false;

foreach ($userRoles as $userRole) {
if($userRole == 16) {
$allowedToAccess = true;
break;
}
}

JsonResponse::staticResponse([
'success' => true,
'userAllowedToAccess' => $allowedToAccess,
], 200);
}
}
29 changes: 29 additions & 0 deletions classes/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ class Constants
* Basic plugin setting
*/
public const SETTING_ENABLE_CODECHECK = 'enableCodecheck';

/**
* The possible Codecheck Statuses
*/
public const CODECHECK_STATUS_NEEDS_CODECHECKER = 'plugins.generic.codecheck.status.needsCodechecker';
public const CODECHECK_STATUS_ASSIGNED_CODECHECKER = 'plugins.generic.codecheck.status.assignedCodechecker';
public const CODECHECK_STATUS_STALLED_AUTHOR = 'plugins.generic.codecheck.status.stalled.author';
public const CODECHECK_STATUS_STALLED_CODECHECKER = 'plugins.generic.codecheck.status.stalled.codechecker';
public const CODECHECK_STATUS_COMPLETED_UNSUCCESSFUL = 'plugins.generic.codecheck.status.completed.unsuccessful';
public const CODECHECK_STATUS_COMPLETED_PARTIAL_REPRODUCTION = 'plugins.generic.codecheck.status.completed.partialReproduction';
public const CODECHECK_STATUS_COMPLETED_FULL_REPRODUCTION = 'plugins.generic.codecheck.status.completed.fullReproduction';
public const CODECHECK_STATUS_PUBLISHED_PARTIAL_REPRODUCTION = 'plugins.generic.codecheck.status.publishedCertificate.partialReproduction';
public const CODECHECK_STATUS_PUBLISHED_FULL_REPRODUCTION = 'plugins.generic.codecheck.status.publishedCertificate.fullReproduction';

public const CODECHECK_STATUSES = [
Constants::CODECHECK_STATUS_NEEDS_CODECHECKER,
Constants::CODECHECK_STATUS_ASSIGNED_CODECHECKER,
Constants::CODECHECK_STATUS_STALLED_AUTHOR,
Constants::CODECHECK_STATUS_STALLED_CODECHECKER,
Constants::CODECHECK_STATUS_COMPLETED_UNSUCCESSFUL,
Constants::CODECHECK_STATUS_COMPLETED_PARTIAL_REPRODUCTION,
Constants::CODECHECK_STATUS_COMPLETED_FULL_REPRODUCTION,
Constants::CODECHECK_STATUS_PUBLISHED_PARTIAL_REPRODUCTION,
Constants::CODECHECK_STATUS_PUBLISHED_FULL_REPRODUCTION,
];

/**
* Plugin settings keys - NEW ADDITIONS
Expand All @@ -40,4 +65,8 @@ class Constants
public const CODECHECK_GITHUB_REGISTER_ISSUE_UPDATE_FIELDS = 'codecheckGithubUpdateFields';
public const CODECHECK_GITHUB_REGISTER_ISSUE_UPDATE_TITLE = 'updateTitle';
public const CODECHECK_GITHUB_REGISTER_ISSUE_UPDATE_BODY = 'updateBody';
# Codecheck Status
public const CODECHECK_STATUS = 'codecheckStatus';
public const CODECHECK_STATUSES_SELECTED = 'codecheckStatusesSelected';
public const CODECHECK_STATUS_KEYS_SELECTED = 'codecheckStatusKeysSelected';
}
Loading
Loading