first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-06-08 17:09:23 -04:00
commit df3a033196
17887 changed files with 8637778 additions and 0 deletions
@@ -0,0 +1,476 @@
<?php
/**
* @file controllers/grid/users/author/AuthorGridHandler.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class AuthorGridHandler
*
* @ingroup controllers_grid_users_author
*
* @deprecated 3.4
*
* @brief base PKP class to handle author grid requests.
*/
namespace PKP\controllers\grid\users\author;
use APP\controllers\grid\users\author\form\AuthorForm;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use PKP\controllers\grid\feature\OrderGridItemsFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\settings\user\form\UserDetailsForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\notification\PKPNotification;
use PKP\security\authorization\PublicationAccessPolicy;
use PKP\security\Role;
use PKP\submission\PKPSubmission;
use PKP\user\User;
class AuthorGridHandler extends GridHandler
{
/** @var bool */
public $_readOnly;
/** @var int */
public $_version;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow', 'addAuthor', 'editAuthor',
'updateAuthor', 'deleteAuthor', 'saveSequence']
);
$this->addRoleAssignment(Role::ROLE_ID_REVIEWER, ['fetchGrid', 'fetchRow']);
$this->addRoleAssignment([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT], ['addUser']);
}
//
// Getters/Setters
//
/**
* Get the submission associated with this author grid.
*
* @return Submission
*/
public function getSubmission()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
}
/**
* Get the publication associated with this author grid.
*
* @return Submission
*/
public function getPublication()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_PUBLICATION);
}
/**
* Get whether or not this grid should be 'read only'
*
* @return bool
*/
public function getReadOnly()
{
return $this->_readOnly;
}
/**
* Set the boolean for 'read only' status
*
* @param bool $readOnly
*/
public function setReadOnly($readOnly)
{
$this->_readOnly = $readOnly;
}
//
// Overridden methods from PKPHandler.
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new PublicationAccessPolicy($request, $args, $roleAssignments));
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$this->setTitle('submission.contributors');
if ($this->getSubmission()->getData('submissionProgress') || $this->canAdminister($request->getUser())) {
$this->setReadOnly(false);
// Grid actions
$router = $request->getRouter();
$actionArgs = $this->getRequestArgs();
$this->addAction(
new LinkAction(
'addAuthor',
new AjaxModal(
$router->url($request, null, null, 'addAuthor', null, $actionArgs),
__('grid.action.addContributor'),
'modal_add_user'
),
__('grid.action.addContributor'),
'add_user'
)
);
} else {
$this->setReadOnly(true);
}
// Columns
$cellProvider = new PKPAuthorGridCellProvider($this->getPublication());
$this->addColumn(
new GridColumn(
'name',
'author.users.contributor.name',
null,
null,
$cellProvider,
['width' => 40, 'alignment' => GridColumn::COLUMN_ALIGNMENT_LEFT]
)
);
$this->addColumn(
new GridColumn(
'email',
'author.users.contributor.email',
null,
null,
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'role',
'author.users.contributor.role',
null,
null,
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'principalContact',
'author.users.contributor.principalContact',
null,
'controllers/grid/users/author/primaryContact.tpl',
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'includeInBrowse',
'author.users.contributor.includeInBrowse',
null,
'controllers/grid/users/author/includeInBrowse.tpl',
$cellProvider
)
);
}
//
// Overridden methods from GridHandler
//
/**
* @see GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
$features = parent::initFeatures($request, $args);
if ($this->canAdminister($request->getUser())) {
$features[] = new OrderGridItemsFeature();
}
return $features;
}
/**
* @copydoc GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($gridDataElement)
{
return $gridDataElement->getSequence();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence)
{
if (!$this->canAdminister($request->getUser())) {
return;
}
$author = Repo::author()->get((int) $rowId, $this->getPublication()->getId());
Repo::author()->edit($author, ['seq' => $newSequence]);
}
/**
* @copydoc GridHandler::getRowInstance()
*
* @return AuthorGridRow
*/
protected function getRowInstance()
{
return new AuthorGridRow($this->getSubmission(), $this->getPublication(), $this->getReadOnly());
}
/**
* Get the arguments that will identify the data in the grid.
* Overridden by child grids.
*
* @return array
*/
public function getRequestArgs()
{
$submission = $this->getSubmission();
$publication = $this->getPublication();
return [
'submissionId' => $submission->getId(),
'publicationId' => $publication->getId()
];
}
/**
* Determines if there should be add/edit actions on this grid.
*
* @param User $user
*
* @return bool
*/
public function canAdminister($user)
{
$publication = $this->getPublication();
$submission = $this->getSubmission();
$userRoles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES);
if ($publication->getData('status') === PKPSubmission::STATUS_PUBLISHED) {
return false;
}
if (in_array(Role::ROLE_ID_SITE_ADMIN, $userRoles)) {
return true;
}
// Incomplete submissions can be edited. (Presumably author.)
if ($submission->getDateSubmitted() == null) {
return true;
}
// The user may not be allowed to edit the metadata
if (Repo::submission()->canEditPublication($submission->getId(), $user->getId())) {
return true;
}
// Default: Read-only.
return false;
}
/**
* @copydoc GridHandler::loadData()
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
return Repo::author()
->getCollector()
->filterByPublicationIds([$this->getPublication()->getId()])
->orderBy(Repo::author()->getCollector()::ORDERBY_SEQUENCE)
->getMany();
}
//
// Public Author Grid Actions
//
/**
* An action to manually add a new author
*
* @param array $args
* @param PKPRequest $request
*/
public function addAuthor($args, $request)
{
if (!$this->canAdminister($request->getUser())) {
return new JSONMessage(false);
}
// Calling editAuthor() with an empty row id will add
// a new author.
return $this->editAuthor($args, $request);
}
/**
* Edit an author
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editAuthor($args, $request)
{
if (!$this->canAdminister($request->getUser())) {
return new JSONMessage(false);
}
// Identify the author to be updated
$authorId = (int) $request->getUserVar('authorId');
$author = Repo::author()->get($authorId, $this->getPublication()->getId());
// Form handling
$authorForm = new AuthorForm($this->getPublication(), $author);
$authorForm->initData();
return new JSONMessage(true, $authorForm->fetch($request));
}
/**
* Update an author
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateAuthor($args, $request)
{
if (!$this->canAdminister($request->getUser())) {
return new JSONMessage(false);
}
// Identify the author to be updated
$authorId = (int) $request->getUserVar('authorId');
$publication = $this->getPublication();
$author = Repo::author()->get($authorId, $publication->getId());
// Form handling
$authorForm = new AuthorForm($publication, $author);
$authorForm->readInputData();
if ($authorForm->validate()) {
$authorId = $authorForm->execute();
if (!isset($author)) {
// This is a new contributor
$author = Repo::author()->get($authorId, $publication->getId());
// New added author action notification content.
$notificationContent = __('notification.addedAuthor');
} else {
// Author edition action notification content.
$notificationContent = __('notification.editedAuthor');
}
// Create trivial notification.
$currentUser = $request->getUser();
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification($currentUser->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => $notificationContent]);
// Prepare the grid row data
$row = $this->getRowInstance();
$row->setGridId($this->getId());
$row->setId($authorId);
$row->setData($author);
$row->initialize($request);
// Render the row into a JSON response
if ($author->getPrimaryContact()) {
// If this is the primary contact, redraw the whole grid
// so that it takes the checkbox off other rows.
$json = \PKP\db\DAO::getDataChangedEvent();
} else {
$json = \PKP\db\DAO::getDataChangedEvent($authorId);
}
$json->setGlobalEvent('authorsUpdated');
return $json;
} else {
return new JSONMessage(true, $authorForm->fetch($request));
}
}
/**
* Delete a author
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteAuthor($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
if (!$this->canAdminister($request->getUser())) {
return new JSONMessage(false);
}
$authorId = (int) $request->getUserVar('authorId');
$author = Repo::author()->get($authorId, $this->getPublication()->getId());
if (!$author) {
return new JSONMessage(false);
}
Repo::author()->delete($author);
$json = \PKP\db\DAO::getDataChangedEvent($authorId);
$json->setGlobalEvent('authorsUpdated');
return $json;
}
/**
* Add a user with data initialized from an existing author.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function addUser($args, $request)
{
// Identify the author Id.
$authorId = (int) $request->getUserVar('authorId');
$author = Repo::author()->get($authorId, $this->getPublication()->getId());
if ($author !== null && Repo::user()->getByEmail($author->getEmail(), true)) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userForm = new UserDetailsForm($request, null, $author);
$userForm->attachValidationChecks($request)->initData();
return new JSONMessage(true, $userForm->display($request));
}
}
@@ -0,0 +1,185 @@
<?php
/**
* @file controllers/grid/users/author/AuthorGridRow.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class AuthorGridRow
*
* @ingroup controllers_grid_users_author
*
* @deprecated 3.4
*
* @brief Base class for author grid row definition
*/
namespace PKP\controllers\grid\users\author;
use APP\facades\Repo;
use APP\publication\Publication;
use APP\submission\Submission;
use PKP\controllers\grid\GridRow;
use PKP\core\PKPRequest;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class AuthorGridRow extends GridRow
{
/** @var Submission */
public $_submission;
/** @var Publication */
public $_publication;
/** @var bool */
public $_readOnly;
/** @var int */
public $_version;
/**
* Constructor
*/
public function __construct($submission, $publication, $readOnly = false)
{
$this->_submission = $submission;
$this->_publication = $publication;
$this->_readOnly = $readOnly;
parent::__construct();
}
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
// Do the default initialization
parent::initialize($request, $template);
// Is this a new row or an existing row?
$rowId = $this->getId();
if (!empty($rowId) && is_numeric($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
$actionArgs = $this->getRequestArgs();
$actionArgs['authorId'] = $rowId;
if (!$this->isReadOnly()) {
// Add row-level actions
$this->addAction(
new LinkAction(
'editAuthor',
new AjaxModal(
$router->url($request, null, null, 'editAuthor', null, $actionArgs),
__('grid.action.editContributor'),
'modal_edit'
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'deleteAuthor',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.delete'),
$router->url($request, null, null, 'deleteAuthor', null, $actionArgs),
'modal_delete'
),
__('grid.action.delete'),
'delete'
)
);
$author = Repo::author()->get((int) $rowId, $this->getPublication()->getId());
if ($author && !Repo::user()->getByEmail($author->getEmail(), true)) {
$this->addAction(
new LinkAction(
'addUser',
new AjaxModal(
$router->url($request, null, null, 'addUser', null, $actionArgs),
__('grid.user.add'),
'modal_add_user',
true
),
__('grid.user.add'),
'add_user'
)
);
}
}
}
}
/**
* Get the submission for this row (already authorized)
*
* @return Submission
*/
public function getSubmission()
{
return $this->_submission;
}
/**
* Get the publication for this row (already authorized)
*
* @return Publication
*/
public function getPublication()
{
return $this->_publication;
}
/**
* Get the base arguments that will identify the data in the grid.
*
* @return array
*/
public function getRequestArgs()
{
$submission = $this->getSubmission();
$publication = $this->getPublication();
return [
'submissionId' => $submission->getId(),
'publicationId' => $publication->getId()
];
}
/**
* Determines whether the current user can create user accounts from authors present
* in the grid.
* Overridden by child grid rows.
*
* @param PKPRequest $request
*
* @return bool
*/
public function allowedToCreateUser($request)
{
return false;
}
/**
* Determine if this grid row should be read only.
*
* @return bool
*/
public function isReadOnly()
{
return $this->_readOnly;
}
}
@@ -0,0 +1,72 @@
<?php
/**
* @file controllers/grid/users/author/PKPAuthorGridCellProvider.php
*
* Copyright (c) 2014-2021 Simon Fraser University
* Copyright (c) 2000-2021 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPAuthorGridCellProvider
*
* @ingroup controllers_grid_users_author
*
* @deprecated 3.4
*
* @brief Base class for a cell provider that can retrieve labels for submission contributors
*/
namespace PKP\controllers\grid\users\author;
use APP\author\Author;
use APP\publication\Publication;
use PKP\controllers\grid\DataObjectGridCellProvider;
use PKP\controllers\grid\GridColumn;
class PKPAuthorGridCellProvider extends DataObjectGridCellProvider
{
/** @var Publication The publication this author is related to */
private $_publication;
/**
* Constructor
*
* @param Publication $publication
*/
public function __construct($publication)
{
$this->_publication = $publication;
}
//
// Template methods from GridCellProvider
//
/**
* Extracts variables for a given column from a data element
* so that they may be assigned to template before rendering.
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return array
*/
public function getTemplateVarsFromRowColumn($row, $column)
{
$element = $row->getData();
$columnId = $column->getId();
assert($element instanceof \PKP\core\DataObject && !empty($columnId));
/** @var Author $element */
switch ($columnId) {
case 'name':
return ['label' => $element->getFullName()];
case 'role':
return ['label' => $element->getLocalizedUserGroupName()];
case 'email':
return parent::getTemplateVarsFromRowColumn($row, $column);
case 'principalContact':
return ['isPrincipalContact' => $this->_publication->getData('primaryContactId') === $element->getId()];
case 'includeInBrowse':
return ['includeInBrowse' => $element->getIncludeInBrowse()];
}
}
}
@@ -0,0 +1,271 @@
<?php
/**
* @file controllers/grid/users/author/form/PKPAuthorForm.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 PKPAuthorForm
*
* @ingroup controllers_grid_users_author_form
*
* @deprecated 3.4
*
* @brief Form for adding/editing a author
*/
namespace PKP\controllers\grid\users\author\form;
use APP\author\Author;
use APP\core\Services;
use APP\facades\Repo;
use APP\publication\Publication;
use APP\template\TemplateManager;
use Exception;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\security\Role;
class PKPAuthorForm extends Form
{
/** @var Publication publication associated with the contributor being edited */
public $_publication;
/** @var Author the author being edited */
public $_author;
/**
* Constructor.
*
* @param Publication $publication
*/
public function __construct($publication, $author)
{
parent::__construct('controllers/grid/users/author/form/authorForm.tpl');
$this->setPublication($publication);
$this->setAuthor($author);
// the publication locale should be the default/required locale
$this->setDefaultFormLocale($publication->getData('locale'));
// Validation checks for this form
$form = $this;
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'givenName', 'required', 'user.profile.form.givenNameRequired', $this->defaultLocale));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'familyName', 'optional', 'user.profile.form.givenNameRequired.locale', function ($familyName) use ($form) {
$givenNames = $form->getData('givenName');
foreach ($familyName as $locale => $value) {
if (!empty($value) && empty($givenNames[$locale])) {
return false;
}
}
return true;
}));
$this->addCheck(new \PKP\form\validation\FormValidatorEmail($this, 'email', 'required', 'form.emailRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorUrl($this, 'userUrl', 'optional', 'user.profile.form.urlInvalid'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'userGroupId', 'required', 'submission.submit.form.contributorRoleRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorORCID($this, 'orcid', 'optional', 'user.orcid.orcidInvalid'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the author
*
* @return Author
*/
public function getAuthor(): ?Author
{
return $this->_author;
}
/**
* Set the author
*
* @param Author $author
*/
public function setAuthor($author)
{
$this->_author = $author;
}
/**
* Get the Publication
*
* @return Publication
*/
public function getPublication()
{
return $this->_publication;
}
/**
* Set the Publication
*
* @param Publication $publication
*/
public function setPublication($publication)
{
$this->_publication = $publication;
}
//
// Overridden template methods
//
/**
* Initialize form data from the associated author.
*/
public function initData()
{
$author = $this->getAuthor();
if ($author) {
$this->_data = [
'authorId' => $author->getId(),
'givenName' => $author->getGivenName(null),
'familyName' => $author->getFamilyName(null),
'preferredPublicName' => $author->getPreferredPublicName(null),
'affiliation' => $author->getAffiliation(null),
'country' => $author->getCountry(),
'email' => $author->getEmail(),
'userUrl' => $author->getUrl(),
'orcid' => $author->getOrcid(),
'competingInterests' => $author->getCompetingInterests(null),
'userGroupId' => $author->getUserGroupId(),
'biography' => $author->getBiography(null),
'primaryContact' => $this->getPublication()->getData('primaryContactId') === $author->getId(),
'includeInBrowse' => $author->getIncludeInBrowse(),
];
} else {
// assume authors should be listed unless otherwise specified.
$this->_data = ['includeInBrowse' => true];
}
// in order to be able to use the hook
return parent::initData();
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$context = $request->getContext();
$authorUserGroups = Repo::userGroup()->getByRoleIds([Role::ROLE_ID_AUTHOR], $context->getId());
$publication = $this->getPublication();
$countries = [];
foreach (Locale::getCountries() as $country) {
$countries[$country->getAlpha2()] = $country->getLocalName();
}
asort($countries);
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'submissionId' => $publication->getData('submissionId'),
'publicationId' => $publication->getId(),
'countries' => $countries,
'authorUserGroups' => $authorUserGroups,
'requireAuthorCompetingInterests' => $context->getData('requireAuthorCompetingInterests'),
]);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'authorId',
'givenName',
'familyName',
'preferredPublicName',
'affiliation',
'country',
'email',
'userUrl',
'orcid',
'competingInterests',
'userGroupId',
'biography',
'primaryContact',
'includeInBrowse',
]);
}
/**
* Save author
*
* @see Form::execute()
*/
public function execute(...$functionParams)
{
$publication = $this->getPublication(); /** @var Publication $publication */
$submission = Repo::submission()->get($publication->getData('submissionId'));
$context = Services::get('context')->get($submission->getData('contextId'));
$author = $this->getAuthor();
if (!$author) {
// this is a new submission contributor
$this->_author = Repo::author()->newDataObject();
$author = $this->getAuthor();
$author->setData('publicationId', $publication->getId());
$author->setData('seq', count($publication->getData('authors')));
$existingAuthor = false;
} else {
$existingAuthor = true;
if ($publication->getId() !== $author->getData('publicationId')) {
fatalError('Invalid author!');
}
}
$author->setGivenName(array_map('trim', $this->getData('givenName')), null);
$author->setFamilyName($this->getData('familyName'), null);
$author->setPreferredPublicName($this->getData('preferredPublicName'), null);
$author->setAffiliation($this->getData('affiliation'), null); // localized
$author->setCountry($this->getData('country'));
$author->setEmail($this->getData('email'));
$author->setUrl($this->getData('userUrl'));
$author->setOrcid($this->getData('orcid'));
if ($context->getData('requireAuthorCompetingInterests')) {
$author->setCompetingInterests($this->getData('competingInterests'), null);
}
$author->setUserGroupId($this->getData('userGroupId'));
$author->setBiography($this->getData('biography'), null); // localized
$author->setIncludeInBrowse(($this->getData('includeInBrowse') ? true : false));
// in order to be able to use the hook
parent::execute(...$functionParams);
if ($existingAuthor) {
Repo::author()->edit($author, []);
$authorId = $author->getId();
} else {
$authorId = Repo::author()->add($author);
}
if ($this->getData('primaryContact')) {
$params = ['primaryContactId' => $authorId];
$errors = Repo::publication()->validate(
$publication,
$params,
$submission,
$context
);
if (!empty($errors)) {
throw new Exception('Invalid primary contact ID. This author can not be a primary contact.');
}
Repo::publication()->edit($publication, $params);
}
return $authorId;
}
}