Skip to content

Commit

Permalink
Merge branch 'pkp:main' into structured-citations
Browse files Browse the repository at this point in the history
  • Loading branch information
GaziYucel authored Oct 21, 2024
2 parents 5dc8799 + b8d985f commit 1df2f9f
Show file tree
Hide file tree
Showing 16 changed files with 594 additions and 71 deletions.
111 changes: 108 additions & 3 deletions api/v1/stats/sushi/PKPStatsSushiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
use Illuminate\Support\Facades\Route;
use PKP\core\PKPBaseController;
use PKP\core\PKPRequest;
use PKP\core\PKPRoutingProvider;
use PKP\security\authorization\ContextRequiredPolicy;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\authorization\UserRolesRequiredPolicy;
use PKP\security\Role;
use PKP\sushi\CounterR5Report;
use PKP\sushi\SushiException;
use PKP\validation\ValidatorFactory;
use Symfony\Component\HttpFoundation\StreamedResponse;

class PKPStatsSushiController extends PKPBaseController
{
Expand Down Expand Up @@ -243,7 +246,7 @@ protected function getReportList(): array
* COUNTER 'Platform Usage' [PR_P1].
* A customizable report summarizing activity across the Platform (journal, press, or server).
*/
public function getReportsPR(Request $illuminateRequest): JsonResponse
public function getReportsPR(Request $illuminateRequest): JsonResponse|StreamedResponse
{
return $this->getReportResponse(new PR(), $illuminateRequest);
}
Expand All @@ -252,24 +255,126 @@ public function getReportsPR(Request $illuminateRequest): JsonResponse
* COUNTER 'Platform Master Report' [PR].
* This is a Standard View of the Platform Master Report that presents usage for the overall Platform broken down by Metric_Type
*/
public function getReportsPR1(Request $illuminateRequest): JsonResponse
public function getReportsPR1(Request $illuminateRequest): JsonResponse|StreamedResponse
{
return $this->getReportResponse(new PR_P1(), $illuminateRequest);
}

/** Validate user input for TSV reports */
protected function _validateUserInput(CounterR5Report $report, array $params): array
{
$request = $this->getRequest();
$context = $request->getContext();
$earliestDate = CounterR5Report::getEarliestDate();
$lastDate = CounterR5Report::getLastDate();
$submissionIds = Repo::submission()->getCollector()->filterByContextIds([$context->getId()])->getIds()->implode(',');

$rules = [
'begin_date' => [
'regex:/^\d{4}-\d{2}(-\d{2})?$/',
'after_or_equal:' . $earliestDate,
'before_or_equal:end_date',
],
'end_date' => [
'regex:/^\d{4}-\d{2}(-\d{2})?$/',
'before_or_equal:' . $lastDate,
'after_or_equal:begin_date',
],
'item_id' => [
// TO-ASK: shell this rather be just validation for positive integer?
'in:' . $submissionIds,
],
'yop' => [
'regex:/^\d{4}((\||-)\d{4})*$/',
],
];
$reportId = $report->getID();
if (in_array($reportId, ['PR', 'TR', 'IR'])) {
$rules['metric_type'] = ['required'];
}

$errors = [];
$validator = ValidatorFactory::make(
$params,
$rules,
[
'begin_date.regex' => __(
'manager.statistics.counterR5Report.settings.wrongDateFormat'
),
'end_date.regex' => __(
'manager.statistics.counterR5Report.settings.wrongDateFormat'
),
'begin_date.after_or_equal' => __(
'stats.dateRange.invalidStartDateMin'
),
'end_date.before_or_equal' => __(
'stats.dateRange.invalidEndDateMax'
),
'begin_date.before_or_equal' => __(
'stats.dateRange.invalidDateRange'
),
'end_date.after_or_equal' => __(
'stats.dateRange.invalidDateRange'
),
'item_id.*' => __(
'manager.statistics.counterR5Report.settings.wrongItemId'
),
'yop.regex' => __(
'manager.statistics.counterR5Report.settings.wrongYOPFormat'
),
]
);

if ($validator->fails()) {
$errors = $validator->errors()->getMessages();
}

return $errors;
}

/**
* Get the requested report
*/
protected function getReportResponse(CounterR5Report $report, Request $illuminateRequest): JsonResponse
protected function getReportResponse(CounterR5Report $report, Request $illuminateRequest): JsonResponse|StreamedResponse
{
$params = $illuminateRequest->query();
//$responseTSV = str_contains($illuminateRequest->getHeaderLine('Accept'), PKPRoutingProvider::RESPONSE_TSV['mime']) ? true : false;
$responseTSV = $illuminateRequest->accepts(PKPRoutingProvider::RESPONSE_TSV['mime']);

if ($responseTSV) {
$errors = $this->_validateUserInput($report, $params);
if (!empty($errors)) {
return response()->json($errors, 400);
}
}

try {
$report->processReportParams($this->getRequest(), $params);
} catch (SushiException $e) {
return response()->json($e->getResponseData(), $e->getHttpStatusCode());
}

if ($responseTSV) {
$reportHeader = $report->getTSVReportHeader();
$reportColumnNames = $report->getTSVColumnNames();
$reportItems = $report->getTSVReportItems();
// consider 3030 error (no usage available)
$key = array_search('3030', array_column($report->warnings, 'Code'));
if ($key !== false) {
$error = $report->warnings[$key]['Code'] . ':' . $report->warnings[$key]['Message'] . '(' . $report->warnings[$key]['Data'] . ')';
foreach ($reportHeader as &$headerRow) {
if (in_array('Exceptions', $headerRow)) {
$headerRow[1] =
$headerRow[1] == '' ?
$error :
$headerRow[1] . ';' . $error;
}
}
}
$report = array_merge($reportHeader, [['']], $reportColumnNames, $reportItems);
return response()->withFile($report, [], count($reportItems));
}

$reportHeader = $report->getReportHeader();
$reportItems = $report->getReportItems();

Expand Down
66 changes: 66 additions & 0 deletions classes/components/forms/counter/PKPCounterReportForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* @file classes/components/form/counter/PKPCounterReportForm.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPCounterReportForm
*
* @ingroup classes_controllers_form
*
* @brief A form for setting a COUNTER R5 report
*/

namespace PKP\components\forms\counter;

use PKP\components\forms\FormComponent;

define('FORM_COUNTER', 'counter');

abstract class PKPCounterReportForm extends FormComponent
{
/** @copydoc FormComponent::$id */
public $id = FORM_COUNTER;

/** @copydoc FormComponent::$method */
public $method = 'GET';

/** Form fields for each COUNTER R5 report */
public $reportFields = [];

/** Set reportFields, that will contain form fields for each COUNTER R5 report */
abstract public function setReportFields(): void;

/**
* Constructor
*
* @param string $action URL to submit the form to
* @param array $locales Supported locales
*/
public function __construct(string $action, array $locales)
{
$this->action = $action;
$this->locales = $locales;

$this->addPage(['id' => 'default', 'submitButton' => ['label' => __('common.download')]]);
$this->addGroup(['id' => 'default', 'pageId' => 'default']);

$this->setReportFields();
}

public function getConfig()
{
$config = parent::getConfig();
$config['reportFields'] = array_map(function ($reportFields) {
return array_map(function ($reportField) {
$field = $this->getFieldConfig($reportField);
$field['groupId'] = 'default';
return $field;
}, $reportFields);
}, $this->reportFields);

return $config;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

namespace PKP\components\forms\dashboard;

use APP\components\forms\FieldSelectIssues;
use APP\core\Application;
use APP\facades\Repo;
use Illuminate\Support\LazyCollection;
Expand All @@ -27,7 +26,7 @@
use PKP\context\Context;
use PKP\security\Role;

class SubmissionFilters extends FormComponent
class PKPSubmissionFilters extends FormComponent
{
/**
* The maximum number of options in a field
Expand All @@ -49,7 +48,6 @@ public function __construct(
->addGroup(['id' => 'default', 'pageId' => 'default'])
->addSectionFields()
->addAssignedTo()
->addIssues()
->addCategories()
->addDaysSinceLastActivity()
;
Expand Down Expand Up @@ -119,17 +117,6 @@ protected function addAssignedTo(): self
]));
}

protected function addIssues(): self
{
$request = Application::get()->getRequest();

return $this->addField(new FieldSelectIssues('issueIds', [
'groupId' => 'default',
'label' => __('issue.issues'),
'value' => [],
'apiUrl' => $request->getDispatcher()->url($request, Application::ROUTE_API, $request->getContext()->getPath(), 'issues'),
]));
}

protected function addCategories(): self
{
Expand Down
1 change: 1 addition & 0 deletions classes/components/forms/publication/ContributorForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public function __construct(string $action, array $locales, ?Submission $submiss
->addField(new FieldText('affiliation', [
'label' => __('user.affiliation'),
'isMultilingual' => true,
'size' => 'large',
]));

if ($authorUserGroupsOptions->count() > 1) {
Expand Down
52 changes: 52 additions & 0 deletions classes/components/listPanels/PKPCounterReportsListPanel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* @file classes/components/listPanels/PKPCounterReportsListPanel.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPCounterReportsListPanel
*
* @ingroup classes_components_list
*
* @brief A ListPanel component for viewing, editing and downloading COUNTER R5 reports
*/

namespace PKP\components\listPanels;

use APP\components\forms\counter\CounterReportForm;
use PKP\sushi\CounterR5Report;

class PKPCounterReportsListPanel extends ListPanel
{
/** URL to the API endpoint where items can be retrieved */
public string $apiUrl = '';

/** Form for setting up and downloading a report*/
public ?CounterReportForm $form = null;

/** Query parameters to pass if this list executes GET requests */
public array $getParams = [];

/**
* @copydoc ListPanel::getConfig()
*/
public function getConfig(): array
{
$config = parent::getConfig();

$earliestDate = CounterR5Report::getEarliestDate();
$lastDate = CounterR5Report::getLastDate();

$config = array_merge(
$config,
[
'apiUrl' => $this->apiUrl,
'form' => $this->form->getConfig(),
'usagePossible' => $lastDate > $earliestDate,
]
);
return $config;
}
}
10 changes: 8 additions & 2 deletions classes/services/queryBuilders/PKPStatsSushiQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ public function getSum(array $groupBy = []): Builder
$q->leftJoin('publications as p', function ($q) {
$q->on('p.submission_id', '=', 'm.submission_id')
->whereIn('p.publication_id', function ($q) {
$q->selectRaw('MIN(p2.publication_id)')->from('publications as p2')->where('p2.status', Submission::STATUS_PUBLISHED);
$q->selectRaw('MIN(p2.publication_id)')
->from('publications as p2')
->where('p2.status', Submission::STATUS_PUBLISHED)
->where('p2.submission_id', '=', DB::raw('m.submission_id'));
});
});
}
Expand Down Expand Up @@ -123,7 +126,10 @@ protected function _getObject(): Builder
$q->leftJoin('publications as p', function ($q) {
$q->on('p.submission_id', '=', 'm.submission_id')
->whereIn('p.publication_id', function ($q) {
$q->selectRaw('MIN(p2.publication_id)')->from('publications as p2')->where('p2.status', Submission::STATUS_PUBLISHED);
$q->selectRaw('MIN(p2.publication_id)')
->from('publications as p2')
->where('p2.status', Submission::STATUS_PUBLISHED)
->where('p2.submission_id', '=', DB::raw('m.submission_id'));
});
});
foreach ($this->yearsOfPublication as $yop) {
Expand Down
Loading

0 comments on commit 1df2f9f

Please sign in to comment.