-
Notifications
You must be signed in to change notification settings - Fork 445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple author affiliations #10460
base: main
Are you sure you want to change the base?
Multiple author affiliations #10460
Changes from all commits
fa1f010
0e13644
60807c9
a8b1bed
b6af604
d772744
58f4abe
08a55c0
81bf90f
1a6ed69
9e359ff
8f0af65
c762570
454b300
44daa68
c4eee42
bcaabf9
d0c6b5c
a0d1d10
758c1a8
5a42adb
bddc094
e2b35ea
51bd801
7f026e2
7b178f5
57a8e60
fd5c090
b52570f
8706bcd
77e6141
4e59a2c
50303e4
a2da59a
a804952
c8a5c7e
93afa41
ff43051
7120f52
9851618
0e4b7a3
f1986b9
bd98be2
771b8b8
858a63a
5073b8b
bc21ee9
46f5f68
4484eb4
00ef141
9a01107
5f254b8
5f7582e
18e00fd
fbc52e8
f7a3f5b
b316f4a
d866254
a12f349
992012a
8049b04
63e2e61
1a0b1fa
17b2316
65c5de5
69be1c2
555df2c
2d6f7ab
067ab1a
8237869
0a2c105
bdf5363
fcc9d41
2137bae
c5e8fde
6218122
6a4d8d7
91079d1
dae710a
a002070
6da506b
dd6ea42
1b76d67
4689bae
af4503f
7676788
7bc5035
f42bc8d
1d7dc88
f022438
a64c28f
1f8abf5
732bd46
2199df7
e3f9938
72f8d73
c1a513b
1606cbc
d490a47
723eba2
c9881ae
e93b597
2a0d842
e82bf5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
<?php | ||
/** | ||
* @file api/v1/rors/PKPRorController.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 PKPRorController | ||
* | ||
* @ingroup api_v1_rors | ||
* | ||
* @brief Controller class to handle API requests for ror operations. | ||
* | ||
*/ | ||
|
||
namespace PKP\API\v1\rors; | ||
|
||
use APP\facades\Repo; | ||
use Illuminate\Http\JsonResponse; | ||
use Illuminate\Http\Request; | ||
use Illuminate\Http\Response; | ||
use Illuminate\Support\Facades\Route; | ||
use PKP\core\PKPBaseController; | ||
use PKP\core\PKPRequest; | ||
use PKP\plugins\Hook; | ||
use PKP\security\authorization\ContextRequiredPolicy; | ||
use PKP\security\authorization\PolicySet; | ||
use PKP\security\authorization\RoleBasedHandlerOperationPolicy; | ||
use PKP\security\authorization\UserRolesRequiredPolicy; | ||
use PKP\security\Role; | ||
|
||
class PKPRorController extends PKPBaseController | ||
{ | ||
/** @var int The default number of rors to return in one request */ | ||
public const DEFAULT_COUNT = 30; | ||
|
||
/** @var int The maximum number of rors to return in one request */ | ||
public const MAX_COUNT = 100; | ||
|
||
/** | ||
* @copydoc \PKP\core\PKPBaseController::getHandlerPath() | ||
*/ | ||
public function getHandlerPath(): string | ||
{ | ||
return 'rors'; | ||
} | ||
|
||
/** | ||
* @copydoc \PKP\core\PKPBaseController::getRouteGroupMiddleware() | ||
*/ | ||
public function getRouteGroupMiddleware(): array | ||
{ | ||
return [ | ||
'has.user', | ||
'has.context', | ||
self::roleAuthorizer([ | ||
Role::ROLE_ID_MANAGER, | ||
]), | ||
]; | ||
} | ||
|
||
/** | ||
* @copydoc \PKP\core\PKPBaseController::getGroupRoutes() | ||
*/ | ||
public function getGroupRoutes(): void | ||
{ | ||
Route::get('{rorId}', $this->get(...)) | ||
->name('ror.getRor') | ||
->whereNumber('rorId'); | ||
|
||
Route::get('', $this->getMany(...)) | ||
->name('ror.getMany'); | ||
} | ||
|
||
/** | ||
* @copydoc \PKP\core\PKPBaseController::authorize() | ||
*/ | ||
public function authorize(PKPRequest $request, array &$args, array $roleAssignments): bool | ||
{ | ||
$this->addPolicy(new UserRolesRequiredPolicy($request), true); | ||
|
||
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES); | ||
|
||
$this->addPolicy(new ContextRequiredPolicy($request)); | ||
|
||
foreach ($roleAssignments as $role => $operations) { | ||
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations)); | ||
} | ||
|
||
$this->addPolicy($rolePolicy); | ||
|
||
return parent::authorize($request, $args, $roleAssignments); | ||
} | ||
|
||
/** | ||
* Get a single ror | ||
*/ | ||
public function get(Request $illuminateRequest): JsonResponse | ||
{ | ||
if (!Repo::ror()->exists((int) $illuminateRequest->route('rorId'), $this->getRequest()->getContext()->getId())) { | ||
return response()->json([ | ||
'error' => __('api.rors.404.rorNotFound') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This locale key seems not to be defined |
||
], Response::HTTP_OK); | ||
} | ||
|
||
$ror = Repo::ror()->get((int) $illuminateRequest->route('rorId')); | ||
|
||
return response()->json(Repo::ror()->getSchemaMap()->map($ror), Response::HTTP_OK); | ||
} | ||
|
||
/** | ||
* Get a collection of rors | ||
* | ||
* @hook API::rors::params [[$collector, $illuminateRequest]] | ||
*/ | ||
public function getMany(Request $illuminateRequest): JsonResponse | ||
{ | ||
$collector = Repo::ror()->getCollector() | ||
->limit(self::DEFAULT_COUNT) | ||
->offset(0); | ||
|
||
foreach ($illuminateRequest->query() as $param => $val) { | ||
switch ($param) { | ||
case 'count': | ||
$collector->limit(min((int) $val, self::MAX_COUNT)); | ||
break; | ||
case 'offset': | ||
$collector->offset((int) $val); | ||
break; | ||
case 'searchPhrase': | ||
$collector->filterBySearchPhrase($val); | ||
break; | ||
} | ||
} | ||
|
||
Hook::call('API::rors::params', [$collector, $illuminateRequest]); | ||
|
||
$rors = $collector->getMany(); | ||
|
||
return response()->json([ | ||
'itemsMax' => $collector->getCount(), | ||
'items' => Repo::ror()->getSchemaMap()->summarizeMany($rors->values())->values(), | ||
], Response::HTTP_OK); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,8 @@ | |
/** | ||
* @file api/v1/submissions/PKPSubmissionController.php | ||
* | ||
* Copyright (c) 2023 Simon Fraser University | ||
* Copyright (c) 2023 John Willinsky | ||
* Copyright (c) 2023-2024 Simon Fraser University | ||
* Copyright (c) 2023-2024 John Willinsky | ||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. | ||
* | ||
* @class PKPSubmissionController | ||
|
@@ -666,7 +666,7 @@ public function add(Request $illuminateRequest): JsonResponse | |
|
||
// Create an author record from the submitter's user account | ||
if ($submitAsUserGroup->getRoleId() === Role::ROLE_ID_AUTHOR) { | ||
$author = Repo::author()->newAuthorFromUser($request->getUser()); | ||
$author = Repo::author()->newAuthorFromUser($request->getUser(), $submission->getDefaultLocale()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second parameter for the funciton See also the comments at the function |
||
$author->setData('publicationId', $publication->getId()); | ||
$author->setUserGroupId($submitAsUserGroup->getId()); | ||
$authorId = Repo::author()->add($author); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
/** | ||
* @file classes/affiliation/Affiliation.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 Affiliation | ||
* | ||
* @ingroup affiliation | ||
* | ||
* @see DAO | ||
* | ||
* @brief Basic class describing a affiliation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. an affiliation ? |
||
*/ | ||
|
||
namespace PKP\affiliation; | ||
|
||
use PKP\core\DataObject; | ||
|
||
class Affiliation extends DataObject | ||
{ | ||
/** | ||
* Get author id | ||
*/ | ||
public function getAuthorId() | ||
{ | ||
return $this->getData('authorId'); | ||
} | ||
|
||
/** | ||
* Get the ROR | ||
* | ||
* @return string|null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to have it here, when we have |
||
*/ | ||
public function getROR(): ?string | ||
{ | ||
return $this->getData('ror'); | ||
} | ||
|
||
/** @copydoc DataObject::getLocalizedGivenName() */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is not in DataObject. Maybe to describe the function anew -- it is not based on another function... |
||
public function getLocalizedName(): mixed | ||
{ | ||
return $this->getLocalizedData('name'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
<?php | ||
/** | ||
* @file classes/affiliation/Collector.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 Collector | ||
* | ||
* @brief A helper class to configure a Query Builder to get a collection of rors | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. collection of affiliations |
||
*/ | ||
|
||
namespace PKP\affiliation; | ||
|
||
use Illuminate\Database\Query\Builder; | ||
use Illuminate\Support\Collection; | ||
use Illuminate\Support\Facades\DB; | ||
use Illuminate\Support\LazyCollection; | ||
use PKP\core\interfaces\CollectorInterface; | ||
use PKP\plugins\Hook; | ||
|
||
/** | ||
* @template T of Affiliation | ||
*/ | ||
class Collector implements CollectorInterface | ||
{ | ||
/** @var DAO */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need to have this? |
||
public DAO $dao; | ||
|
||
public ?int $count = null; | ||
|
||
public ?int $offset = null; | ||
|
||
/** @var int[]|null */ | ||
public ?array $authorIds = null; | ||
|
||
/** Get affiliations with a name */ | ||
public ?string $name = null; | ||
|
||
public ?string $searchPhrase = null; | ||
|
||
public function __construct(DAO $dao) | ||
{ | ||
$this->dao = $dao; | ||
} | ||
|
||
public function getCount(): int | ||
{ | ||
return $this->dao->getCount($this); | ||
} | ||
|
||
/** | ||
* @return Collection<int,int> | ||
*/ | ||
public function getIds(): Collection | ||
{ | ||
return $this->dao->getIds($this); | ||
} | ||
|
||
/** | ||
* @copydoc DAO::getMany() | ||
* | ||
* @return LazyCollection<int,T> | ||
*/ | ||
public function getMany(): LazyCollection | ||
{ | ||
return $this->dao->getMany($this); | ||
} | ||
|
||
/** | ||
* Filter by authors | ||
*/ | ||
public function filterByAuthorIds(?array $authorIds): self | ||
{ | ||
$this->authorIds = $authorIds; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Filter by affiliation name. | ||
* | ||
* @param string|null $name | ||
* | ||
* @return $this | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
*/ | ||
public function filterByName(?string $name): self | ||
{ | ||
$this->name = $name; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Filter rors by those matching a search query | ||
*/ | ||
public function searchPhrase(?string $phrase): self | ||
{ | ||
$this->searchPhrase = $phrase; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Limit the number of objects retrieved | ||
*/ | ||
public function limit(?int $count): self | ||
{ | ||
$this->count = $count; | ||
return $this; | ||
} | ||
|
||
/** | ||
* Offset the number of objects retrieved, for example to | ||
* retrieve the second page of contents | ||
*/ | ||
public function offset(?int $offset): self | ||
{ | ||
$this->offset = $offset; | ||
return $this; | ||
} | ||
|
||
/** | ||
* @copydoc CollectorInterface::getQueryBuilder() | ||
*/ | ||
public function getQueryBuilder(): Builder | ||
{ | ||
$qb = DB::table($this->dao->table . ' as a') | ||
->select('a.*'); | ||
|
||
if (!is_null($this->count)) { | ||
$qb->limit($this->count); | ||
} | ||
|
||
if (!is_null($this->offset)) { | ||
$qb->offset($this->offset); | ||
} | ||
|
||
if (!is_null($this->authorIds)) { | ||
$qb->whereIn('a.author_id', $this->authorIds); | ||
} | ||
|
||
$qb->when($this->name !== null, function (Builder $qb) { | ||
$qb->whereIn('a.author_affiliation_id', function (Builder $qb) { | ||
$qb->select('author_affiliation_id') | ||
->from($this->dao->settingsTable) | ||
->where('setting_name', '=', 'name') | ||
->where('setting_value', $this->name); | ||
}); | ||
}); | ||
|
||
// Add app-specific query statements | ||
Hook::call('Affiliation::Collector', [&$qb, $this]); | ||
|
||
return $qb; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the DB table
rors
does not contain context_id -- the RORs are not connected with the context (journal, press, server), right?Thus, I think we would need to implement that function
exists()
so that it only looks if the ror_id exists. (Also no need for that ror DAO to use the trait EntityWithParent -- I will add the comment there too.)