Skip to content

Commit b512e39

Browse files
authored
Merge pull request #12000 from bozana/11902
#11902 Structured citations improvements
2 parents 222d16a + 3dd6b47 commit b512e39

29 files changed

+450
-298
lines changed

api/v1/citations/PKPCitationController.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
use Illuminate\Http\Request;
2323
use Illuminate\Http\Response;
2424
use Illuminate\Support\Facades\Route;
25+
use PKP\citation\enum\CitationProcessingStatus;
26+
use PKP\citation\pid\Arxiv;
27+
use PKP\citation\pid\Doi;
28+
use PKP\citation\pid\Handle;
2529
use PKP\core\PKPBaseController;
2630
use PKP\core\PKPRequest;
2731
use PKP\plugins\Hook;
@@ -173,6 +177,19 @@ public function edit(Request $illuminateRequest): JsonResponse
173177

174178
$params = $this->convertStringsToSchema(PKPSchemaService::SCHEMA_CITATION, $illuminateRequest->input());
175179

180+
$arxiv = Arxiv::extractFromString($params['arxiv']);
181+
if (!empty($arxiv)) {
182+
$params['arxiv'] = $arxiv;
183+
}
184+
$doi = Doi::extractFromString($params['doi']);
185+
if (!empty($doi)) {
186+
$params['doi'] = $doi;
187+
}
188+
$handle = Handle::extractFromString($params['handle']);
189+
if (!empty($handle)) {
190+
$params['handle'] = $handle;
191+
}
192+
176193
$readOnlyErrors = $this->getWriteDisabledErrors(PKPSchemaService::SCHEMA_CITATION, $params);
177194
if (!empty($readOnlyErrors)) {
178195
return response()->json($readOnlyErrors, Response::HTTP_BAD_REQUEST);
@@ -190,7 +207,8 @@ public function edit(Request $illuminateRequest): JsonResponse
190207
$citation = Repo::citation()->get($citation->getId());
191208

192209
return response()->json(
193-
Repo::citation()->getSchemaMap()->map($citation), Response::HTTP_OK
210+
Repo::citation()->getSchemaMap()->map($citation),
211+
Response::HTTP_OK
194212
);
195213
}
196214

@@ -210,7 +228,8 @@ public function delete(Request $illuminateRequest): JsonResponse
210228
Repo::citation()->delete($citation);
211229

212230
return response()->json(
213-
Repo::citation()->getSchemaMap()->map($citation), Response::HTTP_OK
231+
Repo::citation()->getSchemaMap()->map($citation),
232+
Response::HTTP_OK
214233
);
215234
}
216235

@@ -227,13 +246,14 @@ public function reprocessCitation(Request $illuminateRequest): JsonResponse
227246
], Response::HTTP_NOT_FOUND);
228247
}
229248

230-
$citation->setIsProcessed(false);
249+
$citation->setProcessingStatus(CitationProcessingStatus::NOT_PROCESSED->value);
231250
Repo::citation()->edit($citation, []);
232251

233252
Repo::citation()->reprocessCitation($citation);
234253

235254
return response()->json(
236-
Repo::citation()->getSchemaMap()->map($citation), Response::HTTP_OK
255+
Repo::citation()->getSchemaMap()->map($citation),
256+
Response::HTTP_OK
237257
);
238258
}
239259

api/v1/submissions/PKPSubmissionController.php

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use Illuminate\Validation\Rule;
3838
use PKP\affiliation\Affiliation;
3939
use PKP\citation\Citation;
40+
use PKP\citation\enum\CitationProcessingStatus;
4041
use PKP\components\forms\FormComponent;
4142
use PKP\components\forms\publication\PKPMetadataForm;
4243
use PKP\components\forms\publication\PKPPublicationIdentifiersForm;
@@ -121,8 +122,8 @@ class PKPSubmissionController extends PKPBaseController
121122
'changeVersion',
122123
'getNextAvailableVersion',
123124
'importAdditionalCitations',
124-
'editCitationsMetadataLookup',
125125
'deleteCitationsByPublicationId',
126+
'reprocessCitationsByPublicationId'
126127
];
127128

128129
/** @var array Handlers that must be authorized to write to a publication */
@@ -371,17 +372,17 @@ public function getGroupRoutes(): void
371372
Role::ROLE_ID_AUTHOR,
372373
]),
373374
])->group(function () {
374-
Route::put('{submissionId}/publications/{publicationId}/citations/metadataLookup', $this->editCitationsMetadataLookup(...))
375-
->name('submission.citations.import')
376-
->whereNumber(['submissionId', 'publicationId']);
377-
378375
Route::post('{submissionId}/publications/{publicationId}/citations/importAdditionalCitations', $this->importAdditionalCitations(...))
379376
->name('submission.citations.import')
380377
->whereNumber(['submissionId', 'publicationId']);
381378

382379
Route::delete('{submissionId}/publications/{publicationId}/citations/deleteCitationsByPublicationId', $this->deleteCitationsByPublicationId(...))
383380
->name('submission.citations.delete')
384381
->whereNumber(['submissionId', 'publicationId']);
382+
383+
Route::post('{submissionId}/publications/{publicationId}/citations/reprocessCitationsByPublicationId', $this->reprocessCitationsByPublicationId(...))
384+
->name('submission.citations.reprocess')
385+
->whereNumber(['submissionId', 'publicationId']);
385386
});
386387
}
387388

@@ -2335,9 +2336,9 @@ protected function validateVersionIsMinor(Request $illuminateRequest): ?bool
23352336
}
23362337

23372338
/**
2338-
* Update citationsMetadataLookup of a publication, reprocess citations if enabled.
2339+
* Import / add citations from a raw citation string of a publication.
23392340
*/
2340-
protected function editCitationsMetadataLookup(Request $illuminateRequest): JsonResponse
2341+
protected function importAdditionalCitations(Request $illuminateRequest): JsonResponse
23412342
{
23422343
$publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId'));
23432344

@@ -2365,39 +2366,17 @@ protected function editCitationsMetadataLookup(Request $illuminateRequest): Json
23652366
], Response::HTTP_FORBIDDEN);
23662367
}
23672368

2368-
$citationsMetadataLookup = (bool)$illuminateRequest->input('citationsMetadataLookup');
2369-
2370-
$processCitation = false;
2371-
if ($citationsMetadataLookup && !$publication->getData('citationsMetadataLookup')) {
2372-
$processCitation = true;
2373-
}
2374-
2375-
/** @var Citation $citation */
2376-
foreach ($publication->getData('citations') as &$citation) {
2377-
$citation->setIsProcessed(!$processCitation);
2378-
if ($processCitation) {
2379-
Repo::citation()->reprocessCitation($citation);
2380-
}
2381-
}
2382-
unset($citation);
2383-
2384-
$publication->setData('citationsMetadataLookup', $citationsMetadataLookup);
2385-
Repo::publication()->edit($publication, []);
2369+
$rawCitations = (string)$illuminateRequest->input('rawCitations');
23862370

2387-
$publication = Repo::publication()->get($publication->getId());
2371+
$result = Repo::citation()->importAdditionalCitations($publication->getId(), $rawCitations);
23882372

2389-
return response()->json(
2390-
[
2391-
'citationsMetadataLookup' => $publication->getData('citationsMetadataLookup')
2392-
],
2393-
Response::HTTP_OK
2394-
);
2373+
return response()->json($result, Response::HTTP_OK);
23952374
}
23962375

23972376
/**
2398-
* Import / add citations from a raw citation string of a publication.
2377+
* Delete a publication's citations.
23992378
*/
2400-
protected function importAdditionalCitations(Request $illuminateRequest): JsonResponse
2379+
protected function deleteCitationsByPublicationId(Request $illuminateRequest): JsonResponse
24012380
{
24022381
$publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId'));
24032382

@@ -2425,17 +2404,24 @@ protected function importAdditionalCitations(Request $illuminateRequest): JsonRe
24252404
], Response::HTTP_FORBIDDEN);
24262405
}
24272406

2428-
$rawCitations = (string)$illuminateRequest->input('rawCitations');
2407+
$existingCitations = [];
2408+
/** @var Citation $citation */
2409+
foreach ($publication->getData('citations') as $citation) {
2410+
$existingCitations[] = Repo::citation()->getSchemaMap()->map($citation);
2411+
}
24292412

2430-
$result = Repo::citation()->importAdditionalCitations($publication->getId(), $rawCitations);
2413+
Repo::citation()->deleteByPublicationId($publication->getId());
24312414

2432-
return response()->json($result, Response::HTTP_OK);
2415+
return response()->json([
2416+
'itemsMax' => count($existingCitations),
2417+
'items' => $existingCitations
2418+
], Response::HTTP_OK);
24332419
}
24342420

24352421
/**
2436-
* Delete a publication's citations.
2422+
* Reprocess a publication's citations.
24372423
*/
2438-
protected function deleteCitationsByPublicationId(Request $illuminateRequest): JsonResponse
2424+
protected function reprocessCitationsByPublicationId(Request $illuminateRequest): JsonResponse
24392425
{
24402426
$publication = Repo::publication()->get((int)$illuminateRequest->route('publicationId'));
24412427

@@ -2463,17 +2449,19 @@ protected function deleteCitationsByPublicationId(Request $illuminateRequest): J
24632449
], Response::HTTP_FORBIDDEN);
24642450
}
24652451

2466-
$existingCitations = [];
2467-
/** @var Citation $citation */
2468-
foreach ($publication->getData('citations') as $citation) {
2469-
$existingCitations[] = Repo::citation()->getSchemaMap()->map($citation);
2452+
$citations = $publication->getData('citations');
2453+
$citationsMapped = [];
2454+
foreach ($citations as &$citation) {
2455+
$citation->setProcessingStatus(CitationProcessingStatus::NOT_PROCESSED->value);
2456+
Repo::citation()->edit($citation, []);
2457+
Repo::citation()->reprocessCitation($citation);
2458+
$citationsMapped[] = Repo::citation()->getSchemaMap()->map($citation);
24702459
}
2471-
2472-
Repo::citation()->deleteByPublicationId($publication->getId());
2460+
unset($citation);
24732461

24742462
return response()->json([
2475-
'itemsMax' => count($existingCitations),
2476-
'items' => $existingCitations
2463+
'itemsMax' => count($citationsMapped),
2464+
'items' => $citationsMapped
24772465
], Response::HTTP_OK);
24782466
}
24792467
}

classes/citation/Citation.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,19 @@ public function setSequence(int $seq): void
6363
}
6464

6565
/**
66-
* Get isProcessed
66+
* Get processing status
6767
*/
68-
public function getIsProcessed(): bool
68+
public function getProcessingStatus(): int
6969
{
70-
return $this->getData('isProcessed');
70+
return $this->getData('processingStatus');
7171
}
7272

7373
/**
74-
* Set isProcessed
74+
* Set processing status
7575
*/
76-
public function setIsProcessed(bool $isProcessed): void
76+
public function setProcessingStatus(int $processingStatus): void
7777
{
78-
$this->setData('isProcessed', $isProcessed);
78+
$this->setData('processingStatus', $processingStatus);
7979
}
8080

8181
/**

classes/citation/Repository.php

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Illuminate\Support\Collection;
2323
use Illuminate\Support\Facades\App;
2424
use Illuminate\Support\Facades\Bus;
25+
use PKP\citation\enum\CitationProcessingStatus;
2526
use PKP\citation\filter\CitationListTokenizerFilter;
2627
use PKP\jobs\citation\CrossrefJob;
2728
use PKP\jobs\citation\ExtractPidsJob;
@@ -221,18 +222,16 @@ public function importCitations(int $publicationId, ?string $rawCitationList): v
221222
$importedCitations = [];
222223
$this->deleteByPublicationId($publicationId);
223224
if (is_array($citationStrings) && !empty($citationStrings)) {
224-
$publication = Repo::publication()->get($publicationId);
225225
foreach ($citationStrings as $seq => $rawCitationString) {
226226
if (!empty($rawCitationString)) {
227227
$citation = new Citation();
228228
$citation->setRawCitation($rawCitationString);
229229
$citation->setData('publicationId', $publicationId);
230230
$citation->setSequence($seq + 1);
231-
$citation->setIsProcessed(false);
231+
$citation->setProcessingStatus(CitationProcessingStatus::NOT_PROCESSED->value);
232232
$newCitationId = $this->dao->insert($citation);
233233
$citation->setId($newCitationId);
234-
if ($publication->getData('citationsMetadataLookup') ||
235-
(is_null($publication->getData('citationsMetadataLookup')) && $this->request->getContext()->getData('citationsMetadataLookup'))) {
234+
if ($this->request->getContext()->getData('citationsMetadataLookup')) {
236235
$this->reprocessCitation($citation);
237236
}
238237
$importedCitations[] = $citation;
@@ -256,7 +255,6 @@ public function importAdditionalCitations(int $publicationId, ?string $rawCitati
256255

257256
$rejectedCitations = [];
258257
if (is_array($citationStrings) && !empty($citationStrings)) {
259-
$publication = Repo::publication()->get($publicationId);
260258
foreach ($citationStrings as $rawCitationString) {
261259
if (!empty($rawCitationString)) {
262260
if (!$this->existsRawCitation($publicationId, $rawCitationString)) {
@@ -265,11 +263,10 @@ public function importAdditionalCitations(int $publicationId, ?string $rawCitati
265263
$citation->setRawCitation($rawCitationString);
266264
$citation->setData('publicationId', $publicationId);
267265
$citation->setSequence($lastSeq);
268-
$citation->setIsProcessed(false);
266+
$citation->setProcessingStatus(CitationProcessingStatus::NOT_PROCESSED->value);
269267
$newCitationId = $this->dao->insert($citation);
270268
$citation->setId($newCitationId);
271-
if ($publication->getData('citationsMetadataLookup') ||
272-
(is_null($publication->getData('citationsMetadataLookup')) && $this->request->getContext()->getData('citationsMetadataLookup'))) {
269+
if ($this->request->getContext()->getData('citationsMetadataLookup')) {
273270
$this->reprocessCitation($citation);
274271
}
275272
} else {
@@ -317,6 +314,7 @@ public function reprocessCitation(Citation $citation): void
317314

318315
Bus::chain($jobs)
319316
->catch(function (Throwable $e) {
317+
error_log($e->getMessage());
320318
})
321319
->dispatch();
322320
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/**
4+
* @file classes/citation/enum/CitationProcessingStatus.php
5+
*
6+
* Copyright (c) 2025 Simon Fraser University
7+
* Copyright (c) 2025 John Willinsky
8+
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
9+
*
10+
* @class CitationProcessingStatus
11+
*
12+
* @ingroup citation
13+
*
14+
* @brief Enumeration for citation processing status.
15+
*/
16+
17+
namespace PKP\citation\enum;
18+
19+
enum CitationProcessingStatus: int
20+
{
21+
case NOT_PROCESSED = 0;
22+
case PID_EXTRACTED = 1;
23+
case CROSSREF = 2;
24+
case OPEN_ALEX = 3;
25+
case ORCID = 4;
26+
case PROCESSED = 5;
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/**
4+
* @file classes/citation/enum/CitationSourceType.php
5+
*
6+
* Copyright (c) 2025 Simon Fraser University
7+
* Copyright (c) 2025 John Willinsky
8+
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
9+
*
10+
* @class CitationSourceType
11+
*
12+
* @ingroup citation
13+
*
14+
* @brief Enumeration for citation source types.
15+
*/
16+
17+
namespace PKP\citation\enum;
18+
19+
enum CitationSourceType: string
20+
{
21+
case BOOK_SERIES = 'book series';
22+
case CONFERENCE = 'conference';
23+
case EBOOK_PLATFORM = 'ebook platform';
24+
case JOURNAL = 'journal';
25+
case METADATA = 'metadata';
26+
case OTHER = 'other';
27+
case REPOSITORY = 'repository';
28+
}

0 commit comments

Comments
 (0)