Skip to content
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

Open
wants to merge 104 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
fa1f010
Eloquent model
GaziYucel Sep 20, 2024
0e13644
UI (work in progress)
GaziYucel Sep 20, 2024
60807c9
UI (work in progress)
GaziYucel Sep 20, 2024
a8b1bed
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Sep 23, 2024
b6af604
vuejs skeletion
GaziYucel Sep 23, 2024
d772744
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Sep 24, 2024
58f4abe
multiple-author-affiliations
GaziYucel Sep 24, 2024
08a55c0
Author Affiliations (work in progress)
GaziYucel Sep 26, 2024
81bf90f
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Sep 27, 2024
1a6ed69
Author Affiliations (work in progress)
GaziYucel Sep 27, 2024
9e359ff
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Sep 29, 2024
8f0af65
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 2, 2024
c762570
Author affiliations (work in progress)
GaziYucel Oct 3, 2024
454b300
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 4, 2024
44daa68
Author affiliations locale (work in progress)
GaziYucel Oct 4, 2024
c4eee42
Author affiliations locale (work in progress)
GaziYucel Oct 4, 2024
bcaabf9
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 7, 2024
d0c6b5c
get / set affiliation moved from identity to author and user
GaziYucel Oct 7, 2024
a0d1d10
Typo fixed PKP\affiliation\Affiliation > PKP\affiliation\Repository
GaziYucel Oct 7, 2024
758c1a8
Refactor AuthorAffiliations to Affiliations
GaziYucel Oct 7, 2024
5a42adb
Migration scripts
GaziYucel Oct 7, 2024
bddc094
Author Affiliations (work in progress)
GaziYucel Oct 7, 2024
e2b35ea
Author Affiliations (work in progress)
GaziYucel Oct 7, 2024
51bd801
Author Affiliations (work in progress)
GaziYucel Oct 7, 2024
7f026e2
Author Affiliations (work in progress)
GaziYucel Oct 7, 2024
7b178f5
Author affiliations (work in progress)
GaziYucel Oct 7, 2024
57a8e60
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 8, 2024
fd5c090
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
b52570f
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
8706bcd
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
77e6141
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
4e59a2c
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
50303e4
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
a2da59a
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
a804952
Author Affiliations (work in progress)
GaziYucel Oct 8, 2024
c8a5c7e
Author affiliations (work in progress)
GaziYucel Oct 8, 2024
93afa41
Author affiliations (work in progress)
GaziYucel Oct 8, 2024
ff43051
Author affiliations (work in progress)
GaziYucel Oct 9, 2024
7120f52
Author Affiliations (work in progress)
GaziYucel Oct 9, 2024
9851618
Author Affiliations (work in progress)
GaziYucel Oct 9, 2024
0e4b7a3
Author affiliations (work in progress)
GaziYucel Oct 9, 2024
f1986b9
Author Affiliations (work in progress)
GaziYucel Oct 9, 2024
bd98be2
Author affiliations (work in progress)
GaziYucel Oct 9, 2024
771b8b8
Author affiliations (work in progress)
GaziYucel Oct 9, 2024
858a63a
Author affiliations (work in progress)
GaziYucel Oct 9, 2024
5073b8b
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 10, 2024
bc21ee9
Author affiliations (work in progress)
GaziYucel Oct 10, 2024
46f5f68
Author Affiliations (work in progress)
GaziYucel Oct 10, 2024
4484eb4
Author Affiliations (work in progress)
GaziYucel Oct 10, 2024
00ef141
Author Affiliations (work in progress)
GaziYucel Oct 10, 2024
9a01107
Merge branch 'multiple-author-affiliations' of https://github.com/Gaz…
GaziYucel Oct 10, 2024
5f254b8
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 10, 2024
5f7582e
Merge branch 'multiple-author-affiliations' of https://github.com/Gaz…
GaziYucel Oct 10, 2024
18e00fd
ror-registry-data-cache
GaziYucel Oct 10, 2024
fbc52e8
Copyright year
GaziYucel Oct 10, 2024
f7a3f5b
Move position under biography
GaziYucel Oct 10, 2024
b316f4a
Whitespace
GaziYucel Oct 10, 2024
d866254
fixme: multiple-author-affiliations
GaziYucel Oct 10, 2024
a12f349
Make ror non required; isActive removed, should not be there
GaziYucel Oct 14, 2024
992012a
fixme: does not save is affiliations list is empty
GaziYucel Oct 14, 2024
8049b04
Merge conflict
GaziYucel Oct 21, 2024
63e2e61
Merge conflict
GaziYucel Oct 21, 2024
1a0b1fa
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 21, 2024
17b2316
Merge conflict reapply
GaziYucel Oct 21, 2024
65c5de5
Update ror data set cache after migration
GaziYucel Oct 21, 2024
69be1c2
Save empty affiliations; Form config currentLocale and supportedLocales
GaziYucel Oct 21, 2024
555df2c
Default value if null
GaziYucel Oct 21, 2024
2d6f7ab
Translations
GaziYucel Oct 21, 2024
067ab1a
saveAffiliations: insert, update, delete
GaziYucel Oct 21, 2024
8237869
Migrate affiliations to multiple affiliations
GaziYucel Oct 22, 2024
0a2c105
Migrate affiliations to multiple affiliations (finished)
GaziYucel Oct 22, 2024
bdf5363
Typo
GaziYucel Oct 23, 2024
fcc9d41
Typo
GaziYucel Oct 23, 2024
2137bae
Sort supported locales
GaziYucel Oct 23, 2024
c5e8fde
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 23, 2024
6218122
translations english
GaziYucel Oct 24, 2024
6a4d8d7
query name search => searchPhrase
GaziYucel Oct 24, 2024
91079d1
_data removed
GaziYucel Oct 24, 2024
dae710a
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 24, 2024
a002070
"_data" removed from api response
GaziYucel Oct 24, 2024
6da506b
remove temporary file
GaziYucel Oct 25, 2024
dd6ea42
displayLocale removed from schema
GaziYucel Oct 25, 2024
1b76d67
Bug fix
GaziYucel Oct 25, 2024
4689bae
copyright fix; phpdoc
GaziYucel Oct 25, 2024
af4503f
get mapped to schema
GaziYucel Oct 25, 2024
7676788
locale display names
GaziYucel Oct 25, 2024
7bc5035
Map affiliations to schema
GaziYucel Oct 25, 2024
f42bc8d
More places fixme: multiple-author-affiliations
GaziYucel Oct 25, 2024
1d7dc88
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 28, 2024
f022438
Multiple fixme issues implemented, cleanup, copyright
GaziYucel Oct 28, 2024
a64c28f
Multiple fixme issues implemented, cleanup, copyright
GaziYucel Oct 28, 2024
1f8abf5
setAffiliationsFromString for NativeXmlPKPAuthorFilter
GaziYucel Oct 29, 2024
732bd46
setAffiliationsFromString for NativeXmlPKPAuthorFilter
GaziYucel Oct 29, 2024
2199df7
Merge branch 'multiple-author-affiliations' of https://github.com/Gaz…
GaziYucel Oct 29, 2024
e3f9938
Error creating tables: foreign key first, then indexes.
GaziYucel Oct 29, 2024
72f8d73
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Oct 30, 2024
c1a513b
Typo
GaziYucel Nov 1, 2024
1606cbc
Map affiliations to schema
GaziYucel Nov 1, 2024
d490a47
Merge branch 'pkp:main' into multiple-author-affiliations
GaziYucel Nov 4, 2024
723eba2
Copyright years fixed
GaziYucel Nov 4, 2024
c9881ae
AdvancedSearchReviewerForm
GaziYucel Nov 5, 2024
e93b597
Separator changed from ", " to "; "
GaziYucel Nov 7, 2024
2a0d842
Review changes (work in progress)
GaziYucel Nov 7, 2024
e82bf5a
Fix: no need to index foreign key column
GaziYucel Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions api/v1/rors/PKPRorController.php
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())) {
Copy link
Collaborator

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.)

return response()->json([
'error' => __('api.rors.404.rorNotFound')
Copy link
Collaborator

Choose a reason for hiding this comment

The 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);
}
}
6 changes: 3 additions & 3 deletions api/v1/submissions/PKPSubmissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second parameter for the funciton newAuthorFromUser should be all allowed locales for this submission, i.e. something like:
$allowedLocales = $submission->getPublicationLanguages($this->context->getSupportedSubmissionMetadataLocales());

See also the comments at the function newAuthorFromUser implementation.

$author->setData('publicationId', $publication->getId());
$author->setUserGroupId($submitAsUserGroup->getId());
$authorId = Repo::author()->add($author);
Expand Down
47 changes: 47 additions & 0 deletions classes/affiliation/Affiliation.php
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.
Copy link
Collaborator

Choose a reason for hiding this comment

The 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have it here, when we have : ?string

*/
public function getROR(): ?string
{
return $this->getData('ror');
}

/** @copydoc DataObject::getLocalizedGivenName() */
Copy link
Collaborator

Choose a reason for hiding this comment

The 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');
}
}
155 changes: 155 additions & 0 deletions classes/affiliation/Collector.php
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
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 */
Copy link
Collaborator

Choose a reason for hiding this comment

The 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for @param and @return -- only if we want need to describe it specially

*/
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;
}
}
Loading