Skip to content
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
123 changes: 116 additions & 7 deletions CodecheckPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
use APP\facades\Repo;
use APP\plugins\generic\codecheck\api\v1\CodecheckApiHandler;
use PKP\core\JSONMessage;
use APP\plugins\generic\codecheck\classes\Constants;
use APP\plugins\generic\codecheck\controllers\page\CodecheckPageHandler;

class CodecheckPlugin extends GenericPlugin
{
private CodecheckSchemaMigration $migration;

public function register($category, $path, $mainContextId = null): bool
{
error_log('[CodecheckPlugin] register() called, path=' . $path);
Expand All @@ -40,6 +44,8 @@ public function register($category, $path, $mainContextId = null): bool
Hook::add('Submission::validate', $this->saveWizardFieldsFromRequest(...));
// Add hook for Ajax API calls
Hook::add('Dispatcher::dispatch', [$this, 'setupAPIHandler']);
// Add hook for the custom CODECHECK Pages
Hook::add('LoadHandler', $this->setCodecheckPageHandler(...));
// Add hook for the Template Manager
Hook::add('TemplateManager::display', $this->callbackTemplateManagerDisplay(...));

Expand All @@ -66,6 +72,14 @@ public function register($category, $path, $mainContextId = null): bool
return $success;
}

/**
* Setup the `CodecheckApiHandler`
*
* @param string $hookname The name of the hook
* @param array $args The arguments passed by the hook
*
* @return void
*/
public function setupAPIHandler(string $hookName, array $args): void
{
$request = $args[0];
Expand All @@ -77,7 +91,7 @@ public function setupAPIHandler(string $hookName, array $args): void

if (str_contains($request->getRequestPath(), 'api/v1/codecheck')) {
error_log("[CODECHECK Plugin] Instanciating the CODECHECK APIHandler");
$apiHandler = new CodecheckApiHandler($request);
$apiHandler = new CodecheckApiHandler($this, $request);
error_log("[CODECHECK Plugin] API request: " . $request->getRequestPath() . "\n");
}

Expand All @@ -89,6 +103,46 @@ public function setupAPIHandler(string $hookName, array $args): void
exit;
}

/**
* Declare the handler function to process the actual page PATH
*
* @param string $hookName The name of the invoked hook
* @param array $args Hook parameters
*
* @return bool Hook handling status
*/
public function setCodecheckPageHandler($hookName, $args)
{
$request = Application::get()->getRequest();
$templateMgr = TemplateManager::getManager($request);

$page = &$args[0];
$op = &$args[1];
$handler = &$args[3];


// Construct a path to look for
$path = $page;
if ($op !== 'index') {
$path .= "/{$op}";
}
if ($ops = $request->getRequestedArgs()) {
$path .= '/' . implode('/', $ops);
}

// Check if this is a request for a static page or preview.
if ($page = 'codecheck' && $op == 'info') {
// Trick the handler into dealing with it normally
$page = 'pages';
$op = 'view';

// It is -- attach the static pages handler.
$handler = new CodecheckPageHandler($this);
return true;
}
return false;
}

private function addAssets(): void
{
$request = Application::get()->getRequest();
Expand Down Expand Up @@ -145,6 +199,17 @@ public function callbackTemplateManagerDisplay($hookName, $args): bool
return false;
}

public function getUrlPageRoute(string $page): string
{
$request = Application::get()->getRequest();
return $request->getDispatcher()->url(
$request,
ROUTE_PAGE,
null,
$page
);
}

public function addOptInToSchema(string $hookName, array $args): bool
{
$schema = $args[0];
Expand All @@ -167,18 +232,37 @@ public function addOptInToSchema(string $hookName, array $args): bool
public function addOptInCheckbox(string $hookName, \PKP\components\forms\FormComponent $form): bool
{
if ($form->id === 'submitStart' || $form->id === 'submissionStart' || str_contains($form->id, 'start')) {
$request = Application::get()->getRequest();
$context = $request->getContext();
$codecheckMode = $this->getSetting($context->getId(), Constants::CODECHECK_MODE);
error_log("[CODECHECK Settings] Mode: " . $codecheckMode);
$checkboxValue = false;
$checkboxDisabled = false;
$codecheckDescription = __('plugins.generic.codecheck.optIn.description', [
'codecheckLink' => "<a href='{$this->getUrlPageRoute("codecheck")}/info' target='_blank'>CODECHECK</a>"
]);

if($codecheckMode == 'opt-out') {
$checkboxValue = true;
} elseif ($codecheckMode == 'mandatory') {
$checkboxValue = true;
$checkboxDisabled = true;
$codecheckDescription = __('plugins.generic.codecheck.mandatory.description', [
'codecheckLink' => "<a href='{$this->getUrlPageRoute("codecheck")}/info' target='_blank'>CODECHECK</a>"
]);
}

$form->addField(new FieldOptions('codecheckOptIn', [
'label' => __('plugins.generic.codecheck.displayName'),
'type' => 'checkbox',
'options' => [
[
'value' => 1,
'label' => __('plugins.generic.codecheck.optIn.description', [
'codecheckLink' => '<a href="https://codecheck.org.uk/" target="_blank">CODECHECK</a>'
])
'label' => $codecheckDescription,
'disabled' => $checkboxDisabled,
]
],
'value' => false,
'value' => $checkboxValue,
'groupId' => 'default'
]));

Expand Down Expand Up @@ -233,16 +317,34 @@ public function saveWizardFieldsFromRequest(string $hookName, array $params): bo
return false;
}

/**
* Provide a name for this plugin
*
* The name will appear in the Plugin Gallery where editors can
* install, enable and disable plugins.
*/
public function getDisplayName(): string
{
return __('plugins.generic.codecheck.displayName');
}

/**
* Provide a description for this plugin
*
* The description will appear in the Plugin Gallery where editors can
* install, enable and disable plugins.
*/
public function getDescription(): string
{
return __('plugins.generic.codecheck.description');
}

/**
* Add a settings action to the plugin's entry in the CODECHECK plugins list.
*
* @param Request $request
* @param array $actionArgs
*/
public function getActions($request, $actionArgs): array
{
$actions = new Actions($this);
Expand All @@ -267,12 +369,19 @@ public function setEnabled($enabled, $contextId = null)
$result = parent::setEnabled($enabled, $contextId);

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

return $result;
}

public function resetSchema(): void
{
$this->migration = new CodecheckSchemaMigration();
$this->migration->down();
$this->migration->up();
}
}

if (!PKP_STRICT_MODE) {
Expand Down
38 changes: 33 additions & 5 deletions api/v1/CodecheckApiHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CertificateIdentifier;
use APP\plugins\generic\codecheck\classes\CodecheckRegister\CodecheckVenue;
use APP\plugins\generic\codecheck\classes\Workflow\CodecheckMetadataHandler;
use APP\plugins\generic\codecheck\classes\Constants;
use APP\plugins\generic\codecheck\CodecheckPlugin;

use APP\facades\Repo;
use \Github\Client;
Expand All @@ -29,6 +31,7 @@ class CodecheckApiHandler
private array $roles;
private array $endpoints;
private string $route;
private CodecheckPlugin $plugin;
private Request $request;
private CodecheckMetadataHandler $codecheckMetadataHandler;

Expand All @@ -38,8 +41,10 @@ class CodecheckApiHandler
* @param Request $request API Request
* @return void
*/
public function __construct(Request $request)
public function __construct(CodecheckPlugin $plugin, Request $request)
{
$this->plugin = $plugin;

$this->response = new JsonResponse([
'success' => false,
'error' => 'No API Response was created.',
Expand Down Expand Up @@ -203,11 +208,16 @@ private function getVenueData(): void
return;
}

// get the github custom labels specified in the plugin settings form
$context = $this->request->getContext();
$githubCustomLabels = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_GITHUB_CUSTOM_LABELS);

// Serve the getVenueData API route
JsonResponse::staticResponse([
'success' => true,
'venueTypes' => $codecheckVenueTypes->get()->toArray(),
'venueNames' => $codecheckVenueNames->get()->toArray(),
'customLabels' => $githubCustomLabels,
], 200);
}

Expand All @@ -221,18 +231,35 @@ public function reserveIdentifier(): void
$postParams = json_decode(file_get_contents('php://input'), true);
$venueType = $postParams["venueType"];
$venueName = $postParams["venueName"];
$customLabels = $postParams["customLabels"];
$authorString = $postParams["authorString"];

// get the github Register Repository specified in the plugin settings form
$context = $this->request->getContext();
$githubPersonalAccessToken = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_GITHUB_PERSONAL_ACCESS_TOKEN);
$githubRegisterOrganization = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_GITHUB_REGISTER_ORGANIZATION);
$githubRegisterRepository = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_GITHUB_REGISTER_REPOSITORY);
$isAuthorStringEnabled = $this->plugin->getSetting($context->getId(), Constants::CODECHECK_AUTHOR_ANONYMITY);

error_log("[Codecheck Api Handler] GitHub Register Repository specified in the Settings form: " . $githubRegisterRepository);

// if Authors should be Anonymous/ if no Author string was given, set it to null
if(!$isAuthorStringEnabled || !is_string($authorString)) {
$authorString = null;
}

// check if they are of type string (If not return success false over the API)
if(is_string($venueType) && is_string($venueName) && is_string($authorString)) {
if(is_string($venueType) && is_string($venueName) && is_array($customLabels)) {
// CODECHECK GitHub Issue Register API parser
$codecheckGithubRegisterApiClient = new CodecheckGithubRegisterApiClient(
'testing-dev-register', // Name of the GitHub Repository for the Register
$githubPersonalAccessToken, // The GitHub PAT (classic) needed to access the Register Repository
$githubRegisterOrganization, // The organization owning the GitHub Register Repository
$githubRegisterRepository, // Name of the GitHub Repository for the Register
$this->codecheckMetadataHandler->getSubmissionId(), // Submission ID
$this->request->getContext(), // The Journal Object of the Submission
$context, // The Journal Object of the Submission
);

error_log(print_r($this->request->getContext(), true));
//error_log(print_r($this->request->getContext(), true));

// CODECHECK Register with list of all identifiers in range
try {
Expand Down Expand Up @@ -266,6 +293,7 @@ public function reserveIdentifier(): void
$new_identifier,
$codecheckVenue->getVenueType(),
$codecheckVenue->getVenueName(),
$customLabels,
$authorString,
);
} catch (ApiCreateException $e) {
Expand Down
30 changes: 18 additions & 12 deletions classes/CodecheckRegister/CodecheckGithubRegisterApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,27 @@ class CodecheckGithubRegisterApiClient
private $issues = [];
private UniqueArray $labels;
private $client;
private string $githubPAT;
private string $githubRegisterOrganization;
private string $githubRegisterRepository;
private string $submissionID;
private string $journalName;

/**
* Initializes a new CODECHECK GitHub Register Api Parser (initialize the GitHub Client and a new unique Array)
*
* @param string $githubPersonalAccessToken The required GitHub `(PAT)` (classic), to access the GitHub Register Repository
* @param string $githubRegisterOrganization The Organization owning the GitHub Register Repository
* @param string $githubRegisterRepository The Repository of the GitHub Register
* @param string $submissionID The ID of the Submission realted to the GitHub Register Issue
* @param mixed $journal The name of the Journal the Submission is published in
*/
function __construct(string $githubRegisterRepository, string $submissionID, mixed $journal, ?Client $client = null)
function __construct(string $githubPersonalAccessToken, string $githubRegisterOrganization, string $githubRegisterRepository, string $submissionID, mixed $journal, ?Client $client = null)
{
$this->client = $client ?? new Client();
$this->labels = new UniqueArray();
$this->githubPAT = $githubPersonalAccessToken;
$this->githubRegisterOrganization = $githubRegisterOrganization;
$this->githubRegisterRepository = $githubRegisterRepository;
$this->submissionID = $submissionID;
$this->journalName = $journal?->getLocalizedName() ?? 'Unknown Journal';
Expand Down Expand Up @@ -87,7 +93,7 @@ public function fetchIssues(): void

do {
try {
$allissues = $this->client->api('issue')->all('codecheckers', $this->githubRegisterRepository, [
$allissues = $this->client->api('issue')->all($this->githubRegisterOrganization, $this->githubRegisterRepository, [
'state' => 'all', // 'open', 'closed', or 'all'
'labels' => 'id assigned', // select only issues where there is an id assigned
'sort' => 'updated',
Expand Down Expand Up @@ -121,7 +127,7 @@ public function fetchIssues(): void
public function fetchLabels(): void
{
try {
$fetchedLabels = $this->client->api('issue')->labels()->all('codecheckers', $this->githubRegisterRepository);
$fetchedLabels = $this->client->api('issue')->labels()->all($this->githubRegisterOrganization, $this->githubRegisterRepository);
} catch (\Throwable $e) {
throw new ApiFetchException("Failed fetching the GitHub Issue Labels for the Venue Names\n" . $e->getMessage());
}
Expand All @@ -144,13 +150,11 @@ public function addIssue(
CertificateIdentifier $certificateIdentifier,
string $codecheckVenueType,
string $codecheckVenueName,
string $authorString,
array $customLabels,
?string $authorString,
): string {
$token = $_ENV['CODECHECK_REGISTER_GITHUB_TOKEN'];
$this->client->authenticate($this->githubPAT, null, Client::AUTH_ACCESS_TOKEN);

$this->client->authenticate($token, null, Client::AUTH_ACCESS_TOKEN);

$repositoryOwner = 'codecheckers';
$authorString = empty($authorString) ? 'New CODECHECK' : $authorString;
$issueTitle = $authorString . ' | ' . $certificateIdentifier->toStr();
$issueBody = 'Journal: `' . $this->journalName . '`<br />' . 'Submission ID: `' . $this->submissionID . '`';
Expand All @@ -159,11 +163,13 @@ public function addIssue(
$labelStrings[] = $codecheckVenueType;
$labelStrings[] = $codecheckVenueName;

$labelStrings = array_merge($labelStrings, $customLabels);

//error_log(print_r($labelStrings, true));
error_log($this->githubRegisterOrganization);

try {
$issue = $this->client->api('issue')->create(
$repositoryOwner,
$this->githubRegisterRepository,
[
$issue = $this->client->api('issue')->create($this->githubRegisterOrganization, $this->githubRegisterRepository, [
'title' => $issueTitle,
'body' => $issueBody,
'labels' => $labelStrings
Expand Down
Loading
Loading