first commit
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/_dois/BackendDoiHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class BackendDoiHandler
|
||||
*
|
||||
* @ingroup api_v1_backend
|
||||
*
|
||||
* @brief Handle API requests for backend operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\_dois;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
use PKP\core\APIResponse;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\security\Role;
|
||||
use Slim\Http\Request as SlimRequest;
|
||||
|
||||
class BackendDoiHandler extends \PKP\API\v1\_dois\PKPBackendDoiHandler
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_handlerPath = '_dois';
|
||||
$this->_endpoints = array_merge_recursive($this->_endpoints, [
|
||||
'PUT' => [
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . "/issues/{issueId:\d+}",
|
||||
'handler' => [$this, 'editIssue'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . "/galleys/{galleyId:\d+}",
|
||||
'handler' => [$this, 'editGalley'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
]
|
||||
]
|
||||
]);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit galley to add DOI
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function editGalley(SlimRequest $slimRequest, APIResponse $response, array $args): \Slim\Http\Response
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$context = $request->getContext();
|
||||
|
||||
$galley = Repo::galley()->get((int)$args['galleyId']);
|
||||
if (!$galley) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
$publicationId = $galley->getData('publicationId');
|
||||
$publication = Repo::publication()->get((int)$publicationId);
|
||||
$submissionId = $publication->getData('submissionId');
|
||||
$submission = Repo::submission()->get((int) $submissionId);
|
||||
|
||||
if ($submission->getData('contextId') !== $context->getId()) {
|
||||
return $response->withStatus(403)->withJsonError('api.dois.403.editItemOutOfContext');
|
||||
}
|
||||
|
||||
$params = $this->convertStringsToSchema(\PKP\services\PKPSchemaService::SCHEMA_GALLEY, $slimRequest->getParsedBody());
|
||||
|
||||
$doi = Repo::doi()->get((int) $params['doiId']);
|
||||
if (!$doi) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.doiNotFound');
|
||||
}
|
||||
|
||||
Repo::galley()->edit($galley, ['doiId' => $doi->getId()]);
|
||||
|
||||
/** @var \PKP\submission\GenreDAO $genreDao */
|
||||
$genreDao = DAORegistry::getDAO('GenreDAO');
|
||||
$genres = $genreDao->getByContextId($context->getId())->toArray();
|
||||
// Re-fetch submission and publication to reflect changes in galley
|
||||
$submission = Repo::submission()->get((int) $submissionId);
|
||||
$publication = Repo::publication()->get((int) $publicationId);
|
||||
$galley = Repo::galley()->get($galley->getId());
|
||||
|
||||
$galleyProps = Repo::galley()->getSchemaMap($submission, $publication, $genres)->map($galley);
|
||||
|
||||
return $response->withJson($galleyProps, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit issue to add DOI
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function editIssue(SlimRequest $slimRequest, APIResponse $response, array $args): \Slim\Http\Response
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$context = $request->getContext();
|
||||
|
||||
$issue = Repo::issue()->get($args['issueId']);
|
||||
if (!$issue) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
if ($issue->getData('journalId') !== $context->getId()) {
|
||||
return $response->withStatus(403)->withJsonError('api.dois.403.editItemOutOfContext');
|
||||
}
|
||||
|
||||
$params = $this->convertStringsToSchema(\PKP\services\PKPSchemaService::SCHEMA_ISSUE, $slimRequest->getParsedBody());
|
||||
|
||||
$doi = Repo::doi()->get((int) $params['doiId']);
|
||||
if (!$doi) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.doiNotFound');
|
||||
}
|
||||
|
||||
Repo::issue()->edit($issue, ['doiId' => $doi->getId()]);
|
||||
$issue = Repo::issue()->get($issue->getId());
|
||||
|
||||
return $response->withJson(Repo::issue()->getSchemaMap()->map(
|
||||
$issue,
|
||||
$context,
|
||||
$this->getUserGroups($context->getId()),
|
||||
$this->getGenres($context->getId())
|
||||
), 200);
|
||||
}
|
||||
|
||||
protected function getUserGroups(int $contextId): LazyCollection
|
||||
{
|
||||
return Repo::userGroup()->getCollector()
|
||||
->filterByContextIds([$contextId])
|
||||
->getMany();
|
||||
}
|
||||
|
||||
protected function getGenres(int $contextId): array
|
||||
{
|
||||
/** @var \PKP\submission\GenreDAO $genreDao */
|
||||
$genreDao = DAORegistry::getDAO('GenreDAO');
|
||||
return $genreDao->getByContextId($contextId)->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_dois Backend DOI API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/_dois/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_dois
|
||||
*
|
||||
* @brief Handle API requests for backend DOI operations.
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\_dois\BackendDoiHandler();
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1__email User API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/_email/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1__email
|
||||
*
|
||||
* @brief Handle requests for user API functions.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\_email\PKPEmailHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_library Library files API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/library/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2022 Simon Fraser University
|
||||
* Copyright (c) 2003-2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_library
|
||||
*
|
||||
* @brief Handle API requests for the publisher and submission library files.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\_library\PKPLibraryHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @file api/v1/_payments/BackendPaymentsSettingsHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class BackendPaymentsSettingsHandler
|
||||
*
|
||||
* @ingroup api_v1_backend
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\_payments;
|
||||
|
||||
class BackendPaymentsSettingsHandler extends \PKP\API\v1\_payments\PKPBackendPaymentsSettingsHandler
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_backend Backend API requests for payments settings
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/_payments/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_backend
|
||||
*
|
||||
* @brief Handle requests for backend API.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\_payments\BackendPaymentsSettingsHandler();
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/_submissions/BackendSubmissionsHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class BackendSubmissionsHandler
|
||||
*
|
||||
* @ingroup api_v1_backend
|
||||
*
|
||||
* @brief Handle API requests for backend operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\_submissions;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\payment\ojs\OJSCompletedPaymentDAO;
|
||||
use APP\payment\ojs\OJSPaymentManager;
|
||||
use APP\submission\Collector;
|
||||
use PKP\core\APIResponse;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\security\authorization\SubmissionAccessPolicy;
|
||||
use PKP\security\Role;
|
||||
use PKP\stageAssignment\StageAssignmentDAO;
|
||||
use Slim\Http\Request;
|
||||
|
||||
class BackendSubmissionsHandler extends \PKP\API\v1\_submissions\PKPBackendSubmissionsHandler
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_endpoints = array_merge_recursive($this->_endpoints, [
|
||||
'PUT' => [
|
||||
[
|
||||
'pattern' => '/{contextPath}/api/{version}/_submissions/{submissionId:\d+}/payment',
|
||||
'handler' => [$this, 'payment'],
|
||||
'roles' => [
|
||||
Role::ROLE_ID_SUB_EDITOR,
|
||||
Role::ROLE_ID_MANAGER,
|
||||
Role::ROLE_ID_SITE_ADMIN,
|
||||
Role::ROLE_ID_ASSISTANT,
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc PKPHandler::authorize()
|
||||
*/
|
||||
public function authorize($request, &$args, $roleAssignments)
|
||||
{
|
||||
$routeName = $this->getSlimRequest()->getAttribute('route')->getName();
|
||||
|
||||
if ($routeName === 'payment') {
|
||||
$this->addPolicy(new SubmissionAccessPolicy($request, $args, $roleAssignments));
|
||||
}
|
||||
|
||||
return parent::authorize($request, $args, $roleAssignments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the status of submission payments.
|
||||
*
|
||||
* @param Request $slimRequest Slim request object
|
||||
* @param APIResponse $response object
|
||||
* @param array $args arguments
|
||||
*
|
||||
* @return APIResponse
|
||||
*/
|
||||
public function payment($slimRequest, $response, $args)
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$context = $request->getContext();
|
||||
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
|
||||
|
||||
if (!$submission || !$context || $context->getId() != $submission->getContextId()) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
$paymentManager = Application::getPaymentManager($context);
|
||||
$publicationFeeEnabled = $paymentManager->publicationEnabled();
|
||||
if (!$publicationFeeEnabled) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
$params = $slimRequest->getParsedBody();
|
||||
|
||||
if (empty($params['publicationFeeStatus'])) {
|
||||
return $response->withJson([
|
||||
'publicationFeeStatus' => [__('validator.required')],
|
||||
], 400);
|
||||
}
|
||||
|
||||
$completedPaymentDao = DAORegistry::getDAO('OJSCompletedPaymentDAO'); /** @var OJSCompletedPaymentDAO $completedPaymentDao */
|
||||
$publicationFeePayment = $completedPaymentDao->getByAssoc(null, OJSPaymentManager::PAYMENT_TYPE_PUBLICATION, $submission->getId());
|
||||
|
||||
switch ($params['publicationFeeStatus']) {
|
||||
case 'waived':
|
||||
// Check if a waiver already exists; if so, don't do anything.
|
||||
if ($publicationFeePayment && !$publicationFeePayment->getAmount()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If a fulfillment (nonzero amount) already exists, remove it.
|
||||
if ($publicationFeePayment) {
|
||||
$completedPaymentDao->deleteById($publicationFeePayment->getId());
|
||||
}
|
||||
|
||||
// Record a waived payment.
|
||||
$queuedPayment = $paymentManager->createQueuedPayment(
|
||||
$request,
|
||||
OJSPaymentManager::PAYMENT_TYPE_PUBLICATION,
|
||||
$request->getUser()->getId(),
|
||||
$submission->getId(),
|
||||
0,
|
||||
'' // Zero amount, no currency
|
||||
);
|
||||
$paymentManager->queuePayment($queuedPayment);
|
||||
$paymentManager->fulfillQueuedPayment($request, $queuedPayment, 'ManualPayment');
|
||||
break;
|
||||
case 'paid':
|
||||
// Check if a fulfilled payment already exists; if so, don't do anything.
|
||||
if ($publicationFeePayment && $publicationFeePayment->getAmount()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If a waiver (0 amount) already exists, remove it.
|
||||
if ($publicationFeePayment) {
|
||||
$completedPaymentDao->deleteById($publicationFeePayment->getId());
|
||||
}
|
||||
|
||||
// Record a fulfilled payment.
|
||||
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */
|
||||
$submitterAssignments = $stageAssignmentDao->getBySubmissionAndRoleIds($submission->getId(), [Role::ROLE_ID_AUTHOR]);
|
||||
$submitterAssignment = $submitterAssignments->next();
|
||||
$queuedPayment = $paymentManager->createQueuedPayment(
|
||||
$request,
|
||||
OJSPaymentManager::PAYMENT_TYPE_PUBLICATION,
|
||||
$submitterAssignment->getUserId(),
|
||||
$submission->getId(),
|
||||
$context->getSetting('publicationFee'),
|
||||
$context->getSetting('currency')
|
||||
);
|
||||
$paymentManager->queuePayment($queuedPayment);
|
||||
$paymentManager->fulfillQueuedPayment($request, $queuedPayment, 'Waiver');
|
||||
break;
|
||||
case 'unpaid':
|
||||
if ($publicationFeePayment) {
|
||||
$completedPaymentDao->deleteById($publicationFeePayment->getId());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return $response->withJson([
|
||||
'publicationFeeStatus' => [__('validator.required')],
|
||||
], 400);
|
||||
}
|
||||
|
||||
return $response->withJson(true);
|
||||
}
|
||||
|
||||
/** @copydoc PKPSubmissionHandler::getSubmissionCollector() */
|
||||
protected function getSubmissionCollector(array $queryParams): Collector
|
||||
{
|
||||
$collector = parent::getSubmissionCollector($queryParams);
|
||||
|
||||
if (isset($queryParams['issueIds'])) {
|
||||
$collector->filterByIssueIds(
|
||||
array_map('intval', $this->paramToArray($queryParams['issueIds']))
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($queryParams['sectionIds'])) {
|
||||
$collector->filterBySectionIds(
|
||||
array_map('intval', $this->paramToArray($queryParams['sectionIds']))
|
||||
);
|
||||
}
|
||||
|
||||
return $collector;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_backend Backend API requests for submissions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/_submissions/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_backend
|
||||
*
|
||||
* @brief Handle requests for backend API.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\_submissions\BackendSubmissionsHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_uploadPublicFile Email templates API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/uploadPublicFile/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_uploadPublicFile
|
||||
*
|
||||
* @brief Handle API requests for uploadPublicFile.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\_uploadPublicFile\PKPUploadPublicFileHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_announcements Email templates API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/announcements/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_announcements
|
||||
*
|
||||
* @brief Handle API requests for announcements.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\announcements\PKPAnnouncementHandler();
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* @file api/v1/contexts/ContextHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class ContextHandler
|
||||
*
|
||||
* @ingroup api_v1_contexts
|
||||
*
|
||||
* @brief Handle API requests for contexts (journals/presses).
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\contexts;
|
||||
|
||||
class ContextHandler extends \PKP\API\v1\contexts\PKPContextHandler
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_contexts Context API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/contexts/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_contexts
|
||||
*
|
||||
* @brief Handle API requests for contexts (journals/presses).
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\contexts\ContextHandler();
|
||||
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/dois/DoiHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class DoiHandler
|
||||
*
|
||||
* @ingroup api_v1_dois
|
||||
*
|
||||
* @brief Handle API requests for DOI operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\dois;
|
||||
|
||||
use APP\facades\Repo;
|
||||
use APP\issue\Issue;
|
||||
use APP\jobs\doi\DepositIssue;
|
||||
use PKP\context\Context;
|
||||
use PKP\core\APIResponse;
|
||||
use PKP\doi\Doi;
|
||||
use PKP\doi\exceptions\DoiException;
|
||||
use PKP\security\Role;
|
||||
use Slim\Http\Request as SlimRequest;
|
||||
use Slim\Http\Response;
|
||||
|
||||
class DoiHandler extends \PKP\API\v1\dois\PKPDoiHandler
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_handlerPath = 'dois';
|
||||
$this->_endpoints = array_merge_recursive($this->_endpoints, [
|
||||
'POST' => [
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/assignDois',
|
||||
'handler' => [$this, 'assignIssueDois'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN]
|
||||
]
|
||||
],
|
||||
'PUT' => [
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/export',
|
||||
'handler' => [$this, 'exportIssues'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/deposit',
|
||||
'handler' => [$this, 'depositIssues'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/markRegistered',
|
||||
'handler' => [$this, 'markIssuesRegistered'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/markUnregistered',
|
||||
'handler' => [$this, 'markIssuesUnregistered'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/issues/markStale',
|
||||
'handler' => [$this, 'markIssuesStale'],
|
||||
'roles' => [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
|
||||
],
|
||||
],
|
||||
]);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Export XML for configured DOI registration agency
|
||||
*/
|
||||
public function exportIssues(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve and validate issues
|
||||
$requestIds = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($requestIds)) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.noPubObjectIncluded');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$validIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByPublished(true)
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
$invalidIds = array_diff($requestIds, $validIds);
|
||||
if (count($invalidIds)) {
|
||||
return $response->withStatus(400)->withJsonError('api.dois.400.invalidPubObjectIncluded');
|
||||
}
|
||||
|
||||
/** @var Issue[] $issues */
|
||||
$issues = [];
|
||||
foreach ($requestIds as $id) {
|
||||
$issues[] = Repo::issue()->get($id);
|
||||
}
|
||||
|
||||
if (empty($issues[0])) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.doiNotFound');
|
||||
}
|
||||
|
||||
$agency = $context->getConfiguredDoiAgency();
|
||||
if ($agency === null) {
|
||||
return $response->withStatus(400)->withJsonError('api.dois.400.noRegistrationAgencyConfigured');
|
||||
}
|
||||
|
||||
// Invoke IDoiRegistrationAgency::exportIssues
|
||||
$responseData = $agency->exportIssues($issues, $context);
|
||||
if (!empty($responseData['xmlErrors'])) {
|
||||
return $response->withStatus(400)->withJsonError('api.dois.400.xmlExportFailed');
|
||||
}
|
||||
return $response->withJson(['temporaryFileId' => $responseData['temporaryFileId']], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposit XML for configured DOI registration agency
|
||||
*/
|
||||
public function depositIssues(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve and validate issues
|
||||
$requestIds = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($requestIds)) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.noPubObjectIncluded');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$validIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByPublished(true)
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
$invalidIds = array_diff($requestIds, $validIds);
|
||||
if (count($invalidIds)) {
|
||||
return $response->withStatus(400)->withJsonError('api.dois.400.invalidPubObjectIncluded');
|
||||
}
|
||||
|
||||
$agency = $context->getConfiguredDoiAgency();
|
||||
if ($agency === null) {
|
||||
return $response->withStatus(400)->withJsonError('api.dois.400.noRegistrationAgencyConfigured');
|
||||
}
|
||||
|
||||
$doisToUpdate = [];
|
||||
foreach ($requestIds as $issueId) {
|
||||
dispatch(new DepositIssue($issueId, $context, $agency));
|
||||
array_merge($doisToUpdate, Repo::doi()->getDoisForIssue($issueId));
|
||||
}
|
||||
Repo::doi()->markSubmitted($doisToUpdate);
|
||||
|
||||
return $response->withStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark submission DOIs as registered with a DOI registration agency.
|
||||
*/
|
||||
public function markIssuesRegistered(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve issues
|
||||
$requestIds = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($requestIds)) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.noPubObjectIncluded');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$validIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByPublished(true)
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
$invalidIds = array_diff($requestIds, $validIds);
|
||||
if (count($invalidIds)) {
|
||||
$failedDoiActions = array_map(function (int $id) {
|
||||
$issueTitle = Repo::issue()->get($id)?->getIssueIdentification() ?? 'Issue not found';
|
||||
return new DoiException(DoiException::ISSUE_NOT_PUBLISHED, $issueTitle, $issueTitle);
|
||||
}, $invalidIds);
|
||||
|
||||
return $response->withJson(
|
||||
[
|
||||
'failedDoiActions' => array_map(
|
||||
function (DoiException $item) {
|
||||
return $item->getMessage();
|
||||
},
|
||||
$failedDoiActions
|
||||
)
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($requestIds as $id) {
|
||||
$doiIds = Repo::doi()->getDoisForIssue($id);
|
||||
foreach ($doiIds as $doiId) {
|
||||
Repo::doi()->markRegistered($doiId);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark issues DOIs as no longer registered with a DOI registration agency.
|
||||
*/
|
||||
public function markIssuesUnregistered(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve issues
|
||||
$requestIds = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($requestIds)) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.noPubObjectIncluded');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$validIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
$invalidIds = array_diff($requestIds, $validIds);
|
||||
if (count($invalidIds)) {
|
||||
$failedDoiActions = array_map(function (int $id) {
|
||||
$issueTitle = Repo::issue()->get($id)?->getIssueIdentification() ?? 'Issue not found';
|
||||
return new DoiException(DoiException::INCORRECT_ISSUE_CONTEXT, $issueTitle, $issueTitle);
|
||||
}, $invalidIds);
|
||||
|
||||
return $response->withJson(
|
||||
[
|
||||
'failedDoiActions' => array_map(
|
||||
function (DoiException $item) {
|
||||
return $item->getMessage();
|
||||
},
|
||||
$failedDoiActions
|
||||
)
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($requestIds as $id) {
|
||||
$doiIds = Repo::doi()->getDoisForIssue($id);
|
||||
foreach ($doiIds as $doiId) {
|
||||
Repo::doi()->markUnregistered($doiId);
|
||||
}
|
||||
}
|
||||
|
||||
return $response->withStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark submission DOIs as stale, indicating a need to be resubmitted to registration agency with updated metadata.
|
||||
*/
|
||||
public function markIssuesStale(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve issues
|
||||
$requestIds = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($requestIds)) {
|
||||
return $response->withStatus(404)->withJsonError('api.dois.404.noPubObjectIncluded');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$validIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([$context->getId()])
|
||||
->filterByPublished(true)
|
||||
// Items can only be considered stale if they have been deposited/queued for deposit in the first place
|
||||
->filterByDoiStatuses([Doi::STATUS_SUBMITTED, Doi::STATUS_REGISTERED])
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
$invalidIds = array_diff($requestIds, $validIds);
|
||||
if (count($invalidIds)) {
|
||||
$failedDoiActions = array_map(function (int $id) {
|
||||
$issueTitle = Repo::issue()->get($id)?->getIssueIdentification() ?? 'Issue not found';
|
||||
return new DoiException(DoiException::INCORRECT_STALE_STATUS, $issueTitle, $issueTitle);
|
||||
}, $invalidIds);
|
||||
|
||||
return $response->withJson(
|
||||
[
|
||||
'failedDoiActions' => array_map(
|
||||
function (DoiException $item) {
|
||||
return $item->getMessage();
|
||||
},
|
||||
$failedDoiActions
|
||||
)
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($requestIds as $id) {
|
||||
$doiIds = Repo::doi()->getDoisForIssue($id);
|
||||
Repo::doi()->markStale($doiIds);
|
||||
}
|
||||
|
||||
return $response->withStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign DOIs to issue
|
||||
*/
|
||||
public function assignIssueDois(SlimRequest $slimRequest, APIResponse $response, array $args): Response
|
||||
{
|
||||
// Retrieve issues
|
||||
$ids = $slimRequest->getParsedBody()['ids'] ?? [];
|
||||
if (!count($ids)) {
|
||||
return $response->withStatus(404)->withJsonError('api.issue.404.issuesNotFound');
|
||||
}
|
||||
|
||||
$context = $this->getRequest()->getContext();
|
||||
$doiPrefix = $context->getData(Context::SETTING_DOI_PREFIX);
|
||||
if (empty($doiPrefix)) {
|
||||
return $response->withStatus(403)->withJsonError('api.dois.403.prefixRequired');
|
||||
}
|
||||
|
||||
$failedDoiActions = [];
|
||||
|
||||
// Assign DOIs
|
||||
foreach ($ids as $id) {
|
||||
$issue = Repo::issue()->get($id);
|
||||
if ($issue !== null) {
|
||||
$creationFailureResults = Repo::issue()->createDoi($issue);
|
||||
$failedDoiActions = array_merge($failedDoiActions, $creationFailureResults);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($failedDoiActions)) {
|
||||
return $response->withJson(
|
||||
[
|
||||
'failedDoiActions' => array_map(
|
||||
function (DoiException $item) {
|
||||
return $item->getMessage();
|
||||
},
|
||||
$failedDoiActions
|
||||
)
|
||||
],
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
return $response->withJson(['failedDoiActions' => $failedDoiActions], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc PKPDoiHandler::getPubObjectHandler()
|
||||
*/
|
||||
protected function getPubObjectHandler(string $type): mixed
|
||||
{
|
||||
$handler = parent::getPubObjectHandler($type);
|
||||
if ($handler !== null) {
|
||||
return $handler;
|
||||
}
|
||||
|
||||
return match ($type) {
|
||||
Repo::doi()::TYPE_ISSUE => Repo::issue(),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_dois DOI API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/dois/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_dois
|
||||
*
|
||||
* @brief Handle API requests for DOI operations.
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\dois\DoiHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_emailTemplates Email templates API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/emailTemplates/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_emailTemplates
|
||||
*
|
||||
* @brief Handle API requests for emailTemplates.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\emailTemplates\PKPEmailTemplateHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_highlights Highlights API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/highlights/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2023 Simon Fraser University
|
||||
* Copyright (c) 2003-2023 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_highlights
|
||||
*
|
||||
* @brief Handle API requests for highlights.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\highlights\HighlightsHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_institutions Institution API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/institutions/index.php
|
||||
*
|
||||
* Copyright (c) 2022 Simon Fraser University
|
||||
* Copyright (c) 2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_institutions
|
||||
*
|
||||
* @brief Handle API requests for institutions.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\institutions\PKPInstitutionHandler();
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/issues/IssueHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class IssueHandler
|
||||
*
|
||||
* @ingroup api_v1_issues
|
||||
*
|
||||
* @brief Handle API requests for issues operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\issues;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\facades\Repo;
|
||||
use APP\issue\Collector;
|
||||
use APP\security\authorization\OjsIssueRequiredPolicy;
|
||||
use APP\security\authorization\OjsJournalMustPublishPolicy;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
use PKP\core\APIResponse;
|
||||
use PKP\db\DAORegistry;
|
||||
use PKP\handler\APIHandler;
|
||||
use PKP\plugins\Hook;
|
||||
use PKP\security\authorization\ContextAccessPolicy;
|
||||
use PKP\security\authorization\ContextRequiredPolicy;
|
||||
use PKP\security\authorization\UserRolesRequiredPolicy;
|
||||
use PKP\security\Role;
|
||||
use PKP\submission\GenreDAO;
|
||||
use Slim\Http\Request;
|
||||
|
||||
class IssueHandler extends APIHandler
|
||||
{
|
||||
/** @var int The default number of issues to return in one request */
|
||||
public const DEFAULT_COUNT = 20;
|
||||
|
||||
/** @var int The maximum number of issues to return in one request */
|
||||
public const MAX_COUNT = 100;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_handlerPath = 'issues';
|
||||
$roles = [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR];
|
||||
$this->_endpoints = [
|
||||
'GET' => [
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern(),
|
||||
'handler' => [$this, 'getMany'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/current',
|
||||
'handler' => [$this, 'getCurrent'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/{issueId:\d+}',
|
||||
'handler' => [$this, 'get'],
|
||||
'roles' => $roles
|
||||
],
|
||||
]
|
||||
];
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
//
|
||||
// Implement methods from PKPHandler
|
||||
//
|
||||
public function authorize($request, &$args, $roleAssignments)
|
||||
{
|
||||
$routeName = null;
|
||||
$slimRequest = $this->getSlimRequest();
|
||||
|
||||
if (!is_null($slimRequest) && ($route = $slimRequest->getAttribute('route'))) {
|
||||
$routeName = $route->getName();
|
||||
}
|
||||
|
||||
$this->addPolicy(new UserRolesRequiredPolicy($request), true);
|
||||
$this->addPolicy(new ContextRequiredPolicy($request));
|
||||
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
|
||||
$this->addPolicy(new OjsJournalMustPublishPolicy($request));
|
||||
|
||||
if ($routeName === 'get') {
|
||||
$this->addPolicy(new OjsIssueRequiredPolicy($request, $args));
|
||||
}
|
||||
|
||||
return parent::authorize($request, $args, $roleAssignments);
|
||||
}
|
||||
|
||||
//
|
||||
// Public handler methods
|
||||
//
|
||||
/**
|
||||
* Get a collection of issues
|
||||
*
|
||||
* @param Request $slimRequest Slim request object
|
||||
* @param APIResponse $response object
|
||||
* @param array $args arguments
|
||||
*
|
||||
* @return APIResponse
|
||||
*/
|
||||
public function getMany($slimRequest, $response, $args)
|
||||
{
|
||||
$collector = Repo::issue()->getCollector()
|
||||
->limit(self::DEFAULT_COUNT)
|
||||
->offset(0);
|
||||
|
||||
$request = $this->getRequest();
|
||||
$currentUser = $request->getUser();
|
||||
$context = $request->getContext();
|
||||
|
||||
if (!$context) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
// Process query params to format incoming data as needed
|
||||
foreach ($slimRequest->getQueryParams() as $param => $val) {
|
||||
switch ($param) {
|
||||
case 'orderBy':
|
||||
if (in_array($val, [Collector::ORDERBY_DATE_PUBLISHED, Collector::ORDERBY_LAST_MODIFIED, Collector::ORDERBY_SEQUENCE])) {
|
||||
$collector->orderBy($val);
|
||||
}
|
||||
break;
|
||||
|
||||
// Enforce a maximum count to prevent the API from crippling the
|
||||
// server
|
||||
case 'count':
|
||||
$collector->limit(min((int) $val, self::MAX_COUNT));
|
||||
break;
|
||||
|
||||
case 'offset':
|
||||
$collector->offset((int) $val);
|
||||
break;
|
||||
|
||||
// Always convert volume, number and year values to array
|
||||
case 'volumes':
|
||||
case 'volume':
|
||||
case 'numbers':
|
||||
case 'number':
|
||||
case 'years':
|
||||
case 'year':
|
||||
|
||||
// Support deprecated `year`, `number` and `volume` params
|
||||
if (substr($param, -1) !== 's') {
|
||||
$param .= 's';
|
||||
}
|
||||
|
||||
if (is_string($val)) {
|
||||
$val = explode(',', $val);
|
||||
} elseif (!is_array($val)) {
|
||||
$val = [$val];
|
||||
}
|
||||
$values = array_map('intval', $val);
|
||||
switch ($param) {
|
||||
case 'volumes':
|
||||
$collector->filterByVolumes($values);
|
||||
break;
|
||||
case 'numbers':
|
||||
$collector->filterByNumbers($values);
|
||||
break;
|
||||
case 'years':
|
||||
$collector->filterByYears($values);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'isPublished':
|
||||
$collector->filterByPublished((bool) $val);
|
||||
break;
|
||||
|
||||
case 'searchPhrase':
|
||||
$collector->searchPhrase($val);
|
||||
break;
|
||||
case 'doiStatus':
|
||||
$collector->filterByDoiStatuses(array_map('intval', $this->paramToArray($val)));
|
||||
break;
|
||||
case 'hasDois':
|
||||
$collector->filterByHasDois((bool) $val, $context->getEnabledDoiTypes());
|
||||
}
|
||||
}
|
||||
|
||||
$collector->filterByContextIds([$context->getId()]);
|
||||
|
||||
Hook::call('API::issues::params', [&$collector, $slimRequest]);
|
||||
|
||||
// You must be a manager or site admin to access unpublished Issues
|
||||
$isAdmin = $currentUser->hasRole([Role::ROLE_ID_MANAGER], $context->getId()) || $currentUser->hasRole([Role::ROLE_ID_SITE_ADMIN], \PKP\core\PKPApplication::CONTEXT_SITE);
|
||||
if (isset($collector->isPublished) && !$collector->isPublished && !$isAdmin) {
|
||||
return $response->withStatus(403)->withJsonError('api.submissions.403.unpublishedIssues');
|
||||
} elseif (!$isAdmin) {
|
||||
$collector->filterByPublished(true);
|
||||
}
|
||||
|
||||
$issues = $collector->getMany();
|
||||
|
||||
return $response->withJson([
|
||||
'items' => Repo::issue()->getSchemaMap()->summarizeMany($issues, $context)->values(),
|
||||
'itemsMax' => $collector->limit(null)->offset(null)->getCount(),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current issue
|
||||
*
|
||||
* @param Request $slimRequest Slim request object
|
||||
* @param APIResponse $response object
|
||||
* @param array $args arguments
|
||||
*
|
||||
* @return APIResponse
|
||||
*/
|
||||
public function getCurrent($slimRequest, $response, $args)
|
||||
{
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$issue = Repo::issue()->getCurrent($context->getId());
|
||||
|
||||
if (!$issue) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
$data = Repo::issue()->getSchemaMap()->map(
|
||||
$issue,
|
||||
$context,
|
||||
$this->getUserGroups($context->getId()),
|
||||
$this->getGenres($context->getId())
|
||||
);
|
||||
|
||||
return $response->withJson($data, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single issue
|
||||
*
|
||||
* @param Request $slimRequest Slim request object
|
||||
* @param APIResponse $response object
|
||||
* @param array $args arguments
|
||||
*
|
||||
* @return APIResponse
|
||||
*/
|
||||
public function get($slimRequest, $response, $args)
|
||||
{
|
||||
$context = $this->getRequest()->getContext();
|
||||
|
||||
$issue = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_ISSUE);
|
||||
|
||||
if (!$issue) {
|
||||
return $response->withStatus(404)->withJsonError('api.404.resourceNotFound');
|
||||
}
|
||||
|
||||
$data = Repo::issue()->getSchemaMap()->map(
|
||||
$issue,
|
||||
$context,
|
||||
$this->getUserGroups($context->getId()),
|
||||
$this->getGenres($context->getId())
|
||||
);
|
||||
|
||||
return $response->withJson($data, 200);
|
||||
}
|
||||
|
||||
protected function getUserGroups(int $contextId): LazyCollection
|
||||
{
|
||||
return Repo::userGroup()->getCollector()
|
||||
->filterByContextIds([$contextId])
|
||||
->getMany();
|
||||
}
|
||||
|
||||
protected function getGenres(int $contextId): array
|
||||
{
|
||||
/** @var GenreDAO $genreDao */
|
||||
$genreDao = DAORegistry::getDAO('GenreDAO');
|
||||
return $genreDao->getByContextId($contextId)->toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_issues Issues API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/issues/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_issues
|
||||
*
|
||||
* @brief Handle requests for issues API functions.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\issues\IssueHandler();
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_jobs Queue Jobs API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/jobs/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_users
|
||||
*
|
||||
* @brief Handle requests for Queue Jobs API functions.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\jobs\PKPJobHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_mailables Email templates API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/mailables/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2022 Simon Fraser University
|
||||
* Copyright (c) 2003-2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_mailables
|
||||
*
|
||||
* @brief Handle API requests for mailables.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\mailables\MailableHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_site Site API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/site/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_site
|
||||
*
|
||||
* @brief Handle API requests for the site object.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\site\PKPSiteHandler();
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/stats/StatsEditorialHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class StatsEditorialHandler
|
||||
*
|
||||
* @ingroup api_v1_stats
|
||||
*
|
||||
* @brief Handle API requests for editorial statistics.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\stats\editorial;
|
||||
|
||||
class StatsEditorialHandler extends \PKP\API\v1\stats\editorial\PKPStatsEditorialHandler
|
||||
{
|
||||
/** @var string The name of the section ids query param for this application */
|
||||
public $sectionIdsQueryParam = 'sectionIds';
|
||||
|
||||
public function getSectionIdsQueryParam()
|
||||
{
|
||||
return $this->sectionIdsQueryParam;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_stats Publication statistics API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/stats/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_stats
|
||||
*
|
||||
* @brief Handle API requests for publication statistics
|
||||
*
|
||||
*/
|
||||
|
||||
use APP\core\Application;
|
||||
|
||||
$requestPath = Application::get()->getRequest()->getRequestPath();
|
||||
if (strpos($requestPath, '/stats/publications')) {
|
||||
return new \APP\API\v1\stats\publications\StatsPublicationHandler();
|
||||
} elseif (strpos($requestPath, '/stats/editorial')) {
|
||||
return new \APP\API\v1\stats\editorial\StatsEditorialHandler();
|
||||
} elseif (strpos($requestPath, '/stats/users')) {
|
||||
return new \PKP\API\v1\stats\users\PKPStatsUserHandler();
|
||||
} elseif (strpos($requestPath, '/stats/issues')) {
|
||||
return new \APP\API\v1\stats\issues\StatsIssueHandler();
|
||||
} elseif (strpos($requestPath, '/stats/contexts')) {
|
||||
return new \PKP\API\v1\stats\contexts\PKPStatsContextHandler();
|
||||
} elseif (strpos($requestPath, '/stats/sushi')) {
|
||||
return new \APP\API\v1\stats\sushi\StatsSushiHandler();
|
||||
} else {
|
||||
http_response_code('404');
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'error' => 'api.404.endpointNotFound',
|
||||
'errorMessage' => __('api.404.endpointNotFound'),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/stats/StatsIssueHandler.php
|
||||
*
|
||||
* Copyright (c) 2022 Simon Fraser University
|
||||
* Copyright (c) 2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class StatsIssueHandler
|
||||
*
|
||||
* @ingroup api_v1_stats
|
||||
*
|
||||
* @brief Handle API requests for issue statistics.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\stats\issues;
|
||||
|
||||
use APP\core\Application;
|
||||
use APP\core\Services;
|
||||
use APP\facades\Repo;
|
||||
use APP\security\authorization\OjsIssueRequiredPolicy;
|
||||
use APP\statistics\StatisticsHelper;
|
||||
use PKP\core\APIResponse;
|
||||
use PKP\handler\APIHandler;
|
||||
use PKP\plugins\Hook;
|
||||
use PKP\security\authorization\ContextAccessPolicy;
|
||||
use PKP\security\authorization\PolicySet;
|
||||
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
|
||||
use PKP\security\authorization\UserRolesRequiredPolicy;
|
||||
use PKP\security\Role;
|
||||
use Slim\Http\Request as SlimHttpRequest;
|
||||
|
||||
class StatsIssueHandler extends APIHandler
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_handlerPath = 'stats/issues';
|
||||
$roles = [Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_MANAGER /*, Role::ROLE_ID_SUB_EDITOR */];
|
||||
$this->_endpoints = [
|
||||
'GET' => [
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern(),
|
||||
'handler' => [$this, 'getMany'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/timeline',
|
||||
'handler' => [$this, 'getManyTimeline'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/{issueId:\d+}',
|
||||
'handler' => [$this, 'get'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/{issueId:\d+}/timeline',
|
||||
'handler' => [$this, 'getTimeline'],
|
||||
'roles' => $roles
|
||||
],
|
||||
],
|
||||
];
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc PKPHandler::authorize()
|
||||
*/
|
||||
public function authorize($request, &$args, $roleAssignments)
|
||||
{
|
||||
$routeName = null;
|
||||
$slimRequest = $this->getSlimRequest();
|
||||
|
||||
$this->addPolicy(new UserRolesRequiredPolicy($request), true);
|
||||
|
||||
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
|
||||
|
||||
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
|
||||
foreach ($roleAssignments as $role => $operations) {
|
||||
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
|
||||
}
|
||||
$this->addPolicy($rolePolicy);
|
||||
|
||||
if (!is_null($slimRequest) && ($route = $slimRequest->getAttribute('route'))) {
|
||||
$routeName = $route->getName();
|
||||
}
|
||||
if (in_array($routeName, ['get', 'getGalley', 'getToc'])) {
|
||||
$this->addPolicy(new OjsIssueRequiredPolicy($request, $args));
|
||||
}
|
||||
|
||||
return parent::authorize($request, $args, $roleAssignments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get usage stats for a set of issues
|
||||
*
|
||||
* Returns total views by toc and all galleys.
|
||||
*/
|
||||
public function getMany(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
$responseCSV = str_contains($slimRequest->getHeaderLine('Accept'), APIResponse::RESPONSE_CSV) ? true : false;
|
||||
|
||||
$defaultParams = [
|
||||
'count' => 30,
|
||||
'offset' => 0,
|
||||
'orderDirection' => StatisticsHelper::STATISTICS_ORDER_DESC,
|
||||
];
|
||||
|
||||
$requestParams = array_merge($defaultParams, $slimRequest->getQueryParams());
|
||||
|
||||
$allowedParams = $this->_processAllowedParams($requestParams, [
|
||||
'dateStart',
|
||||
'dateEnd',
|
||||
'count',
|
||||
'offset',
|
||||
'orderDirection',
|
||||
'searchPhrase',
|
||||
'issueIds',
|
||||
]);
|
||||
|
||||
Hook::call('API::stats::issues::params', [&$allowedParams, $slimRequest]);
|
||||
|
||||
$allowedParams['contextIds'] = [$request->getContext()->getId()];
|
||||
|
||||
$result = $this->_validateStatDates($allowedParams);
|
||||
if ($result !== true) {
|
||||
return $response->withStatus(400)->withJsonError($result);
|
||||
}
|
||||
|
||||
if (!in_array($allowedParams['orderDirection'], [StatisticsHelper::STATISTICS_ORDER_ASC, StatisticsHelper::STATISTICS_ORDER_DESC])) {
|
||||
return $response->withStatus(400)->withJsonError('api.stats.400.invalidOrderDirection');
|
||||
}
|
||||
|
||||
// Identify issues which should be included in the results when a searchPhrase is passed
|
||||
if (!empty($allowedParams['searchPhrase'])) {
|
||||
$allowedIssueIds = empty($allowedParams['issueIds']) ? [] : $allowedParams['issueIds'];
|
||||
$allowedParams['issueIds'] = $this->_processSearchPhrase($allowedParams['searchPhrase'], $allowedIssueIds);
|
||||
|
||||
if (empty($allowedParams['issueIds'])) {
|
||||
$csvColumnNames = $this->_getIssueReportColumnNames();
|
||||
if ($responseCSV) {
|
||||
return $response->withCSV([], $csvColumnNames, 0);
|
||||
} else {
|
||||
return $response->withJson([
|
||||
'items' => [],
|
||||
'itemsMax' => 0,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list (count number) of top issues by total (toc + galley) views
|
||||
$statsService = Services::get('issueStats');
|
||||
$totalMetrics = $statsService->getTotals($allowedParams);
|
||||
|
||||
// Get the stats for each issue
|
||||
$items = [];
|
||||
foreach ($totalMetrics as $totalMetric) {
|
||||
$issueId = $totalMetric->issue_id;
|
||||
$dateStart = array_key_exists('dateStart', $allowedParams) ? $allowedParams['dateStart'] : null;
|
||||
$dateEnd = array_key_exists('dateEnd', $allowedParams) ? $allowedParams['dateEnd'] : null;
|
||||
$metricsByType = $statsService->getTotalsByType($issueId, $this->getRequest()->getContext()->getId(), $dateStart, $dateEnd);
|
||||
|
||||
if ($responseCSV) {
|
||||
$items[] = $this->getItemForCSV($issueId, $metricsByType['toc'], $metricsByType['galley']);
|
||||
} else {
|
||||
$items[] = $this->getItemForJSON($issueId, $metricsByType['toc'], $metricsByType['galley']);
|
||||
}
|
||||
}
|
||||
|
||||
$itemsMax = $statsService->getCount($allowedParams);
|
||||
$csvColumnNames = $this->_getIssueReportColumnNames();
|
||||
if ($responseCSV) {
|
||||
return $response->withCSV($items, $csvColumnNames, $itemsMax);
|
||||
} else {
|
||||
return $response->withJson([
|
||||
'items' => $items,
|
||||
'itemsMax' => $itemsMax,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total TOC or issue galley views for a set of issues
|
||||
* in a timeline broken down by month or day
|
||||
*/
|
||||
public function getManyTimeline(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
$responseCSV = str_contains($slimRequest->getHeaderLine('Accept'), APIResponse::RESPONSE_CSV) ? true : false;
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
$defaultParams = [
|
||||
'timelineInterval' => StatisticsHelper::STATISTICS_DIMENSION_MONTH,
|
||||
];
|
||||
|
||||
$requestParams = array_merge($defaultParams, $slimRequest->getQueryParams());
|
||||
|
||||
$allowedParams = $this->_processAllowedParams($requestParams, [
|
||||
'dateStart',
|
||||
'dateEnd',
|
||||
'timelineInterval',
|
||||
'searchPhrase',
|
||||
'type'
|
||||
]);
|
||||
|
||||
Hook::call('API::stats::issues::timeline::params', [&$allowedParams, $slimRequest]);
|
||||
|
||||
if (!$this->isValidTimelineInterval($allowedParams['timelineInterval'])) {
|
||||
return $response->withStatus(400)->withJsonError('api.stats.400.wrongTimelineInterval');
|
||||
}
|
||||
|
||||
$result = $this->_validateStatDates($allowedParams);
|
||||
if ($result !== true) {
|
||||
return $response->withStatus(400)->withJsonError($result);
|
||||
}
|
||||
|
||||
$allowedParams['contextIds'] = [$request->getContext()->getId()];
|
||||
$allowedParams['assocTypes'] = [Application::ASSOC_TYPE_ISSUE];
|
||||
if (array_key_exists('type', $allowedParams) && $allowedParams['type'] == 'files') {
|
||||
$allowedParams['assocTypes'] = [Application::ASSOC_TYPE_ISSUE_GALLEY];
|
||||
};
|
||||
|
||||
// Identify issues which should be included in the results when a searchPhrase is passed
|
||||
if (!empty($allowedParams['searchPhrase'])) {
|
||||
$allowedIssueIds = empty($allowedParams['issueIds']) ? [] : $allowedParams['issueIds'];
|
||||
$allowedParams['issueIds'] = $this->_processSearchPhrase($allowedParams['searchPhrase'], $allowedIssueIds);
|
||||
|
||||
if (empty($allowedParams['issueIds'])) {
|
||||
$dateStart = empty($allowedParams['dateStart']) ? StatisticsHelper::STATISTICS_EARLIEST_DATE : $allowedParams['dateStart'];
|
||||
$dateEnd = empty($allowedParams['dateEnd']) ? date('Ymd', strtotime('yesterday')) : $allowedParams['dateEnd'];
|
||||
$emptyTimeline = Services::get('issueStats')->getEmptyTimelineIntervals($dateStart, $dateEnd, $allowedParams['timelineInterval']);
|
||||
if ($responseCSV) {
|
||||
$csvColumnNames = Services::get('issueStats')->getTimelineReportColumnNames();
|
||||
return $response->withCSV($emptyTimeline, $csvColumnNames, 0);
|
||||
}
|
||||
return $response->withJson($emptyTimeline, 200);
|
||||
}
|
||||
}
|
||||
|
||||
$data = Services::get('issueStats')->getTimeline($allowedParams['timelineInterval'], $allowedParams);
|
||||
if ($responseCSV) {
|
||||
$csvColumnNames = Services::get('issueStats')->getTimelineReportColumnNames();
|
||||
return $response->withCSV($data, $csvColumnNames, count($data));
|
||||
}
|
||||
return $response->withJson($data, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single issue's usage statistics
|
||||
*/
|
||||
public function get(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
|
||||
$issue = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_ISSUE);
|
||||
|
||||
$allowedParams = $this->_processAllowedParams($slimRequest->getQueryParams(), [
|
||||
'dateStart',
|
||||
'dateEnd',
|
||||
]);
|
||||
|
||||
Hook::call('API::stats::issue::params', [&$allowedParams, $slimRequest]);
|
||||
|
||||
$result = $this->_validateStatDates($allowedParams);
|
||||
if ($result !== true) {
|
||||
return $response->withStatus(400)->withJsonError($result);
|
||||
}
|
||||
|
||||
$statsService = Services::get('issueStats');
|
||||
$dateStart = array_key_exists('dateStart', $allowedParams) ? $allowedParams['dateStart'] : null;
|
||||
$dateEnd = array_key_exists('dateEnd', $allowedParams) ? $allowedParams['dateEnd'] : null;
|
||||
$metricsByType = $statsService->getTotalsByType($issue->getId(), $request->getContext()->getId(), $dateStart, $dateEnd);
|
||||
|
||||
return $response->withJson([
|
||||
'tocViews' => $metricsByType['toc'],
|
||||
'issueGalleyViews' => $metricsByType['galley'],
|
||||
'issue' => Repo::issue()->getSchemaMap()->mapToStats($issue),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total TOC or issue galley views for an issue broken down by
|
||||
* month or day
|
||||
*/
|
||||
public function getTimeline(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
$request = $this->getRequest();
|
||||
|
||||
$issue = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_ISSUE);
|
||||
|
||||
$defaultParams = [
|
||||
'timelineInterval' => StatisticsHelper::STATISTICS_DIMENSION_MONTH,
|
||||
];
|
||||
|
||||
$requestParams = array_merge($defaultParams, $slimRequest->getQueryParams());
|
||||
|
||||
$allowedParams = $this->_processAllowedParams($requestParams, [
|
||||
'dateStart',
|
||||
'dateEnd',
|
||||
'timelineInterval',
|
||||
'type'
|
||||
]);
|
||||
|
||||
Hook::call('API::stats::issue::timeline::params', [&$allowedParams, $slimRequest]);
|
||||
|
||||
$allowedParams['contextIds'] = [$request->getContext()->getId()];
|
||||
$allowedParams['issueIds'] = [$issue->getId()];
|
||||
$allowedParams['assocTypes'] = [Application::ASSOC_TYPE_ISSUE];
|
||||
if (array_key_exists('type', $allowedParams) && $allowedParams['type'] == 'files') {
|
||||
$allowedParams['assocTypes'] = [Application::ASSOC_TYPE_ISSUE_GALLEY];
|
||||
};
|
||||
|
||||
if (!$this->isValidTimelineInterval($allowedParams['timelineInterval'])) {
|
||||
return $response->withStatus(400)->withJsonError('api.stats.400.wrongTimelineInterval');
|
||||
}
|
||||
|
||||
$result = $this->_validateStatDates($allowedParams);
|
||||
if ($result !== true) {
|
||||
return $response->withStatus(400)->withJsonError($result);
|
||||
}
|
||||
|
||||
$statsService = Services::get('issueStats');
|
||||
$data = $statsService->getTimeline($allowedParams['timelineInterval'], $allowedParams);
|
||||
return $response->withJson($data, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to filter and sanitize the request params
|
||||
*
|
||||
* Only allows the specified params through and enforces variable
|
||||
* type where needed.
|
||||
*/
|
||||
protected function _processAllowedParams(array $requestParams, array $allowedParams): array
|
||||
{
|
||||
$returnParams = [];
|
||||
foreach ($requestParams as $requestParam => $value) {
|
||||
if (!in_array($requestParam, $allowedParams)) {
|
||||
continue;
|
||||
}
|
||||
switch ($requestParam) {
|
||||
case 'dateStart':
|
||||
case 'dateEnd':
|
||||
case 'timelineInterval':
|
||||
case 'searchPhrase':
|
||||
case 'type':
|
||||
$returnParams[$requestParam] = $value;
|
||||
break;
|
||||
|
||||
case 'count':
|
||||
$returnParams[$requestParam] = min(100, (int) $value);
|
||||
break;
|
||||
|
||||
case 'offset':
|
||||
$returnParams[$requestParam] = (int) $value;
|
||||
break;
|
||||
|
||||
case 'orderDirection':
|
||||
$returnParams[$requestParam] = strtoupper($value);
|
||||
break;
|
||||
|
||||
case 'issueIds':
|
||||
if (is_string($value) && strpos($value, ',') > -1) {
|
||||
$value = explode(',', $value);
|
||||
} elseif (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$returnParams[$requestParam] = array_map('intval', $value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $returnParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to get the issueIds param when a searchPhase
|
||||
* param is also passed.
|
||||
*
|
||||
* If the searchPhrase and issueIds params were both passed in the
|
||||
* request, then we only return IDs that match both conditions.
|
||||
*/
|
||||
protected function _processSearchPhrase(string $searchPhrase, array $issueIds = []): array
|
||||
{
|
||||
$searchPhraseIssueIds = Repo::issue()
|
||||
->getCollector()
|
||||
->filterByContextIds([Application::get()->getRequest()->getContext()->getId()])
|
||||
->filterByPublished(true)
|
||||
->searchPhrase($searchPhrase)
|
||||
->getIds()
|
||||
->toArray();
|
||||
|
||||
if (!empty($issueIds)) {
|
||||
return array_intersect($issueIds, $searchPhraseIssueIds);
|
||||
}
|
||||
return $searchPhraseIssueIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get column names for the issue CSV report
|
||||
*/
|
||||
protected function _getIssueReportColumnNames(): array
|
||||
{
|
||||
return [
|
||||
__('common.id'),
|
||||
__('editor.issues.issueIdentification'),
|
||||
__('stats.total'),
|
||||
__('stats.views'),
|
||||
__('stats.downloads')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CSV row with issue metrics
|
||||
*/
|
||||
protected function getItemForCSV(int $issueId, int $tocViews, int $issueGalleyViews): array
|
||||
{
|
||||
$totalViews = $tocViews + $issueGalleyViews;
|
||||
// Get issue identification for display
|
||||
$issue = Repo::issue()->get($issueId);
|
||||
$identification = $issue->getIssueIdentification();
|
||||
return [
|
||||
$issueId,
|
||||
$identification,
|
||||
$totalViews,
|
||||
$tocViews,
|
||||
$issueGalleyViews
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON data with issue metrics
|
||||
*/
|
||||
protected function getItemForJSON(int $issueId, int $tocViews, int $issueGalleyViews): array
|
||||
{
|
||||
$totalViews = $tocViews + $issueGalleyViews;
|
||||
// Get basic issue details for display
|
||||
$issue = Repo::issue()->get($issueId);
|
||||
$issueProps = Repo::issue()->getSchemaMap()->mapToStats($issue);
|
||||
return [
|
||||
'totalViews' => $totalViews,
|
||||
'tocViews' => $tocViews,
|
||||
'issueGalleyViews' => $issueGalleyViews,
|
||||
'issue' => $issueProps,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the timeline interval is valid
|
||||
*/
|
||||
protected function isValidTimelineInterval(string $interval): bool
|
||||
{
|
||||
return in_array($interval, [
|
||||
StatisticsHelper::STATISTICS_DIMENSION_DAY,
|
||||
StatisticsHelper::STATISTICS_DIMENSION_MONTH
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/stats/publications/StatsPublicationHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class StatsPublicationHandler
|
||||
*
|
||||
* @ingroup api_v1_stats
|
||||
*
|
||||
* @brief Handle API requests for publication statistics.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\stats\publications;
|
||||
|
||||
class StatsPublicationHandler extends \PKP\API\v1\stats\publications\PKPStatsPublicationHandler
|
||||
{
|
||||
/** @var string The name of the section ids query param for this application */
|
||||
public $sectionIdsQueryParam = 'sectionIds';
|
||||
|
||||
public function getSectionIdsQueryParam()
|
||||
{
|
||||
return $this->sectionIdsQueryParam;
|
||||
}
|
||||
|
||||
protected function getManyAllowedParams()
|
||||
{
|
||||
$params = parent::getManyAllowedParams();
|
||||
$params[] = 'issueIds';
|
||||
return $params;
|
||||
}
|
||||
|
||||
protected function getManyTimelineAllowedParams()
|
||||
{
|
||||
$params = parent::getManyTimelineAllowedParams();
|
||||
$params[] = 'issueIds';
|
||||
return $params;
|
||||
}
|
||||
|
||||
protected function _processParam(string $requestParam, mixed $value): array
|
||||
{
|
||||
if ($requestParam == 'issueIds') {
|
||||
$returnParams = [];
|
||||
if (is_string($value) && str_contains($value, ',')) {
|
||||
$value = explode(',', $value);
|
||||
} elseif (!is_array($value)) {
|
||||
$value = [$value];
|
||||
}
|
||||
$returnParams[$requestParam] = array_map('intval', $value);
|
||||
} else {
|
||||
$returnParams = parent::_processParam($requestParam, $value);
|
||||
}
|
||||
return $returnParams;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/stats/sushi/StatsSushiHandler.php
|
||||
*
|
||||
* Copyright (c) 2022 Simon Fraser University
|
||||
* Copyright (c) 2022 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class StatsSushiHandler
|
||||
*
|
||||
* @ingroup api_v1_stats
|
||||
*
|
||||
* @brief Handle API requests for COUNTER R5 SUSHI statistics.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\stats\sushi;
|
||||
|
||||
use APP\sushi\IR;
|
||||
use APP\sushi\IR_A1;
|
||||
use APP\sushi\TR;
|
||||
use APP\sushi\TR_J3;
|
||||
use PKP\core\APIResponse;
|
||||
use Slim\Http\Request as SlimHttpRequest;
|
||||
|
||||
class StatsSushiHandler extends \PKP\API\v1\stats\sushi\PKPStatsSushiHandler
|
||||
{
|
||||
/**
|
||||
* Get this API's endpoints definitions
|
||||
*/
|
||||
protected function getGETDefinitions(array $roles = null): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::getGETDefinitions($roles),
|
||||
[
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/reports/tr',
|
||||
'handler' => [$this, 'getReportsTR'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/reports/tr_j3',
|
||||
'handler' => [$this, 'getReportsTRJ3'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/reports/ir',
|
||||
'handler' => [$this, 'getReportsIR'],
|
||||
'roles' => $roles
|
||||
],
|
||||
[
|
||||
'pattern' => $this->getEndpointPattern() . '/reports/ir_a1',
|
||||
'handler' => [$this, 'getReportsIRA1'],
|
||||
'roles' => $roles
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* COUNTER 'Title Master Report' [TR].
|
||||
* A customizable report detailing activity at the journal level
|
||||
* that allows the user to apply filters and select other configuration options for the report.
|
||||
*/
|
||||
public function getReportsTR(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
return $this->getReportResponse(new TR(), $slimRequest, $response, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* COUNTER 'Journal Usage by Access Type' [TR_J3].
|
||||
* This is a Standard View of Title Master Report that reports on usage of journal content for all Metric_Types broken down by Access_Type.
|
||||
*/
|
||||
public function getReportsTRJ3(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
return $this->getReportResponse(new TR_J3(), $slimRequest, $response, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* COUNTER 'Item Master Report' [IR].
|
||||
* A customizable report detailing activity at the article level
|
||||
* that allows the user to apply filters and select other configuration options for the report.
|
||||
*/
|
||||
public function getReportsIR(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
return $this->getReportResponse(new IR(), $slimRequest, $response, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* COUNTER 'Journal Article Requests' [IR_A1].
|
||||
* This is a Standard View of Item Master Report that reports on journal article requests at the article level.
|
||||
*/
|
||||
public function getReportsIRA1(SlimHttpRequest $slimRequest, APIResponse $response, array $args): APIResponse
|
||||
{
|
||||
return $this->getReportResponse(new IR_A1(), $slimRequest, $response, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application specific list of reports supported by the API
|
||||
*/
|
||||
protected function getReportList(): array
|
||||
{
|
||||
return array_merge(parent::getReportList(), [
|
||||
[
|
||||
'Report_Name' => 'Title Master Report',
|
||||
'Report_ID' => 'TR',
|
||||
'Release' => '5',
|
||||
'Report_Description' => __('sushi.reports.tr.description'),
|
||||
'Path' => 'reports/tr'
|
||||
],
|
||||
[
|
||||
'Report_Name' => 'Journal Usage by Access Type',
|
||||
'Report_ID' => 'TR_J3',
|
||||
'Release' => '5',
|
||||
'Report_Description' => __('sushi.reports.tr_j3.description'),
|
||||
'Path' => 'reports/tr_j3'
|
||||
],
|
||||
[
|
||||
'Report_Name' => 'Item Master Report',
|
||||
'Report_ID' => 'IR',
|
||||
'Release' => '5',
|
||||
'Report_Description' => __('sushi.reports.ir.description'),
|
||||
'Path' => 'reports/ir'
|
||||
],
|
||||
[
|
||||
'Report_Name' => 'Journal Article Requests',
|
||||
'Report_ID' => 'IR_A1',
|
||||
'Release' => '5',
|
||||
'Report_Description' => __('sushi.reports.ir_a1.description'),
|
||||
'Path' => 'reports/ir_a1'
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/submissions/SubmissionHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class SubmissionHandler
|
||||
*
|
||||
* @ingroup api_v1_submission
|
||||
*
|
||||
* @brief Handle API requests for submission operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\submissions;
|
||||
|
||||
use APP\submission\Collector;
|
||||
|
||||
class SubmissionHandler extends \PKP\API\v1\submissions\PKPSubmissionHandler
|
||||
{
|
||||
/** @copydoc PKPSubmissionHandler::getSubmissionCollector() */
|
||||
protected function getSubmissionCollector(array $queryParams): Collector
|
||||
{
|
||||
$collector = parent::getSubmissionCollector($queryParams);
|
||||
|
||||
if (isset($queryParams['issueIds'])) {
|
||||
$collector->filterByIssueIds(
|
||||
array_map('intval', $this->paramToArray($queryParams['issueIds']))
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($queryParams['sectionIds'])) {
|
||||
$collector->filterBySectionIds(
|
||||
array_map('intval', $this->paramToArray($queryParams['sectionIds']))
|
||||
);
|
||||
}
|
||||
|
||||
return $collector;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_submissions Submission API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/submissions/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_submissions
|
||||
*
|
||||
* @brief Handle requests for submission API functions.
|
||||
*
|
||||
*/
|
||||
$urlParts = explode('/', trim($_SERVER['PATH_INFO'], '/'));
|
||||
if (count($urlParts) >= 6 && $urlParts[5] == 'files') {
|
||||
return new \PKP\API\v1\submissions\PKPSubmissionFileHandler();
|
||||
} else {
|
||||
return new \APP\API\v1\submissions\SubmissionHandler();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_temporaryFiles Temporary file upload API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/temporaryFiles/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_temporaryFiles
|
||||
*
|
||||
* @brief Handle API requests for temporary file uploading.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\temporaryFiles\PKPTemporaryFilesHandler();
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file api/v1/users/UserHandler.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class UserHandler
|
||||
*
|
||||
* @ingroup api_v1_users
|
||||
*
|
||||
* @brief Handle API requests for user operations.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace APP\API\v1\users;
|
||||
|
||||
class UserHandler extends \PKP\API\v1\users\PKPUserHandler
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @defgroup api_v1_users User API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/users/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_users
|
||||
*
|
||||
* @brief Handle requests for user API functions.
|
||||
*
|
||||
*/
|
||||
|
||||
return new \APP\API\v1\users\UserHandler();
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* @defgroup api_v1_vocabs Controlled vocabulary API requests
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file api/v1/vocabs/index.php
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2003-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @ingroup api_v1_vocabs
|
||||
*
|
||||
* @brief Handle API requests for vocabs.
|
||||
*/
|
||||
|
||||
return new \PKP\API\v1\vocabs\PKPVocabHandler();
|
||||
Reference in New Issue
Block a user