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,686 @@
<?php
/**
* @file controllers/grid/settings/user/UserGridHandler.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 UserGridHandler
*
* @ingroup controllers_grid_settings_user
*
* @brief Handle user grid requests.
*/
namespace PKP\controllers\grid\settings\user;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use PKP\controllers\grid\ColumnBasedGridCellProvider;
use PKP\controllers\grid\DataObjectGridCellProvider;
use PKP\controllers\grid\feature\PagingFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\settings\user\form\UserDetailsForm;
use PKP\controllers\grid\settings\user\form\UserDisableForm;
use PKP\controllers\grid\settings\user\form\UserEmailForm;
use PKP\controllers\grid\settings\user\form\UserRoleForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\core\VirtualArrayIterator;
use PKP\db\DAORegistry;
use PKP\identity\Identity;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\notification\PKPNotification;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\Role;
use PKP\security\RoleDAO;
use PKP\security\Validation;
use PKP\user\User;
use PKP\userGroup\UserGroup;
class UserGridHandler extends GridHandler
{
/** @var int user id for the user to remove */
public $_oldUserId;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[
Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['fetchGrid', 'fetchRow', 'editUser', 'updateUser', 'updateUserRoles',
'editDisableUser', 'disableUser', 'removeUser', 'addUser',
'editEmail', 'sendEmail', 'mergeUsers']
);
}
//
// Implement template methods from PKPHandler.
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new ContextAccessPolicy($request, $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->_oldUserId = (int) $request->getUserVar('oldUserId');
// Basic grid configuration.
$this->setTitle('grid.user.currentUsers');
// Grid actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addUser',
new AjaxModal(
$router->url($request, null, null, 'addUser', null, null),
__('grid.user.add'),
'modal_add_user',
true
),
__('grid.user.add'),
'add_user'
)
);
//
// Grid columns.
//
$cellProvider = new DataObjectGridCellProvider();
// First Name.
$this->addColumn(
new GridColumn(
'givenName',
'user.givenName',
null,
null,
$cellProvider
)
);
// Last Name.
$this->addColumn(
new GridColumn(
'familyName',
'user.familyName',
null,
null,
$cellProvider
)
);
// User name.
$this->addColumn(
new GridColumn(
'userName',
'user.username',
null,
null,
$cellProvider
)
);
// Roles.
$columnBasedGridCellProvider = new ColumnBasedGridCellProvider();
$this->addColumn(
new class (
'roles',
'user.roles',
null,
null,
$columnBasedGridCellProvider
) extends GridColumn {
public function getTemplateVarsFromRow($row): array
{
$user = $row->getData();
assert($user instanceof User);
$contextId = Application::get()->getRequest()->getContext()->getId();
$userGroupsIterator = Repo::userGroup()->userUserGroups($user->getId(), $contextId);
$roles = $userGroupsIterator->map(fn (UserGroup $userGroup) => $userGroup->getLocalizedName())->join(__('common.commaListSeparator'));
return ['label' => $roles];
}
}
);
// Email.
$this->addColumn(
new GridColumn(
'email',
'user.email',
null,
null,
$cellProvider
)
);
}
//
// Implement methods from GridHandler.
//
/**
* @copydoc GridHandler::getRowInstance()
*
* @return UserGridRow
*/
protected function getRowInstance()
{
return new UserGridRow($this->_oldUserId);
}
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new PagingFeature()];
}
/**
* @copydoc GridHandler::loadData()
*
* @param PKPRequest $request
*
* @return VirtualArrayIterator Grid data.
*/
protected function loadData($request, $filter)
{
$context = $request->getContext();
$collector = Repo::user()->getCollector();
$collector->filterByStatus($collector::STATUS_ALL);
if ($filter['userGroup'] ?? false) {
$collector->filterByUserGroupIds((array) $filter['userGroup']);
}
if (!($filter['includeNoRole'] ?? false)) {
$collector->filterByContextIds([$context->getId()]);
}
if (strlen($filter['search'] ?? '')) {
$collector->searchPhrase($filter['search']);
}
// Handle grid paging (deprecated style)
$rangeInfo = $this->getGridRangeInfo($request, $this->getId());
$totalCount = $collector->getCount();
$collector->limit($rangeInfo->getCount());
$collector->offset($rangeInfo->getOffset() + max(0, $rangeInfo->getPage() - 1) * $rangeInfo->getCount());
$iterator = $collector->getMany();
return new VirtualArrayIterator(iterator_to_array($iterator, true), $totalCount, $rangeInfo->getPage(), $rangeInfo->getCount());
}
/**
* @copydoc GridHandler::renderFilter()
*/
public function renderFilter($request, $filterData = [])
{
$context = $request->getContext();
$userGroups = Repo::userGroup()->getCollector()
->filterByContextIds([$context->getId()])
->getMany();
$userGroupOptions = ['' => __('grid.user.allRoles')];
foreach ($userGroups as $userGroup) {
$userGroupOptions[$userGroup->getId()] = $userGroup->getLocalizedName();
}
$userDao = Repo::user()->dao;
$fieldOptions = [
Identity::IDENTITY_SETTING_GIVENNAME => 'user.givenName',
Identity::IDENTITY_SETTING_FAMILYNAME => 'user.familyName',
$userDao::USER_FIELD_USERNAME => 'user.username',
$userDao::USER_FIELD_EMAIL => 'user.email'
];
$matchOptions = [
'contains' => 'form.contains',
'is' => 'form.is'
];
$filterData = [
'userGroupOptions' => $userGroupOptions,
'fieldOptions' => $fieldOptions,
'matchOptions' => $matchOptions,
// oldUserId is used when merging users. see: userGridFilter.tpl
'oldUserId' => $request->getUserVar('oldUserId'),
];
return parent::renderFilter($request, $filterData);
}
/**
* @copydoc GridHandler::getFilterSelectionData()
*
* @return array Filter selection data.
*/
public function getFilterSelectionData($request)
{
// Get the search terms.
$includeNoRole = $request->getUserVar('includeNoRole') ? (int) $request->getUserVar('includeNoRole') : null;
$userGroup = $request->getUserVar('userGroup') ? (int)$request->getUserVar('userGroup') : null;
$searchField = $request->getUserVar('searchField');
$searchMatch = $request->getUserVar('searchMatch');
$search = $request->getUserVar('search');
return $filterSelectionData = [
'includeNoRole' => $includeNoRole,
'userGroup' => $userGroup,
'searchField' => $searchField,
'searchMatch' => $searchMatch,
'search' => $search ? $search : ''
];
}
/**
* @copydoc GridHandler::getFilterForm()
*
* @return string Filter template.
*/
protected function getFilterForm()
{
return 'controllers/grid/settings/user/userGridFilter.tpl';
}
/**
* Get the js handler for this component.
*
* @return string
*/
public function getJSHandler()
{
return '$.pkp.controllers.grid.users.UserGridHandler';
}
//
// Public grid actions.
//
/**
* Add a new user.
*
* @param array $args
* @param PKPRequest $request
*/
public function addUser($args, $request)
{
// Calling editUser with an empty row id will add a new user.
return $this->editUser($args, $request);
}
/**
* Edit an existing user.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editUser($args, $request)
{
// Identify the user Id.
$userId = $request->getUserVar('rowId');
if (!$userId) {
$userId = $request->getUserVar('userId');
}
$user = $request->getUser();
$administrationLevel = null;
if ($userId !== null && ($administrationLevel = Validation::getAdministrationLevel($userId, $user->getId(), $request->getContext()->getId())) === Validation::ADMINISTRATION_PROHIBITED) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userForm = new UserDetailsForm($request, $userId);
$administrationLevel === Validation::ADMINISTRATION_PARTIAL
? $userForm->applyUserGroupUpdateOnly()
: $userForm->attachValidationChecks($request);
$userForm->initData();
return new JSONMessage(true, $userForm->display($request));
}
/**
* Update an existing user.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateUser($args, $request)
{
$user = $request->getUser();
// Identify the user Id.
$userId = $request->getUserVar('userId');
$administrationLevel = null;
if ($userId !== null && ($administrationLevel = Validation::getAdministrationLevel($userId, $user->getId(), $request->getContext()->getId())) === Validation::ADMINISTRATION_PROHIBITED) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userForm = new UserDetailsForm($request, $userId);
$administrationLevel === Validation::ADMINISTRATION_PARTIAL
? $userForm->applyUserGroupUpdateOnly()
: $userForm->attachValidationChecks($request);
$userForm->readInputData();
if ($userForm->validate()) {
$user = $userForm->execute();
// If this is a newly created user, show role management form.
if (!$userId) {
$userRoleForm = new UserRoleForm($user->getId(), $user->getFullName());
$userRoleForm->initData();
return new JSONMessage(true, $userRoleForm->display($request));
} else {
// Successful edit of an existing user.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.editedUser')]);
// Prepare the grid row data.
return \PKP\db\DAO::getDataChangedEvent($userId);
}
} else {
return new JSONMessage(false);
}
}
/**
* Update a newly created user's roles
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateUserRoles($args, $request)
{
$user = $request->getUser();
// Identify the user Id.
$userId = $request->getUserVar('userId');
if ($userId !== null && Validation::getAdministrationLevel($userId, $user->getId()) !== Validation::ADMINISTRATION_FULL) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userRoleForm = new UserRoleForm($userId, $user->getFullName());
$userRoleForm->readInputData();
if ($userRoleForm->validate()) {
$userRoleForm->execute();
// Successfully managed newly created user's roles.
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
/**
* Edit enable/disable user form
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage Serialized JSON object
*/
public function editDisableUser($args, $request)
{
$user = $request->getUser();
// Identify the user Id.
$userId = $request->getUserVar('rowId');
if (!$userId) {
$userId = $request->getUserVar('userId');
}
// Are we enabling or disabling this user.
$enable = isset($args['enable']) ? (bool) $args['enable'] : false;
if ($userId !== null && Validation::getAdministrationLevel($userId, $user->getId()) !== Validation::ADMINISTRATION_FULL) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
} else {
// Form handling
$userForm = new UserDisableForm($userId, $enable);
$userForm->initData();
return new JSONMessage(true, $userForm->display($request));
}
}
/**
* Enable/Disable an existing user
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function disableUser($args, $request)
{
$user = $request->getUser();
// Identify the user Id.
$userId = $request->getUserVar('userId');
// Are we enabling or disabling this user.
$enable = (bool) $request->getUserVar('enable');
if ($userId !== null && Validation::getAdministrationLevel($userId, $user->getId()) !== Validation::ADMINISTRATION_FULL) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userForm = new UserDisableForm($userId, $enable);
$userForm->readInputData();
if ($userForm->validate()) {
$user = $userForm->execute();
// Successful enable/disable of an existing user.
// Update grid data.
return \PKP\db\DAO::getDataChangedEvent($userId);
} else {
return new JSONMessage(false, $userForm->display($request));
}
}
/**
* Remove all user group assignments for a context for a given user.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function removeUser($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$context = $request->getContext();
$user = $request->getUser();
// Identify the user Id.
$userId = $request->getUserVar('rowId');
if ($userId !== null && Validation::getAdministrationLevel($userId, $user->getId(), $request->getContext()->getId()) === Validation::ADMINISTRATION_PROHIBITED) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Remove user from all user group assignments for this context.
// Check if this user has any user group assignments for this context.
$userGroupCount = Repo::userGroup()
->userUserGroups($userId, $context->getId())
->count();
if (!$userGroupCount) {
return new JSONMessage(false, __('grid.user.userNoRoles'));
} else {
Repo::userGroup()->deleteAssignmentsByContextId($context->getId(), $userId);
return \PKP\db\DAO::getDataChangedEvent($userId);
}
}
/**
* Displays a modal to edit an email message to the user.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage Serialized JSON object
*/
public function editEmail($args, $request)
{
$user = $request->getUser();
$context = $request->getContext();
// Identify the user Id.
$userId = $request->getUserVar('rowId');
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
if (
!$roleDao->userHasRole(\PKP\core\PKPApplication::CONTEXT_SITE, $user->getId(), Role::ROLE_ID_SITE_ADMIN) && !(
$context &&
$roleDao->userHasRole($context->getId(), $user->getId(), Role::ROLE_ID_MANAGER)
)
) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
} else {
// Form handling.
$userEmailForm = new UserEmailForm($userId);
$userEmailForm->initData();
return new JSONMessage(true, $userEmailForm->fetch($request));
}
}
/**
* Send the user email and close the modal.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function sendEmail($args, $request)
{
$user = $request->getUser();
$context = $request->getContext();
// Identify the user Id.
$userId = $request->getUserVar('userId');
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
if (
!$roleDao->userHasRole(\PKP\core\PKPApplication::CONTEXT_SITE, $user->getId(), Role::ROLE_ID_SITE_ADMIN) && !(
$context &&
$roleDao->userHasRole($context->getId(), $user->getId(), Role::ROLE_ID_MANAGER)
)
) {
// We don't have administrative rights over this user.
return new JSONMessage(false, __('grid.user.cannotAdminister'));
}
// Form handling.
$userEmailForm = new UserEmailForm($userId);
$userEmailForm->readInputData();
if ($userEmailForm->validate()) {
$userEmailForm->execute();
return new JSONMessage(true);
} else {
return new JSONMessage(false, __('validator.filled'));
}
}
/**
* Allow user account merging, including attributed submissions etc.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function mergeUsers($args, $request)
{
$newUserId = (int) $request->getUserVar('newUserId');
$oldUserId = (int) $request->getUserVar('oldUserId');
$user = $request->getUser();
// if there is a $newUserId, this is the second time through, so merge the users.
if ($newUserId > 0 && $oldUserId > 0 && Validation::getAdministrationLevel($oldUserId, $user->getId()) === Validation::ADMINISTRATION_FULL) {
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
Repo::user()->mergeUsers($oldUserId, $newUserId);
$json = new JSONMessage(true);
$json->setGlobalEvent('userMerged', [
'oldUserId' => $oldUserId,
'newUserId' => $newUserId,
]);
return $json;
// Otherwise present the grid for selecting the user to merge into
} else {
$userGrid = new UserGridHandler();
$userGrid->initialize($request);
$userGrid->setTitle('grid.user.mergeUsers.mergeIntoUser');
return $userGrid->fetchGrid($args, $request);
}
}
/**
* @see GridHandler::getRequestArgs()
*/
public function getRequestArgs()
{
$requestArgs = parent::getRequestArgs();
$requestArgs['oldUserId'] = $this->_oldUserId;
return $requestArgs;
}
}
@@ -0,0 +1,227 @@
<?php
/**
* @file controllers/grid/settings/user/UserGridRow.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 UserGridRow
*
* @ingroup controllers_grid_settings_user
*
* @brief User grid row definition
*/
namespace PKP\controllers\grid\settings\user;
use APP\facades\Repo;
use PKP\controllers\grid\GridRow;
use PKP\core\PKPApplication;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RedirectConfirmationModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\security\Validation;
class UserGridRow extends GridRow
{
/** @var int the user id of the old user to remove when merging users. */
public $_oldUserId;
/**
* Constructor
*
* @param null|mixed $oldUserId
*/
public function __construct($oldUserId = null)
{
$this->_oldUserId = $oldUserId;
parent::__construct();
}
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
// Is this a new row or an existing row?
$element = & $this->getData();
assert(is_a($element, 'User'));
$rowId = $this->getId();
if (!empty($rowId) && is_numeric($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
$actionArgs = [
'gridId' => $this->getGridId(),
'rowId' => $rowId
];
$actionArgs = array_merge($actionArgs, $this->getRequestArgs());
// If this is the grid for merging a user, only show the merge
// linkaction
if ($this->getOldUserId()) {
$actionArgs['oldUserId'] = $this->getOldUserId();
$actionArgs['newUserId'] = $rowId;
// Verify that the old user exists
$oldUser = Repo::user()->get((int) $this->getOldUserId(), true);
// Don't merge a user in itself
if ($oldUser && $actionArgs['oldUserId'] != $actionArgs['newUserId']) {
$this->addAction(
new LinkAction(
'mergeUser',
new RemoteActionConfirmationModal(
$request->getSession(),
__('grid.user.mergeUsers.confirm', ['oldUsername' => $oldUser->getUsername(), 'newUsername' => $element->getUsername()]),
null,
$router->url($request, null, null, 'mergeUsers', null, $actionArgs),
'modal_merge_users'
),
__('grid.user.mergeUsers.mergeIntoUser'),
'merge_users'
)
);
}
// Otherwise display all the default link actions
} else {
$this->addAction(
new LinkAction(
'email',
new AjaxModal(
$router->url($request, null, null, 'editEmail', null, $actionArgs),
__('grid.user.email'),
'modal_email',
true
),
__('grid.user.email'),
'notify'
)
);
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editUser', null, $actionArgs),
__('grid.user.edit'),
'modal_edit',
true
),
__('grid.user.edit'),
'edit'
)
);
if ($element->getDisabled()) {
$actionArgs['enable'] = true;
$this->addAction(
new LinkAction(
'enable',
new AjaxModal(
$router->url($request, null, null, 'editDisableUser', null, $actionArgs),
__('common.enable'),
'enable',
true
),
__('common.enable'),
'enable'
)
);
} else {
$actionArgs['enable'] = false;
$this->addAction(
new LinkAction(
'disable',
new AjaxModal(
$router->url($request, null, null, 'editDisableUser', null, $actionArgs),
__('grid.user.disable'),
'disable',
true
),
__('grid.user.disable'),
'disable'
)
);
}
$this->addAction(
new LinkAction(
'remove',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.people.confirmRemove'),
__('common.remove'),
$router->url($request, null, null, 'removeUser', null, $actionArgs),
'modal_delete'
),
__('grid.action.remove'),
'delete'
)
);
$canAdminister = Validation::getAdministrationLevel($this->getId(), $request->getUser()->getId()) === Validation::ADMINISTRATION_FULL;
if (
!Validation::loggedInAs() &&
$request->getUser()->getId() != $this->getId() &&
$canAdminister
) {
$dispatcher = $router->getDispatcher();
$this->addAction(
new LinkAction(
'logInAs',
new RedirectConfirmationModal(
__('grid.user.confirmLogInAs'),
__('grid.action.logInAs'),
$dispatcher->url($request, PKPApplication::ROUTE_PAGE, null, 'login', 'signInAsUser', $this->getId())
),
__('grid.action.logInAs'),
'enroll_user'
)
);
}
// do not allow the deletion of your own account.
if (
$request->getUser()->getId() != $this->getId() and
$canAdminister
) {
$this->addAction(
new LinkAction(
'mergeUser',
new AjaxModal(
$router->url($request, null, null, 'mergeUsers', null, ['oldUserId' => $rowId]),
__('grid.user.mergeUsers.mergeUser'),
'modal_merge_users',
true
),
__('grid.user.mergeUsers.mergeUser'),
'merge_users'
)
);
}
}
}
}
/**
* Returns the stored user id of the user to be removed.
*
* @return int the user id.
*/
public function getOldUserId()
{
return $this->_oldUserId;
}
}
@@ -0,0 +1,406 @@
<?php
/**
* @file controllers/grid/settings/user/form/UserDetailsForm.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 UserDetailsForm
*
* @ingroup controllers_grid_settings_user_form
*
* @brief Form for editing user profiles.
*/
namespace PKP\controllers\grid\settings\user\form;
use APP\author\Author;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use Illuminate\Support\Facades\Mail;
use PKP\core\Core;
use PKP\core\PKPRequest;
use PKP\core\PKPString;
use PKP\facades\Locale;
use PKP\identity\Identity;
use PKP\mail\mailables\UserCreated;
use PKP\notification\PKPNotification;
use PKP\security\Validation;
use PKP\session\SessionManager;
use PKP\user\InterestManager;
use PKP\user\User;
use Symfony\Component\Mailer\Exception\TransportException;
class UserDetailsForm extends UserForm
{
/** @var User */
public $user;
/** @var Author An optional author to base this user on */
public $author;
/** @var bool An internal use flag that allows to determine the update only for user group */
protected bool $userGroupUpdateOnly = false;
/**
* Constructor.
*
* @param PKPRequest $request
* @param int $userId optional
* @param Author $author optional
*/
public function __construct($request, $userId = null, $author = null)
{
parent::__construct('controllers/grid/settings/user/form/userDetailsForm.tpl', $userId);
if (isset($author)) {
$this->author = & $author;
} else {
$this->author = null;
}
// the users register for the site, thus
// the site primary locale is the required default locale
$this->addSupportedFormLocale($request->getSite()->getPrimaryLocale());
if ($userId !== null) {
$this->user = Repo::user()->get($userId, true);
}
}
/**
* Attach the validation checks for this form
*
* @param PKPRequest|null $request
*/
public function attachValidationChecks($request = null): self
{
$request ??= Application::get()->getRequest();
$site = $request->getSite();
$form = $this;
if (!$this->user) {
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'username', 'required', 'user.profile.form.usernameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'username', 'required', 'user.register.form.usernameExists', function ($username, $userId) {
$user = Repo::user()->getByUsername($username, true);
return !$user || $user->getId() == $userId;
}, [$this->userId]));
$this->addCheck(new \PKP\form\validation\FormValidatorUsername($this, 'username', 'required', 'user.register.form.usernameAlphaNumeric'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'password', 'required', 'user.profile.form.passwordRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'password', 'required', 'user.register.form.passwordLengthRestriction', function ($password) use ($form, $site) {
return $form->getData('generatePassword') || PKPString::strlen($password) >= $site->getMinPasswordLength();
}, [], false, ['length' => $site->getMinPasswordLength()]));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'password', 'required', 'user.register.form.passwordsDoNotMatch', function ($password) use ($form) {
return $password == $form->getData('password2');
}));
} else {
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'password', 'optional', 'user.register.form.passwordLengthRestriction', function ($password) use ($form, $site) {
return $form->getData('generatePassword') || PKPString::strlen($password) >= $site->getMinPasswordLength();
}, [], false, ['length' => $site->getMinPasswordLength()]));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'password', 'optional', 'user.register.form.passwordsDoNotMatch', function ($password) use ($form) {
return $password == $form->getData('password2');
}));
}
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'givenName', 'required', 'user.profile.form.givenNameRequired', $site->getPrimaryLocale()));
$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\FormValidatorUrl($this, 'userUrl', 'optional', 'user.profile.form.urlInvalid'));
$this->addCheck(new \PKP\form\validation\FormValidatorEmail($this, 'email', 'required', 'user.profile.form.emailRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'email', 'required', 'user.register.form.emailExists', function ($email, $currentUserId) {
$user = Repo::user()->getByEmail($email, true);
return !$user || $user->getId() == $currentUserId;
}, [$this->userId]));
$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));
return $this;
}
/**
* Apply the update only for user's user group
*
*/
public function applyUserGroupUpdateOnly(): self
{
$this->userGroupUpdateOnly = true;
return $this;
}
/**
* Initialize form data from current user profile.
*/
public function initData()
{
$request = Application::get()->getRequest();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('site', $request->getSite());
$data = [];
if (isset($this->user)) {
$user = $this->user;
$templateMgr->assign('user', $user);
$interestManager = new InterestManager();
$data = [
'username' => $user->getUsername(),
'givenName' => $user->getGivenName(null), // Localized
'familyName' => $user->getFamilyName(null), // Localized
'preferredPublicName' => $user->getPreferredPublicName(null), // Localized
'signature' => $user->getSignature(null), // Localized
'affiliation' => $user->getAffiliation(null), // Localized
'email' => $user->getEmail(),
'userUrl' => $user->getUrl(),
'phone' => $user->getPhone(),
'orcid' => $user->getOrcid(),
'mailingAddress' => $user->getMailingAddress(),
'country' => $user->getCountry(),
'biography' => $user->getBiography(null), // Localized
'interests' => $interestManager->getInterestsForUser($user),
'locales' => $user->getLocales(),
];
$data['canCurrentUserGossip'] = Repo::user()->canCurrentUserGossip($user->getId());
if ($data['canCurrentUserGossip']) {
$data['gossip'] = $user->getGossip();
}
} elseif (isset($this->author)) {
$author = $this->author;
$templateMgr->assign('user', $author);
$data = [
'givenName' => $author->getGivenName(null), // Localized
'familyName' => $author->getFamilyName(null), // Localized
'affiliation' => $author->getAffiliation(null), // Localized
'preferredPublicName' => $author->getPreferredPublicName(null), // Localized
'email' => $author->getEmail(),
'userUrl' => $author->getUrl(),
'orcid' => $author->getOrcid(),
'country' => $author->getCountry(),
'biography' => $author->getBiography(null), // Localized
];
} else {
$data = [
'mustChangePassword' => true,
];
}
foreach ($data as $key => $value) {
$this->setData($key, $value);
}
parent::initData();
}
/**
* @copydoc UserForm::display
*
* @param null|mixed $request
* @param null|mixed $template
*/
public function display($request = null, $template = null)
{
$site = $request->getSite();
$countries = [];
foreach (Locale::getCountries() as $country) {
$countries[$country->getAlpha2()] = $country->getLocalName();
}
asort($countries);
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'minPasswordLength' => $site->getMinPasswordLength(),
'source' => $request->getUserVar('source'),
'userId' => $this->userId,
'sitePrimaryLocale' => $site->getPrimaryLocale(),
'availableLocales' => $site->getSupportedLocaleNames(),
'countries' => $countries,
'userGroupUpdateOnly' => $this->userGroupUpdateOnly,
]);
if (isset($this->user)) {
$templateMgr->assign('username', $this->user->getUsername());
}
return parent::display($request, $template);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
parent::readInputData();
// if doing only a partial update that includes only updating user's user group
if ($this->userGroupUpdateOnly) {
return;
}
$this->readUserVars([
'password',
'password2',
'givenName',
'familyName',
'preferredPublicName',
'signature',
'affiliation',
'email',
'userUrl',
'phone',
'orcid',
'mailingAddress',
'country',
'biography',
'gossip',
'interests',
'locales',
'generatePassword',
'sendNotify',
'mustChangePassword'
]);
if ($this->userId == null) {
$this->readUserVars(['username']);
}
if ($this->getData('locales') == null || !is_array($this->getData('locales'))) {
$this->setData('locales', []);
}
}
/**
* Get all locale field names
*/
public function getLocaleFieldNames()
{
return ['biography', 'signature', 'affiliation', Identity::IDENTITY_SETTING_GIVENNAME, Identity::IDENTITY_SETTING_FAMILYNAME, 'preferredPublicName'];
}
/**
* Create or update a user.
*/
public function execute(...$functionParams)
{
$request = Application::get()->getRequest();
$context = $request->getContext();
if (!isset($this->user)) {
$this->user = Repo::user()->newDataObject();
$this->user->setInlineHelp(1); // default new users to having inline help visible
}
//save the user's user group assignment
$this->saveUserGroupAssignments($request);
// if doing only a partial update that includes only updating user's user group
if ($this->userGroupUpdateOnly) {
parent::execute(...$functionParams);
return $this->user;
}
$this->user->setGivenName($this->getData('givenName'), null); // Localized
$this->user->setFamilyName($this->getData('familyName'), null); // Localized
$this->user->setPreferredPublicName($this->getData('preferredPublicName'), null); // Localized
$this->user->setAffiliation($this->getData('affiliation'), null); // Localized
$this->user->setSignature($this->getData('signature'), null); // Localized
$this->user->setEmail($this->getData('email'));
$this->user->setUrl($this->getData('userUrl'));
$this->user->setPhone($this->getData('phone'));
$this->user->setOrcid($this->getData('orcid'));
$this->user->setMailingAddress($this->getData('mailingAddress'));
$this->user->setCountry($this->getData('country'));
$this->user->setBiography($this->getData('biography'), null); // Localized
$this->user->setMustChangePassword($this->getData('mustChangePassword') ? 1 : 0);
// Users can never view/edit their own gossip fields
if (Repo::user()->canCurrentUserGossip($this->user->getId())) {
$this->user->setGossip($this->getData('gossip'));
}
$site = $request->getSite();
$availableLocales = $site->getSupportedLocales();
$locales = [];
foreach ($this->getData('locales') as $locale) {
if (Locale::isLocaleValid($locale) && in_array($locale, $availableLocales)) {
array_push($locales, $locale);
}
}
$this->user->setLocales($locales);
parent::execute(...$functionParams);
if ($this->user->getId() != null) {
if ($this->getData('password') !== '') {
$this->user->setPassword(Validation::encryptCredentials($this->user->getUsername(), $this->getData('password')));
$sessionManager = SessionManager::getManager();
$sessionManager->invalidateSessions(
$this->user->getId(),
(int) $this->user->getId() === (int) $request->getUser()->getId()
? $sessionManager->getUserSession()->getId()
: null
);
}
Repo::user()->edit($this->user);
} else {
$this->user->setUsername($this->getData('username'));
if ($this->getData('generatePassword')) {
$password = Validation::generatePassword();
$sendNotify = true;
} else {
$password = $this->getData('password');
$sendNotify = $this->getData('sendNotify');
}
$this->user->setPassword(Validation::encryptCredentials($this->getData('username'), $password));
$this->user->setDateRegistered(Core::getCurrentDate());
Repo::user()->add($this->user);
if ($sendNotify) {
// Send welcome email to user
$mailable = new UserCreated($context, $password);
$mailable->recipients($this->user);
$mailable->sender($request->getUser());
$mailable->replyTo($context->getData('contactEmail'), $context->getData('contactName'));
$template = Repo::emailTemplate()->getByKey($context->getId(), UserCreated::getEmailTemplateKey());
$mailable->body($template->getLocalizedData('body'));
$mailable->subject($template->getLocalizedData('subject'));
try {
Mail::send($mailable);
} catch (TransportException $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
error_log($e->getMessage());
}
}
}
$interestManager = new InterestManager();
$interestManager->setInterestsForUser($this->user, $this->getData('interests'));
return $this->user;
}
}
@@ -0,0 +1,111 @@
<?php
/**
* @file controllers/grid/settings/user/form/UserDisableForm.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 UserDisableForm
*
* @ingroup controllers_grid_settings_user_form
*
* @brief Form for enabling/disabling a user
*/
namespace PKP\controllers\grid\settings\user\form;
use APP\facades\Repo;
use APP\template\TemplateManager;
use PKP\form\Form;
use PKP\db\DAORegistry;
class UserDisableForm extends Form
{
/** @var int The user id of user to enable/disable */
public $_userId;
/** @var bool Whether to enable or disable the user */
public $_enable;
/**
* Constructor.
*/
public function __construct($userId, $enable = false)
{
parent::__construct('controllers/grid/settings/user/form/userDisableForm.tpl');
$this->_userId = (int) $userId;
$this->_enable = (bool) $enable;
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Initialize form data.
*/
public function initData()
{
if ($this->_userId) {
$user = Repo::user()->get($this->_userId, true);
if ($user) {
$this->_data = [
'disableReason' => $user->getDisabledReason()
];
}
}
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(
[
'disableReason',
]
);
}
/**
* @copydoc Form::display
*
* @param null|mixed $request
* @param null|mixed $template
*/
public function display($request = null, $template = null)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'userId' => $this->_userId,
'enable' => $this->_enable,
]);
return $this->fetch($request);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$user = Repo::user()->get($this->_userId, true);
if ($user) {
$user->setDisabled($this->_enable ? false : true);
$user->setDisabledReason($this->getData('disableReason'));
Repo::user()->edit($user);
if ($user->getDisabled()) {
$sessionDao = DAORegistry::getDAO('SessionDAO');
$sessionDao->deleteByUserId($user->getId());
}
}
parent::execute(...$functionArgs);
return $user;
}
}
@@ -0,0 +1,115 @@
<?php
/**
* @file controllers/grid/settings/user/form/UserEmailForm.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 UserEmailForm
*
* @ingroup controllers_grid_settings_user_form
*
* @brief Form for sending an email to a user
*/
namespace PKP\controllers\grid\settings\user\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use Exception;
use Illuminate\Support\Facades\Mail;
use PKP\form\Form;
use PKP\mail\Mailable;
use PKP\notification\PKPNotification;
class UserEmailForm extends Form
{
/** @var int The user id of user to send email to */
public $userId;
/**
* Constructor.
*
* @param int $userId User ID to contact.
*/
public function __construct($userId)
{
parent::__construct('controllers/grid/settings/user/form/userEmailForm.tpl');
$this->userId = (int) $userId;
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'subject', 'required', 'email.subjectRequired'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'message', 'required', 'email.bodyRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars([
'subject',
'message',
]);
}
/**
* @copydoc Form::Fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$user = Repo::user()->get($this->userId);
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'userId' => $this->userId,
'userFullName' => $user->getFullName(),
'userEmail' => $user->getEmail(),
]);
return parent::fetch($request, $template, $display);
}
/**
* Send the email
*
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$toUser = Repo::user()->get($this->userId);
$request = Application::get()->getRequest();
$fromUser = $request->getUser();
$mailable = new Mailable();
$mailable
->from($fromUser->getEmail(), $fromUser->getFullName())
->to($toUser->getEmail(), $toUser->getFullName())
->subject($this->getData('subject'))
->body($this->getData('message'));
parent::execute(...$functionArgs);
try {
Mail::send($mailable);
} catch (Exception $e) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('email.compose.error')]
);
error_log($e->getMessage());
}
}
}
@@ -0,0 +1,142 @@
<?php
/**
* @file controllers/grid/settings/user/form/UserForm.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 UserForm
*
* @ingroup controllers_grid_settings_user_form
*
* @brief Base class for user forms.
*/
namespace PKP\controllers\grid\settings\user\form;
use APP\core\Application;
use APP\core\Request;
use APP\facades\Repo;
use APP\template\TemplateManager;
use PKP\form\Form;
class UserForm extends Form
{
/** @var int Id of the user being edited */
public $userId;
/**
* Constructor.
*
* @param int $userId optional
*/
public function __construct($template, $userId = null)
{
parent::__construct($template);
$this->userId = isset($userId) ? (int) $userId : null;
if (!is_null($userId)) {
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'userGroupIds', 'required', 'manager.users.roleRequired'));
}
}
/**
* Initialize form data from current user profile.
*/
public function initData()
{
$userGroupIds = [];
if (!is_null($this->userId)) {
$userGroups = Repo::userGroup()->userUserGroups($this->userId);
foreach ($userGroups as $userGroup) {
$userGroupIds[] = $userGroup->getId();
}
}
$this->setData('userGroupIds', $userGroupIds);
parent::initData();
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['userGroupIds']);
parent::readInputData();
}
/**
* @copydoc Form::display
*
* @param null|mixed $request
* @param null|mixed $template
*/
public function display($request = null, $template = null)
{
$context = $request->getContext();
$contextId = $context ? $context->getId() : \PKP\core\PKPApplication::CONTEXT_ID_NONE;
$templateMgr = TemplateManager::getManager($request);
$allUserGroups = [];
$userGroups = Repo::userGroup()->getCollector()
->filterByContextIds([$contextId])
->getMany();
foreach ($userGroups as $userGroup) {
$allUserGroups[(int) $userGroup->getId()] = $userGroup->getLocalizedName();
}
$templateMgr->assign([
'allUserGroups' => $allUserGroups,
'assignedUserGroups' => array_map('intval', $this->getData('userGroupIds')),
]);
return $this->fetch($request);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
parent::execute(...$functionArgs);
}
/**
* Save the user group assignments
*/
public function saveUserGroupAssignments(Request $request): void
{
if (!isset($this->userId)) {
return;
}
Repo::userGroup()
->deleteAssignmentsByContextId(
Application::get()->getRequest()->getContext()->getId(),
$this->userId
);
if ($this->getData('userGroupIds')) {
$contextId = $request->getContext()->getId();
collect($this->getData('userGroupIds'))
->each(
fn ($userGroupId) =>
Repo::userGroup()->contextHasGroup($contextId, $userGroupId)
? Repo::userGroup()->assignUserToGroup($this->userId, $userGroupId)
: null
);
}
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @file controllers/grid/settings/user/form/UserRoleForm.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 UserRoleForm
*
* @ingroup controllers_grid_settings_user_form
*
* @brief Form for managing roles for a newly created user.
*/
namespace PKP\controllers\grid\settings\user\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\template\TemplateManager;
class UserRoleForm extends UserForm
{
/** @var string User full name */
public $_userFullName;
/**
* Constructor.
*
* @param int $userId
* @param string $userFullName
*/
public function __construct($userId, $userFullName)
{
parent::__construct('controllers/grid/settings/user/form/userRoleForm.tpl', $userId);
$this->_userFullName = $userFullName;
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* @copydoc UserForm::display
*
* @param null|mixed $request
* @param null|mixed $template
*/
public function display($request = null, $template = null)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'userId' => $this->userId,
'userFullName' => $this->_userFullName,
]);
return parent::display($request, $template);
}
/**
* Update user's roles.
*/
public function execute(...$functionParams)
{
$request = Application::get()->getRequest();
//save the user's user group assignment
$this->saveUserGroupAssignments($request);
parent::execute(...$functionParams);
// Role management handled by parent form, just return user.
return Repo::user()->get($this->userId);
}
}