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,77 @@
<?php
/**
* @file controllers/grid/settings/SetupGridHandler.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 SetupGridHandler
*
* @ingroup controllers_grid_settings
*
* @brief Base class for setup grid handlers
*/
namespace PKP\controllers\grid\settings;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\file\TemporaryFileManager;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\Role;
class SetupGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['uploadImage']
);
}
/**
* @copydoc PKPHandler::authorize()
*
* @param bool $contextRequired
*/
public function authorize($request, &$args, $roleAssignments, $contextRequired = true)
{
if ($contextRequired) {
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
}
return parent::authorize($request, $args, $roleAssignments);
}
/**
* Handle file uploads for cover/image art for things like Series and Categories.
*
* @param array $args
* @param PKPRequest $request
*/
public function uploadImage($args, $request)
{
$router = $request->getRouter();
$context = $request->getContext();
$user = $request->getUser();
$temporaryFileManager = new TemporaryFileManager();
$temporaryFile = $temporaryFileManager->handleUpload('uploadedFile', $user->getId());
if ($temporaryFile) {
$json = new JSONMessage(true);
$json->setAdditionalAttributes([
'temporaryFileId' => $temporaryFile->getId()
]);
return $json;
} else {
return new JSONMessage(false, __('common.uploadFailed'));
}
}
}
@@ -0,0 +1,344 @@
<?php
/**
* @file controllers/grid/settings/category/CategoryCategoryGridHandler.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 CategoryCategoryGridHandler
*
* @ingroup controllers_grid_settings_category
*
* @brief Handle operations for category management operations.
*/
namespace PKP\controllers\grid\settings\category;
use APP\core\Request;
use APP\facades\Repo;
use PKP\controllers\grid\CategoryGridHandler;
use PKP\controllers\grid\DataObjectGridCellProvider;
use PKP\controllers\grid\feature\OrderCategoryGridItemsFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\settings\category\form\CategoryForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\facades\Locale;
use PKP\file\TemporaryFileManager;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\Role;
class CategoryCategoryGridHandler extends CategoryGridHandler
{
public $_contextId;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid',
'fetchCategory',
'fetchRow',
'addCategory',
'editCategory',
'updateCategory',
'deleteCategory',
'uploadImage',
'saveSequence',
]
);
}
//
// Overridden 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 CategoryGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$context = $request->getContext();
$this->_contextId = $context->getId();
// Set the grid title.
$this->setTitle('grid.category.categories');
// Add grid-level actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addCategory',
new AjaxModal(
$router->url($request, null, null, 'addCategory'),
__('grid.category.add'),
'modal_manage'
),
__('grid.category.add'),
'add_category'
)
);
// Add grid columns.
$cellProvider = new DataObjectGridCellProvider();
$cellProvider->setLocale(Locale::getLocale());
$this->addColumn(
new GridColumn(
'title',
'grid.category.name',
null,
null,
$cellProvider
)
);
}
/**
* @copydoc GridHandler::loadData
*/
public function loadData($request, $filter)
{
// For top-level rows, only list categories without parents.
return Repo::category()->getCollector()
->filterByContextIds([$this->_getContextId()])
->filterByParentIds([null])
->getMany()
->toArray();
}
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return array_merge(
parent::initFeatures($request, $args),
[new OrderCategoryGridItemsFeature(OrderCategoryGridItemsFeature::ORDER_CATEGORY_GRID_CATEGORIES_AND_ROWS, true, $this)]
);
}
/**
* @copydoc CategoryGridHandler::getDataElementInCategorySequence()
*/
public function getDataElementInCategorySequence($categoryId, &$category)
{
return $category->getSequence();
}
/**
* @copydoc CategoryGridHandler::setDataElementInCategorySequence()
*/
public function setDataElementInCategorySequence($parentCategoryId, &$category, $newSequence)
{
$category->setSequence($newSequence);
Repo::category()->edit($category, []);
}
/**
* @copydoc GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($gridDataElement)
{
return $gridDataElement->getSequence();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $categoryId, $category, $newSequence)
{
$category->setSequence($newSequence);
Repo::category()->edit($category, []);
}
/**
* @copydoc CategoryGridHandler::getCategoryRowIdParameterName()
*/
public function getCategoryRowIdParameterName()
{
return 'parentCategoryId';
}
/**
* @copydoc GridHandler::getRowInstance()
*/
public function getRowInstance()
{
return new \PKP\controllers\grid\settings\category\CategoryGridRow();
}
/**
* @copydoc CategoryGridHandler::getCategoryRowInstance()
*/
public function getCategoryRowInstance()
{
return new \PKP\controllers\grid\settings\category\CategoryGridCategoryRow();
}
/**
* @copydoc CategoryGridHandler::loadCategoryData()
*
* @param null|mixed $filter
*/
public function loadCategoryData($request, &$category, $filter = null)
{
$categoryId = $category->getId();
return Repo::category()->getCollector()
->filterByContextIds([$this->_getContextId()])
->filterByParentIds([$categoryId])
->getMany()
->toArray();
}
/**
* Handle the add category operation.
*
* @param array $args
* @param PKPRequest $request
*/
public function addCategory($args, $request)
{
return $this->editCategory($args, $request);
}
/**
* Handle the edit category operation.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editCategory($args, $request)
{
$categoryForm = $this->_getCategoryForm($request);
$categoryForm->initData();
return new JSONMessage(true, $categoryForm->fetch($request));
}
/**
* Update category data in database and grid.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateCategory($args, $request)
{
$categoryForm = $this->_getCategoryForm($request);
$categoryForm->readInputData();
if ($categoryForm->validate()) {
$categoryForm->execute();
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(true, $categoryForm->fetch($request));
}
}
/**
* Delete a category
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteCategory($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$context = $request->getContext();
$category = Repo::category()->get((int) $request->getUserVar('categoryId'));
if ($category && $category->getContextId() == $context->getId()) {
Repo::category()->delete($category);
}
// FIXME delete dependent objects?
return \PKP\db\DAO::getDataChangedEvent();
}
/**
* Handle file uploads for cover/image art for things like Series and Categories.
*
* @param PKPRequest $request
* @param array $args
*
* @return JSONMessage JSON object
*/
public function uploadImage($args, $request)
{
$user = $request->getUser();
$temporaryFileManager = new TemporaryFileManager();
$temporaryFile = $temporaryFileManager->handleUpload('uploadedFile', $user->getId());
if ($temporaryFile) {
$json = new JSONMessage(true);
$json->setAdditionalAttributes([
'temporaryFileId' => $temporaryFile->getId()
]);
return $json;
} else {
return new JSONMessage(false, __('common.uploadFailed'));
}
}
//
// Private helper methods.
//
/**
* Get a CategoryForm instance.
*
* @param Request $request
*
* @return CategoryForm
*/
public function _getCategoryForm($request)
{
// Get the category ID.
$categoryId = (int) $request->getUserVar('categoryId');
// Instantiate the files form.
$contextId = $this->_getContextId();
return new CategoryForm($contextId, $categoryId);
}
/**
* Get context id.
*
* @return int
*/
public function _getContextId()
{
return $this->_contextId;
}
}
@@ -0,0 +1,89 @@
<?php
/**
* @file controllers/grid/settings/category/CategoryGridCategoryRow.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 CategoryGridCategoryRow
*
* @ingroup controllers_grid_settings_category
*
* @brief Category grid category row definition
*/
namespace PKP\controllers\grid\settings\category;
use APP\facades\Repo;
use PKP\controllers\grid\GridCategoryRow;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class CategoryGridCategoryRow extends GridCategoryRow
{
//
// Overridden methods from GridCategoryRow
//
/**
* @copydoc GridCategoryRow::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?
$categoryId = $this->getId();
if (!empty($categoryId) && is_numeric($categoryId)) {
// Only add row actions if this is an existing row
$category = $this->getData();
$router = $request->getRouter();
$childCategoryCount = Repo::category()->getCollector()
->filterByParentIds([$categoryId])
->getCount();
if ($childCategoryCount == 0) {
$this->addAction(
new LinkAction(
'deleteCategory',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.delete'),
$router->url($request, null, null, 'deleteCategory', null, ['categoryId' => $categoryId]),
'modal_delete'
),
__('grid.action.remove'),
'delete'
)
);
}
$this->addAction(new LinkAction(
'editCategory',
new AjaxModal(
$router->url($request, null, null, 'editCategory', null, ['categoryId' => $categoryId]),
__('grid.category.edit'),
'modal_edit'
),
$category->getLocalizedTitle()
), GridRow::GRID_ACTION_POSITION_ROW_CLICK);
}
}
/**
* Category rows only have one cell and one label. This is it.
* return string
*/
public function getCategoryLabel()
{
return '';
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @file controllers/grid/settings/category/CategoryGridRow.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 CategoryGridRow
*
* @ingroup controllers_grid_settings_category
*
* @brief Category grid row definition
*/
namespace PKP\controllers\grid\settings\category;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class CategoryGridRow extends GridRow
{
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$rowData = $this->getData(); // a Category object
assert($rowData != null);
$rowId = $this->getId();
// Only add row actions if this is an existing row.
if (!empty($rowId) && is_numeric($rowId)) {
$actionArgs = array_merge(
$this->getRequestArgs(),
['categoryId' => $rowData->getId()]
);
$router = $request->getRouter();
$this->addAction(new LinkAction(
'editCategory',
new AjaxModal(
$router->url($request, null, null, 'editCategory', null, $actionArgs),
__('grid.category.edit')
),
__('grid.action.edit'),
'edit'
));
$this->addAction(new LinkAction(
'removeCategory',
new RemoteActionConfirmationModal(
$request->getSession(),
__('grid.category.removeText'),
null,
$router->url($request, null, null, 'deleteCategory', null, $actionArgs)
),
__('grid.action.remove'),
'delete'
));
}
}
}
@@ -0,0 +1,427 @@
<?php
/**
* @file lib/pkp/controllers/grid/settings/category/form/CategoryForm.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 CategoryForm
*
* @ingroup controllers_grid_settings_category_form
*
* @brief Form to add/edit category.
*/
namespace PKP\controllers\grid\settings\category\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\template\TemplateManager;
use PKP\context\SubEditorsDAO;
use PKP\core\Core;
use PKP\db\DAORegistry;
use PKP\file\ContextFileManager;
use PKP\file\TemporaryFileDAO;
use PKP\file\TemporaryFileManager;
use PKP\form\Form;
use PKP\security\Role;
use PKP\userGroup\UserGroup;
class CategoryForm extends Form
{
/** @var int Id of the category being edited */
public $_categoryId;
/** @var int The context ID of the category being edited */
public $_contextId;
/** @var int $_userId The current user ID */
public $_userId;
/** @var string $_imageExtension Cover image extension */
public $_imageExtension;
/** @var array $_sizeArray Cover image information from getimagesize */
public $_sizeArray;
/** @var array Roles that can be assigned to this category */
public $assignableRoles = [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT];
/**
* Constructor.
*
* @param int $contextId Context id.
* @param int $categoryId Category id.
*/
public function __construct($contextId, $categoryId = null)
{
parent::__construct('controllers/grid/settings/category/form/categoryForm.tpl');
$this->_contextId = $contextId;
$this->_categoryId = $categoryId;
$request = Application::get()->getRequest();
$user = $request->getUser();
$this->_userId = $user->getId();
// Validation checks for this form
$form = $this;
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'name', 'required', 'grid.category.nameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorRegExp($this, 'path', 'required', 'grid.category.pathAlphaNumeric', '/^[a-zA-Z0-9\/._-]+$/'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom(
$this,
'path',
'required',
'grid.category.pathExists',
function ($path) use ($form, $contextId) {
$category = Repo::category()->getCollector()
->filterByContextIds([$contextId])
->filterByPaths([$path])
->getMany()
->first();
return !$category || $category->getPath() == $form->getData('oldPath');
}
));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the category id.
*
* @return int categoryId
*/
public function getCategoryId()
{
return $this->_categoryId;
}
/**
* Set the category ID for this section.
*
* @param int $categoryId
*/
public function setCategoryId($categoryId)
{
$this->_categoryId = $categoryId;
}
/**
* Get the context id.
*
* @return int contextId
*/
public function getContextId()
{
return $this->_contextId;
}
//
// Implement template methods from Form.
//
/**
* Get all locale field names
*/
public function getLocaleFieldNames()
{
return ['name', 'description'];
}
/**
* @see Form::initData()
*/
public function initData()
{
$category = Repo::category()->get($this->getCategoryId());
$this->setData('assignedSubeditors', []);
if ($category) {
if ($category->getContextId() != $this->getContextId()) {
throw new \Exception('Wrong context ID for category!');
}
$this->setData('name', $category->getTitle(null)); // Localized
$this->setData('description', $category->getDescription(null)); // Localized
$this->setData('parentId', $category->getParentId());
$this->setData('path', $category->getPath());
$this->setData('image', $category->getImage());
$sortOption = $category->getSortOption() ? $category->getSortOption() : Repo::submission()->getDefaultSortOption();
$this->setData('sortOption', $sortOption);
$subeditorUserGroups = [];
$assignedSubeditors = Repo::user()
->getCollector()
->filterByContextIds([Application::get()->getRequest()->getContext()->getId()])
->filterByRoleIds($this->assignableRoles)
->assignedToCategoryIds([$this->getCategoryId()])
->getIds()
->toArray();
if (!empty($assignedSubeditors)) {
$subEditorsDao = DAORegistry::getDAO('SubEditorsDAO'); /** @var SubEditorsDAO $subEditorsDao */
$subeditorUserGroups = $subEditorsDao->getAssignedUserGroupIds(
Application::get()->getRequest()->getContext()->getId(),
Application::ASSOC_TYPE_CATEGORY,
$this->getCategoryId(),
$assignedSubeditors
)->toArray();
}
$this->setData('subeditorUserGroups', $subeditorUserGroups);
}
return parent::initData();
}
/**
* @see Form::validate()
*/
public function validate($callHooks = true)
{
if ($temporaryFileId = $this->getData('temporaryFileId')) {
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */
$temporaryFile = $temporaryFileDao->getTemporaryFile($temporaryFileId, $this->_userId);
if (!$temporaryFile ||
!($this->_imageExtension = $temporaryFileManager->getImageExtension($temporaryFile->getFileType())) ||
!($this->_sizeArray = getimagesize($temporaryFile->getFilePath())) ||
$this->_sizeArray[0] <= 0 || $this->_sizeArray[1] <= 0
) {
$this->addError('temporaryFileId', __('form.invalidImage'));
return false;
}
}
return parent::validate($callHooks);
}
/**
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['name', 'parentId', 'path', 'description', 'temporaryFileId', 'sortOption', 'subEditors']);
// For path duplicate checking; excuse the current path.
if ($categoryId = $this->getCategoryId()) {
$category = Repo::category()->get($categoryId);
if ($category->getContextId() != $this->getContextId()) {
throw new \Exception('Wrong context ID for category!');
}
$this->setData('oldPath', $category->getPath());
}
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$context = $request->getContext();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('categoryId', $this->getCategoryId());
// Provide a list of root categories to the template
$rootCategoriesCollection = Repo::category()->getCollector()
->filterByParentIds([null])
->filterByContextIds([$context->getId()])
->getMany();
$rootCategories = [null => __('common.none')];
foreach ($rootCategoriesCollection as $category) {
$categoryId = $category->getId();
if ($categoryId != $this->getCategoryId()) {
// Don't permit time travel paradox
$rootCategories[$categoryId] = $category->getLocalizedTitle();
}
}
$templateMgr->assign('rootCategories', $rootCategories);
// Determine if this category has children of its own;
// if so, prevent the user from giving it a parent.
// (Forced two-level maximum tree depth.)
if ($this->getCategoryId()) {
$childCount = Repo::category()->getCollector()
->filterByParentIds([$this->getCategoryId()])
->filterByContextIds([$context->getId()])
->getCount();
$templateMgr->assign('cannotSelectChild', $childCount > 0);
}
// Sort options.
$templateMgr->assign('sortOptions', Repo::submission()->getSortSelectOptions());
$assignableUserGroups = Repo::userGroup()
->getCollector()
->filterByContextIds([$request->getContext()->getId()])
->filterByRoleIds($this->assignableRoles)
->filterByStageIds([WORKFLOW_STAGE_ID_SUBMISSION])
->getMany()
->map(function (UserGroup $userGroup) use ($request) {
return [
'userGroup' => $userGroup,
'users' => Repo::user()
->getCollector()
->filterByUserGroupIds([$userGroup->getId()])
->filterByContextIds([$request->getContext()->getId()])
->getMany()
->mapWithKeys(fn ($user, $key) => [$user->getId() => $user->getFullName()])
->toArray()
];
});
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'assignableUserGroups' => $assignableUserGroups->toArray(),
]);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$categoryId = $this->getCategoryId();
$context = Application::get()->getRequest()->getContext();
// Get a category object to edit or create
if ($categoryId == null) {
$category = Repo::category()->dao->newDataObject();
$category->setContextId($this->getContextId());
} else {
$category = Repo::category()->get($categoryId);
if ($category->getContextId() != $this->getContextId()) {
throw new \Exception('Wrong context ID for category!');
}
}
// Set the editable properties of the category object
$category->setTitle($this->getData('name'), null); // Localized
$category->setDescription($this->getData('description'), null); // Localized
$category->setParentId(((int) $this->getData('parentId')) ?: null);
$category->setPath($this->getData('path'));
$category->setSortOption($this->getData('sortOption'));
// Update or insert the category object
if ($categoryId == null) {
$this->setCategoryId(Repo::category()->add($category));
$category->setSequence(REALLY_BIG_NUMBER);
Repo::category()->dao->resequenceCategories($this->getContextId());
} else {
Repo::category()->edit($category, []);
}
// Update category editors
$subEditorsDao = DAORegistry::getDAO('SubEditorsDAO'); /** @var SubEditorsDAO $subEditorsDao */
$subEditorsDao->deleteBySubmissionGroupId($category->getId(), Application::ASSOC_TYPE_CATEGORY, $category->getContextId());
$subEditors = $this->getData('subEditors');
if (!empty($subEditors)) {
$allowedEditors = Repo::user()
->getCollector()
->filterByRoleIds($this->assignableRoles)
->filterByContextIds([$context->getId()])
->getIds();
foreach ($subEditors as $userGroupId => $userIds) {
foreach ($userIds as $userId) {
if (!$allowedEditors->contains($userId)) {
continue;
}
$subEditorsDao->insertEditor($context->getId(), $this->getCategoryId(), $userId, Application::ASSOC_TYPE_CATEGORY, (int) $userGroupId);
}
}
}
// Handle the image upload if there was one.
if ($temporaryFileId = $this->getData('temporaryFileId')) {
// Fetch the temporary file storing the uploaded library file
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */
$temporaryFile = $temporaryFileDao->getTemporaryFile($temporaryFileId, $this->_userId);
$temporaryFilePath = $temporaryFile->getFilePath();
$contextFileManager = new ContextFileManager($this->getContextId());
$basePath = $contextFileManager->getBasePath() . '/categories/';
// Delete the old file if it exists
$oldSetting = $category->getImage();
if ($oldSetting) {
$contextFileManager->deleteByPath($basePath . $oldSetting['thumbnailName']);
$contextFileManager->deleteByPath($basePath . $oldSetting['name']);
}
// The following variables were fetched in validation
assert($this->_sizeArray && $this->_imageExtension);
// Generate the surrogate images.
switch ($this->_imageExtension) {
case '.jpg': $image = imagecreatefromjpeg($temporaryFilePath);
break;
case '.png': $image = imagecreatefrompng($temporaryFilePath);
break;
case '.gif': $image = imagecreatefromgif($temporaryFilePath);
break;
default: $image = null; // Suppress warning
}
assert($image);
$context = Application::get()->getRequest()->getContext();
$coverThumbnailsMaxWidth = $context->getSetting('coverThumbnailsMaxWidth');
$coverThumbnailsMaxHeight = $context->getSetting('coverThumbnailsMaxHeight');
$thumbnailFilename = $category->getId() . '-category-thumbnail' . $this->_imageExtension;
$xRatio = min(1, ($coverThumbnailsMaxWidth ? $coverThumbnailsMaxWidth : 100) / $this->_sizeArray[0]);
$yRatio = min(1, ($coverThumbnailsMaxHeight ? $coverThumbnailsMaxHeight : 100) / $this->_sizeArray[1]);
$ratio = min($xRatio, $yRatio);
$thumbnailWidth = round($ratio * $this->_sizeArray[0]);
$thumbnailHeight = round($ratio * $this->_sizeArray[1]);
$thumbnail = imagecreatetruecolor($thumbnailWidth, $thumbnailHeight);
imagecopyresampled($thumbnail, $image, 0, 0, 0, 0, $thumbnailWidth, $thumbnailHeight, $this->_sizeArray[0], $this->_sizeArray[1]);
// Copy the new file over
$filename = $category->getId() . '-category' . $this->_imageExtension;
$contextFileManager->copyFile($temporaryFile->getFilePath(), $basePath . $filename);
switch ($this->_imageExtension) {
case '.jpg': imagejpeg($thumbnail, $basePath . $thumbnailFilename);
break;
case '.png': imagepng($thumbnail, $basePath . $thumbnailFilename);
break;
case '.gif': imagegif($thumbnail, $basePath . $thumbnailFilename);
break;
}
imagedestroy($thumbnail);
imagedestroy($image);
$category->setImage([
'name' => $filename,
'width' => $this->_sizeArray[0],
'height' => $this->_sizeArray[1],
'thumbnailName' => $thumbnailFilename,
'thumbnailWidth' => $thumbnailWidth,
'thumbnailHeight' => $thumbnailHeight,
'uploadName' => $temporaryFile->getOriginalFileName(),
'dateUploaded' => Core::getCurrentDate(),
]);
// Clean up the temporary file
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileManager->deleteById($temporaryFileId, $this->_userId);
}
// Update category object to store image information.
Repo::category()->edit($category, []);
parent::execute(...$functionArgs);
return $category;
}
}
@@ -0,0 +1,285 @@
<?php
/**
* @file controllers/grid/settings/genre/GenreGridHandler.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 GenreGridHandler
*
* @ingroup controllers_grid_settings_genre
*
* @brief Handle Genre grid requests.
*/
namespace PKP\controllers\grid\settings\genre;
use APP\facades\Repo;
use PKP\controllers\grid\DataObjectGridCellProvider;
use PKP\controllers\grid\feature\OrderGridItemsFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\settings\genre\form\GenreForm;
use PKP\controllers\grid\settings\SetupGridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAO;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\security\Role;
use PKP\submission\GenreDAO;
class GenreGridHandler extends SetupGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN], [
'fetchGrid', 'fetchRow',
'addGenre', 'editGenre', 'updateGenre',
'deleteGenre', 'restoreGenres', 'saveSequence'
]);
}
//
// Overridden template methods
//
/**
* Configure the grid
*
* @see SetupGridHandler::initialize
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Set the grid title.
$this->setTitle('grid.genres.title');
// Add grid-level actions
$router = $request->getRouter();
$actionArgs = ['gridId' => $this->getId()];
$this->addAction(
new LinkAction(
'addGenre',
new AjaxModal(
$router->url($request, null, null, 'addGenre', null, $actionArgs),
__('grid.action.addGenre'),
'modal_add_item',
true
),
__('grid.action.addGenre'),
'add_item'
)
);
$this->addAction(
new LinkAction(
'restoreGenres',
new RemoteActionConfirmationModal(
$request->getSession(),
__('grid.action.restoreDefaults.confirm'),
null,
$router->url($request, null, null, 'restoreGenres', null, $actionArgs),
'modal_delete'
),
__('grid.action.restoreDefaults'),
'reset_default'
)
);
// Columns
$cellProvider = new DataObjectGridCellProvider();
$cellProvider->setLocale(Locale::getLocale());
$this->addColumn(
new GridColumn(
'name',
'common.name',
null,
null,
$cellProvider
)
);
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
// Elements to be displayed in the grid
$context = $request->getContext();
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
return $genreDao->getEnabledByContextId($context->getId(), self::getRangeInfo($request, $this->getId()));
}
//
// Overridden methods from GridHandler
//
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new OrderGridItemsFeature()];
}
/**
* @copydoc GridHandler::getRowInstance()
*
* @return GenreGridRow
*/
protected function getRowInstance()
{
return new GenreGridRow();
}
/**
* @copydoc GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($row)
{
return $row->getSequence();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence)
{
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$context = $request->getContext();
$genre = $genreDao->getById($rowId, $context->getId());
$genre->setSequence($newSequence);
$genreDao->updateObject($genre);
}
//
// Public Genre Grid Actions
//
/**
* An action to add a new Genre
*
* @param array $args
* @param PKPRequest $request
*/
public function addGenre($args, $request)
{
// Calling editGenre with an empty row id will add a new Genre.
return $this->editGenre($args, $request);
}
/**
* An action to edit a Genre
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editGenre($args, $request)
{
$genreId = isset($args['genreId']) ? (int) $args['genreId'] : null;
$this->setupTemplate($request);
$genreForm = new GenreForm($genreId);
$genreForm->initData($args);
return new JSONMessage(true, $genreForm->fetch($request));
}
/**
* Update a Genre
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateGenre($args, $request)
{
$genreId = isset($args['genreId']) ? (int) $args['genreId'] : null;
$genreForm = new GenreForm($genreId);
$genreForm->readInputData();
if ($genreForm->validate()) {
$genreForm->execute();
return DAO::getDataChangedEvent($genreForm->getGenreId());
}
return new JSONMessage(false);
}
/**
* Delete a Genre.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteGenre($args, $request)
{
$genreId = isset($args['genreId']) ? (int) $args['genreId'] : null;
$context = $request->getContext();
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$genre = $genreDao->getById($genreId, $context->getId());
if (!$request->checkCSRF()) {
return new JSONMessage(false, __('form.csrfInvalid'));
}
if (!$genre) {
return new JSONMessage(false, __('manager.setup.errorDeletingItem'));
}
$submissionsByGenre = Repo::submissionFile()
->getCollector()
->filterByGenreIds([$genreId])
->getCount();
// Block the removal of genres that have at least one assigned submission file
if ($submissionsByGenre) {
return new JSONMessage(false, __('manager.genres.alertDelete'));
}
$genreDao->deleteObject($genre);
return DAO::getDataChangedEvent($genre->getId());
}
/**
* Restore the default Genre settings for the context.
* All default settings that were available when the context instance was created will be restored.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function restoreGenres($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
// Restore all the genres in this context form the registry XML file
$context = $request->getContext();
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$genreDao->installDefaults($context->getId(), $context->getSupportedFormLocales());
return DAO::getDataChangedEvent();
}
}
@@ -0,0 +1,77 @@
<?php
/**
* @file controllers/grid/settings/genre/GenreGridRow.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 GenreGridRow
*
* @ingroup controllers_grid_settings_genre
*
* @brief Handle Genre grid row requests.
*/
namespace PKP\controllers\grid\settings\genre;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class GenreGridRow extends GridRow
{
//
// Overridden template methods
//
/**
* @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?
$rowId = $this->getId();
if (!empty($rowId) && is_numeric($rowId)) {
$router = $request->getRouter();
$actionArgs = [
'gridId' => $this->getGridId(),
'genreId' => $rowId
];
$this->addAction(
new LinkAction(
'editGenre',
new AjaxModal(
$router->url($request, null, null, 'editGenre', null, $actionArgs),
__('grid.action.edit'),
'modal_edit',
true
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'deleteGenre',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('grid.action.delete'),
$router->url($request, null, null, 'deleteGenre', null, $actionArgs),
'modal_delete'
),
__('grid.action.delete'),
'delete'
)
);
}
}
}
@@ -0,0 +1,179 @@
<?php
/**
* @file controllers/grid/settings/genre/form/GenreForm.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 GenreForm
*
* @ingroup controllers_grid_settings_genre_form
*
* @brief Form for adding/editing a Submission File Genre.
*/
namespace PKP\controllers\grid\settings\genre\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\security\Validation;
use PKP\submission\Genre;
use PKP\submission\GenreDAO;
class GenreForm extends Form
{
/** @var int the id for the genre being edited */
public $_genreId;
/**
* Set the genre id
*
* @param int $genreId
*/
public function setGenreId($genreId)
{
$this->_genreId = $genreId;
}
/**
* Get the genre id
*
* @return int
*/
public function getGenreId()
{
return $this->_genreId;
}
/**
* Constructor.
*
* @param null|mixed $genreId
*/
public function __construct($genreId = null)
{
$this->setGenreId($genreId);
parent::__construct('controllers/grid/settings/genre/form/genreForm.tpl');
$request = Application::get()->getRequest();
$context = $request->getContext();
// Validation checks for this form
$form = $this;
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'name', 'required', 'manager.setup.form.genre.nameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom($this, 'key', 'optional', 'manager.setup.genres.key.exists', function ($key) use ($context, $form) {
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
return $key == '' || !$genreDao->keyExists($key, $context->getId(), $form->getGenreId());
}));
$this->addCheck(new \PKP\form\validation\FormValidatorRegExp($this, 'key', 'optional', 'manager.setup.genres.key.alphaNumeric', '/^[a-z0-9]+([\-_][a-z0-9]+)*$/i'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Initialize form data from current settings.
*
* @param array $args
*/
public function initData($args = [])
{
$request = Application::get()->getRequest();
$context = $request->getContext();
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
if ($this->getGenreId()) {
$genre = $genreDao->getById($this->getGenreId(), $context->getId());
}
if (isset($genre)) {
$this->_data = [
'genreId' => $this->getGenreId(),
'name' => $genre->getName(null),
'category' => $genre->getCategory(),
'dependent' => $genre->getDependent(),
'supplementary' => $genre->getSupplementary(),
'required' => $genre->getRequired(),
'key' => $genre->getKey(),
'keyReadOnly' => $genre->isDefault(),
];
} else {
$this->_data = [
'name' => [],
];
}
// grid related data
$this->_data['gridId'] = $args['gridId'];
$this->_data['rowId'] = $args['rowId'] ?? null;
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('submissionFileCategories', [
Genre::GENRE_CATEGORY_DOCUMENT => __('submission.document'),
Genre::GENRE_CATEGORY_ARTWORK => __('submission.art'),
Genre::GENRE_CATEGORY_SUPPLEMENTARY => __('submission.supplementary'),
]);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['genreId', 'name', 'category', 'dependent', 'supplementary', 'required', 'gridId', 'rowId', 'key']);
}
/**
* @copydoc Form::execute()
*
* @return bool
*/
public function execute(...$functionArgs)
{
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$request = Application::get()->getRequest();
$context = $request->getContext();
// Update or insert genre
if (!$this->getGenreId()) {
$genre = $genreDao->newDataObject();
$genre->setContextId($context->getId());
} else {
$genre = $genreDao->getById($this->getGenreId(), $context->getId());
}
$genre->setData('name', $this->getData('name'), null); // Localized
$genre->setCategory($this->getData('category'));
$genre->setDependent($this->getData('dependent'));
$genre->setSupplementary($this->getData('supplementary'));
$genre->setRequired((bool) $this->getData('required'));
if (!$genre->isDefault()) {
$genre->setKey($this->getData('key'));
}
if (!$this->getGenreId()) {
$this->setGenreId($genreDao->insertObject($genre));
} else {
$genreDao->updateObject($genre);
}
parent::execute(...$functionArgs);
return true;
}
}
@@ -0,0 +1,128 @@
<?php
/**
* @file controllers/grid/settings/languages/ManageLanguageGridHandler.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 ManageLanguageGridHandler
*
* @ingroup controllers_grid_settings_languages
*
* @brief Handle language management grid requests only.
*/
namespace PKP\controllers\grid\settings\languages;
use APP\core\Request;
use APP\core\Services;
use APP\notification\NotificationManager;
use PKP\controllers\grid\languages\LanguageGridHandler;
use PKP\core\JSONMessage;
use PKP\facades\Locale;
use PKP\notification\PKPNotification;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\Role;
class ManageLanguageGridHandler extends LanguageGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['saveLanguageSetting', 'setContextPrimaryLocale', 'reloadLocale', 'fetchGrid', 'fetchRow']
);
}
//
// Implement methods from GridHandler.
//
/**
* @copydoc GridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$site = $request->getSite();
$context = $request->getContext();
$allLocales = Locale::getLocales();
$supportedLocales = $site->getSupportedLocales();
$contextPrimaryLocale = $context->getPrimaryLocale();
$data = [];
foreach ($supportedLocales as $locale) {
$formattedLocale = Locale::getFormattedDisplayNames([$locale], $allLocales);
$data[$locale] = [];
$data[$locale]['code'] = $locale;
$data[$locale]['name'] = array_shift($formattedLocale);
$data[$locale]['supported'] = true;
$data[$locale]['primary'] = ($locale == $contextPrimaryLocale);
}
$data = $this->addManagementData($request, $data);
return $data;
}
//
// Extended methods from LanguageGridHandler.
//
/**
* @copydoc LanguageGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$this->addNameColumn();
$this->addLocaleCodeColumn();
$this->addPrimaryColumn('contextPrimary');
$this->addManagementColumns();
}
/**
* Reload locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function reloadLocale($args, $request)
{
$context = $request->getContext();
$locale = $request->getUserVar('rowId');
$gridData = $this->getGridDataElements($request);
if (empty($context) || !$request->checkCSRF() || !array_key_exists($locale, $gridData)) {
return new JSONMessage(false);
}
$context = Services::get('context')->restoreLocaleDefaults($context, $request, $locale);
$notificationManager = new NotificationManager();
$notificationManager->createTrivialNotification(
$request->getUser()->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeReloaded', ['locale' => $gridData[$locale]['name'], 'contextName' => $context->getLocalizedName()])]
);
return \PKP\db\DAO::getDataChangedEvent($locale);
}
}
@@ -0,0 +1,100 @@
<?php
/**
* @file controllers/grid/settings/library/LibraryFileAdminGridDataProvider.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 LibraryFileAdminGridDataProvider
*
* @ingroup controllers_grid_settings_library
*
* @brief The data provider for the admin library files grid.
*/
namespace PKP\controllers\grid\settings\library;
use PKP\context\Context;
use PKP\context\LibraryFileDAO;
use PKP\controllers\grid\CategoryGridDataProvider;
use PKP\db\DAORegistry;
use PKP\security\authorization\ContextAccessPolicy;
class LibraryFileAdminGridDataProvider extends CategoryGridDataProvider
{
/** @var Context the context for this library */
public $_context;
/** @var bool Whether or not this grid is editable */
public $_canEdit;
/**
* Constructor
*/
public function __construct($canEdit)
{
$this->_canEdit = $canEdit;
parent::__construct();
}
//
// Getters and Setters
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
$this->_context = $request->getContext();
return new ContextAccessPolicy($request, $roleAssignments);
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
return ['canEdit' => $this->canEdit()];
}
/**
* get the current context
*
* @return $context Context
*/
public function &getContext()
{
return $this->_context;
}
/**
* get whether or not this grid is editable (has actions).
*
* @return bool $canEdit
*/
public function canEdit()
{
return $this->_canEdit;
}
/**
* @copydoc CategoryGridHandler::loadCategoryData()
*
* @param null|mixed $filter
*/
public function loadCategoryData($request, $fileType, $filter = null)
{
// Elements to be displayed in the grid
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$context = $this->getContext();
$libraryFiles = $libraryFileDao->getByContextId($context->getId(), $fileType);
return $libraryFiles->toAssociativeArray();
}
}
@@ -0,0 +1,86 @@
<?php
/**
* @file controllers/grid/settings/library/LibraryFileAdminGridHandler.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 LibraryFileAdminGridHandler
*
* @ingroup controllers_grid_settings_library
*
* @brief Handle library file grid requests.
*/
namespace PKP\controllers\grid\settings\library;
use PKP\context\Context;
use PKP\controllers\grid\files\LibraryFileGridHandler;
use PKP\controllers\grid\settings\library\form\EditLibraryFileForm;
use PKP\controllers\grid\settings\library\form\NewLibraryFileForm;
use PKP\security\Role;
class LibraryFileAdminGridHandler extends LibraryFileGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(new LibraryFileAdminGridDataProvider(true));
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid', 'addFile', 'uploadFile', 'saveFile', // Adding new library files
'editFile', 'updateFile', // Editing existing library files
'deleteFile'
]
);
}
//
// Overridden template methods
//
/**
* Configure the grid
*
* @see LibraryGridHandler::initialize
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
// determine if this grid is read only.
$this->setCanEdit((bool) $request->getUserVar('canEdit'));
parent::initialize($request, $args);
}
/**
* Returns a specific instance of the new form for this grid.
*
* @param Context $context
*
* @return NewLibraryFileForm
*/
public function _getNewFileForm($context)
{
return new NewLibraryFileForm($context->getId());
}
/**
* Returns a specific instance of the edit form for this grid.
*
* @param Context $context
* @param int $fileId
*
* @return EditLibraryFileForm
*/
public function _getEditFileForm($context, $fileId)
{
return new EditLibraryFileForm($context->getId(), $fileId);
}
}
@@ -0,0 +1,105 @@
<?php
/**
* @file controllers/grid/settings/library/form/EditLibraryFileForm.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 EditLibraryFileForm
*
* @ingroup controllers_grid_file_form
*
* @brief Form for editing a library file
*/
namespace PKP\controllers\grid\settings\library\form;
use APP\core\Application;
use APP\file\LibraryFileManager;
use PKP\context\LibraryFile;
use PKP\context\LibraryFileDAO;
use PKP\controllers\grid\files\form\LibraryFileForm;
use PKP\db\DAORegistry;
use PKP\file\TemporaryFileManager;
class EditLibraryFileForm extends LibraryFileForm
{
/** @var LibraryFile the file being edited, or null for new */
public $libraryFile;
/** @var int the id of the context this library file is attached to */
public $contextId;
/**
* Constructor.
*
* @param int $contextId
* @param int $fileId optional
*/
public function __construct($contextId, $fileId)
{
parent::__construct('controllers/grid/settings/library/form/editFileForm.tpl', $contextId);
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$this->libraryFile = $libraryFileDao->getById($fileId);
if (!$this->libraryFile || $this->libraryFile->getContextId() != $this->contextId) {
fatalError('Invalid library file!');
}
}
/**
* Assign form data to user-submitted data.
* @see Form::readInputData()
*/
function readInputData() {
$this->readUserVars(array('temporaryFileId'));
return parent::readInputData();
}
/**
* Initialize form data from current settings.
*/
public function initData()
{
$this->_data = [
'libraryFileName' => $this->libraryFile->getName(null), // Localized
'libraryFile' => $this->libraryFile, // For read-only info
'publicAccess' => $this->libraryFile->getPublicAccess() ? true : false,
'temporaryFileId' => null,
];
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$userId = Application::get()->getRequest()->getUser()->getId();
// Fetch the temporary file storing the uploaded library file
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /* @var $temporaryFileDao TemporaryFileDAO */
$temporaryFile = $temporaryFileDao->getTemporaryFile(
$this->getData('temporaryFileId'),
$userId
);
if ($temporaryFile) {
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /* @var $libraryFileDao LibraryFileDAO */
$libraryFileManager = new LibraryFileManager($this->contextId);
// Convert the temporary file to a library file and store
$this->libraryFile = $libraryFileManager->replaceFromTemporaryFile($temporaryFile, $this->getData('fileType'), $this->libraryFile);
// Clean up the temporary file
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileManager->deleteById($this->getData('temporaryFileId'), $userId);
}
$this->libraryFile->setName($this->getData('libraryFileName'), null); // Localized
$this->libraryFile->setType($this->getData('fileType'));
$this->libraryFile->setPublicAccess($this->getData('publicAccess'));
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$libraryFileDao->updateObject($this->libraryFile);
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,86 @@
<?php
/**
* @file controllers/grid/settings/library/form/NewLibraryFileForm.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 NewLibraryFileForm
*
* @ingroup controllers_grid_file_form
*
* @brief Form for adding/editing a file
* stores/retrieves from an associative array
*/
namespace PKP\controllers\grid\settings\library\form;
use APP\core\Application;
use APP\file\LibraryFileManager;
use PKP\context\LibraryFileDAO;
use PKP\controllers\grid\files\form\LibraryFileForm;
use PKP\db\DAORegistry;
use PKP\file\TemporaryFileDAO;
use PKP\file\TemporaryFileManager;
class NewLibraryFileForm extends LibraryFileForm
{
/**
* Constructor.
*
* @param int $contextId
*/
public function __construct($contextId)
{
parent::__construct('controllers/grid/settings/library/form/newFileForm.tpl', $contextId);
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'temporaryFileId', 'required', 'settings.libraryFiles.fileRequired'));
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['temporaryFileId']);
return parent::readInputData();
}
/**
* @copydoc Form::execute()
*
* @return $fileId int The new library file id.
*/
public function execute(...$functionArgs)
{
$userId = Application::get()->getRequest()->getUser()->getId();
// Fetch the temporary file storing the uploaded library file
$temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */
$temporaryFile = $temporaryFileDao->getTemporaryFile(
$this->getData('temporaryFileId'),
$userId
);
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$libraryFileManager = new LibraryFileManager($this->contextId);
// Convert the temporary file to a library file and store
$libraryFile = $libraryFileManager->copyFromTemporaryFile($temporaryFile, $this->getData('fileType'));
assert(isset($libraryFile));
$libraryFile->setContextId($this->contextId);
$libraryFile->setName($this->getData('libraryFileName'), null); // Localized
$libraryFile->setType($this->getData('fileType'));
$libraryFile->setPublicAccess($this->getData('publicAccess'));
$fileId = $libraryFileDao->insertObject($libraryFile);
// Clean up the temporary file
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileManager->deleteById($this->getData('temporaryFileId'), $userId);
parent::execute(...$functionArgs);
return $fileId;
}
}
@@ -0,0 +1,46 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormElementGridCellProvider.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 ReviewFormElementGridCellProvider
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief Subclass for review form element column's cell provider
*/
namespace PKP\controllers\grid\settings\reviewForms;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
class ReviewFormElementGridCellProvider extends 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\reviewForm\ReviewFormElement && !empty($columnId));
switch ($columnId) {
case 'question':
$label = $element->getLocalizedQuestion();
return ['label' => $label];
default:
assert(false);
break;
}
}
}
@@ -0,0 +1,75 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormElementGridRow.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 ReviewFormElementGridRow
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief ReviewFormElements grid row definition
*/
namespace PKP\controllers\grid\settings\reviewForms;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class ReviewFormElementGridRow extends GridRow
{
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
// add grid row actions: edit, delete
$element = parent::getData();
assert($element instanceof \PKP\reviewForm\ReviewFormElement);
$rowId = $this->getId();
$router = $request->getRouter();
if (!empty($rowId) && is_numeric($rowId)) {
// add 'edit' grid row action
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editReviewFormElement', null, ['rowId' => $rowId, 'reviewFormId' => $element->getReviewFormId()]),
__('grid.action.edit'),
'modal_edit',
true
),
__('grid.action.edit'),
'edit'
)
);
// add 'delete' grid row action
$this->addAction(
new LinkAction(
'delete',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.reviewFormElements.confirmDelete'),
null,
$router->url($request, null, null, 'deleteReviewFormElement', null, ['rowId' => $rowId, 'reviewFormId' => $element->getReviewFormId()])
),
__('grid.action.delete'),
'delete'
)
);
}
}
}
@@ -0,0 +1,291 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormElementsGridHandler.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 ReviewFormElementsGridHandler
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief Handle review form element grid requests.
*/
namespace PKP\controllers\grid\settings\reviewForms;
use APP\core\Application;
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\reviewForms\form\ReviewFormElementForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\reviewForm\ReviewFormDAO;
use PKP\reviewForm\ReviewFormElementDAO;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
class ReviewFormElementsGridHandler extends GridHandler
{
/** @var int Review form ID */
public $reviewFormId;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['fetchGrid', 'fetchRow', 'saveSequence',
'createReviewFormElement', 'editReviewFormElement', 'deleteReviewFormElement', 'updateReviewFormElement']
);
}
//
// Implement template methods from PKPHandler.
//
/**
* @see PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);
$this->reviewFormId = (int) $request->getUserVar('reviewFormId');
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
if (!$reviewFormDao->reviewFormExists($this->reviewFormId, Application::getContextAssocType(), $request->getContext()->getId())) {
return false;
}
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Grid actions.
$router = $request->getRouter();
// Create Review Form Element link
$this->addAction(
new LinkAction(
'createReviewFormElement',
new AjaxModal(
$router->url($request, null, null, 'createReviewFormElement', null, ['reviewFormId' => $this->reviewFormId]),
__('manager.reviewFormElements.create'),
'modal_add_item',
true
),
__('manager.reviewFormElements.create'),
'add_item'
)
);
//
// Grid columns.
//
$reviewFormElementGridCellProvider = new ReviewFormElementGridCellProvider();
// Review form element name.
$this->addColumn(
new GridColumn(
'question',
'manager.reviewFormElements.question',
null,
null,
$reviewFormElementGridCellProvider,
['html' => true, 'maxLength' => 220]
)
);
// Basic grid configuration.
$this->setTitle('manager.reviewFormElements');
}
//
// Implement methods from GridHandler.
//
/**
* @see GridHandler::addFeatures()
*/
public function initFeatures($request, $args)
{
return [new OrderGridItemsFeature()];
}
/**
* @see GridHandler::getRowInstance()
*
* @return ReviewFormElementGridRow
*/
protected function getRowInstance()
{
return new ReviewFormElementGridRow();
}
/**
* @copydoc GridHandler::loadData()
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
// Get review form elements.
//$rangeInfo = $this->getRangeInfo('reviewFormElements');
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElements = $reviewFormElementDao->getByReviewFormId($this->reviewFormId, null); //FIXME add range info?
return $reviewFormElements->toAssociativeArray();
}
/**
* @copydoc CategoryGridHandler::getRequestArgs()
*/
public function getRequestArgs()
{
return array_merge(['reviewFormId' => $this->reviewFormId], parent::getRequestArgs());
}
/**
* @copydoc GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($gridDataElement)
{
return $gridDataElement->getSequence();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence)
{
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$gridDataElement->setSequence($newSequence);
$reviewFormElementDao->updateObject($gridDataElement);
}
//
// Public grid actions.
//
/**
* Add a new review form element.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function createReviewFormElement($args, $request)
{
// Form handling
$reviewFormElementForm = new ReviewFormElementForm($this->reviewFormId);
$reviewFormElementForm->initData();
return new JSONMessage(true, $reviewFormElementForm->fetch($request));
}
/**
* Edit an existing review form element.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editReviewFormElement($args, $request)
{
// Identify the review form element Id
$reviewFormElementId = (int) $request->getUserVar('rowId');
// Display form
$reviewFormElementForm = new ReviewFormElementForm($this->reviewFormId, $reviewFormElementId);
$reviewFormElementForm->initData();
return new JSONMessage(true, $reviewFormElementForm->fetch($request));
}
/**
* Save changes to a review form element.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateReviewFormElement($args, $request)
{
$reviewFormElementId = (int) $request->getUserVar('reviewFormElementId');
$context = $request->getContext();
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewForm = $reviewFormDao->getById($this->reviewFormId, Application::getContextAssocType(), $context->getId());
if (!$reviewFormDao->unusedReviewFormExists($this->reviewFormId, Application::getContextAssocType(), $context->getId()) || ($reviewFormElementId && !$reviewFormElementDao->reviewFormElementExists($reviewFormElementId, $this->reviewFormId))) {
fatalError('Invalid review form information!');
}
$reviewFormElementForm = new ReviewFormElementForm($this->reviewFormId, $reviewFormElementId);
$reviewFormElementForm->readInputData();
if ($reviewFormElementForm->validate()) {
$reviewFormElementId = $reviewFormElementForm->execute();
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($reviewFormElementId);
}
return new JSONMessage(false);
}
/**
* Delete a review form element.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteReviewFormElement($args, $request)
{
$reviewFormElementId = (int) $request->getUserVar('rowId');
$context = $request->getContext();
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
if ($request->checkCSRF() && $reviewFormDao->unusedReviewFormExists($this->reviewFormId, Application::getContextAssocType(), $context->getId())) {
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElementDao->deleteById($reviewFormElementId);
return \PKP\db\DAO::getDataChangedEvent($reviewFormElementId);
}
return new JSONMessage(false);
}
}
@@ -0,0 +1,104 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormGridCellProvider.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 ReviewFormGridCellProvider
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief Subclass for review form column's cell provider
*/
namespace PKP\controllers\grid\settings\reviewForms;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\reviewForm\ReviewForm;
class ReviewFormGridCellProvider extends 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 ReviewForm && !empty($columnId));
switch ($columnId) {
case 'name':
return ['label' => $element->getLocalizedTitle()];
case 'inReview':
return ['label' => $element->getIncompleteCount()];
case 'completed':
return ['label' => $element->getCompleteCount()];
case 'active':
return ['selected' => $element->getActive()];
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
/**
* @see GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
switch ($column->getId()) {
case 'active':
/** @var ReviewForm */
$element = $row->getData();
$router = $request->getRouter();
if ($element->getActive()) {
return [new LinkAction(
'deactivateReviewForm',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.reviewForms.confirmDeactivate'),
null,
$router->url(
$request,
null,
'grid.settings.reviewForms.ReviewFormGridHandler',
'deactivateReviewForm',
null,
['reviewFormKey' => $element->getId()]
)
)
)];
} else {
return [new LinkAction(
'activateReviewForm',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.reviewForms.confirmActivate'),
null,
$router->url(
$request,
null,
'grid.settings.reviewForms.ReviewFormGridHandler',
'activateReviewForm',
null,
['reviewFormKey' => $element->getId()]
)
)
)];
}
}
return parent::getCellActions($request, $row, $column, $position);
}
}
@@ -0,0 +1,525 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormGridHandler.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 ReviewFormGridHandler
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief Handle review form grid requests.
*/
namespace PKP\controllers\grid\settings\reviewForms;
use APP\core\Application;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use PKP\controllers\grid\feature\OrderGridItemsFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\settings\reviewForms\form\PreviewReviewForm;
use PKP\controllers\grid\settings\reviewForms\form\ReviewFormForm;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\reviewForm\ReviewFormDAO;
use PKP\reviewForm\ReviewFormElementDAO;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
class ReviewFormGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['fetchGrid', 'fetchRow', 'createReviewForm', 'editReviewForm', 'updateReviewForm',
'reviewFormBasics', 'reviewFormElements', 'copyReviewForm',
'reviewFormPreview', 'activateReviewForm', 'deactivateReviewForm', 'deleteReviewForm',
'saveSequence']
);
}
//
// Implement template methods from PKPHandler.
//
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Basic grid configuration.
$this->setTitle('manager.reviewForms');
// Grid actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'createReviewForm',
new AjaxModal(
$router->url($request, null, null, 'createReviewForm', null, null),
__('manager.reviewForms.create'),
'modal_add_item',
true
),
__('manager.reviewForms.create'),
'add_item'
)
);
//
// Grid columns.
//
$reviewFormGridCellProvider = new ReviewFormGridCellProvider();
// Review form name.
$this->addColumn(
new GridColumn(
'name',
'manager.reviewForms.title',
null,
null,
$reviewFormGridCellProvider
)
);
// Review Form 'in review'
$this->addColumn(
new GridColumn(
'inReview',
'manager.reviewForms.inReview',
null,
null,
$reviewFormGridCellProvider
)
);
// Review Form 'completed'.
$this->addColumn(
new GridColumn(
'completed',
'manager.reviewForms.completed',
null,
null,
$reviewFormGridCellProvider
)
);
// Review form 'activate/deactivate'
// if ($element->getActive()) {
$this->addColumn(
new GridColumn(
'active',
'common.active',
null,
'controllers/grid/common/cell/selectStatusCell.tpl',
$reviewFormGridCellProvider
)
);
}
/**
* @see PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);
return parent::authorize($request, $args, $roleAssignments);
}
//
// Implement methods from GridHandler.
//
/**
* @see GridHandler::getRowInstance()
*
* @return ReviewFormGridRow
*/
protected function getRowInstance()
{
return new ReviewFormGridRow();
}
/**
* @copydoc GridHandler::loadData()
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
// Get all review forms.
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$context = $request->getContext();
$reviewForms = $reviewFormDao->getByAssocId(Application::getContextAssocType(), $context->getId());
return $reviewForms->toAssociativeArray();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence)
{
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$gridDataElement->setSequence($newSequence);
$reviewFormDao->updateObject($gridDataElement);
}
/**
* @see lib/pkp/classes/controllers/grid/GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($reviewForm)
{
return $reviewForm->getSequence();
}
/**
* @see GridHandler::addFeatures()
*/
public function initFeatures($request, $args)
{
return [new OrderGridItemsFeature()];
}
//
// Public grid actions.
//
/**
* Preview a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function reviewFormPreview($args, $request)
{
// Identify the review form ID.
$reviewFormId = (int) $request->getUserVar('reviewFormId');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
$previewReviewForm = new PreviewReviewForm($reviewFormId);
$previewReviewForm->initData();
return new JSONMessage(true, $previewReviewForm->fetch($request));
}
/**
* Add a new review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function createReviewForm($args, $request)
{
// Form handling.
$reviewFormForm = new ReviewFormForm(null);
$reviewFormForm->initData();
return new JSONMessage(true, $reviewFormForm->fetch($request));
}
/**
* Edit an existing review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editReviewForm($args, $request)
{
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$context = $request->getContext();
$reviewForm = $reviewFormDao->getById(
$request->getUserVar('rowId'),
Application::getContextAssocType(),
$context->getId()
);
// Display 'editReviewForm' tabs
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'preview' => $request->getUserVar('preview'),
'reviewFormId' => $reviewForm->getId(),
'canEdit' => $reviewForm->getIncompleteCount() == 0 && $reviewForm->getCompleteCount() == 0,
]);
return new JSONMessage(true, $templateMgr->fetch('controllers/grid/settings/reviewForms/editReviewForm.tpl'));
}
/**
* Edit an existing review form's basics (title, description)
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function reviewFormBasics($args, $request)
{
// Identify the review form Id
$reviewFormId = (int) $request->getUserVar('reviewFormId');
// Form handling
$reviewFormForm = new ReviewFormForm($reviewFormId);
$reviewFormForm->initData();
return new JSONMessage(true, $reviewFormForm->fetch($request));
}
/**
* Display a list of the review form elements within a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function reviewFormElements($args, $request)
{
$templateMgr = TemplateManager::getManager($request);
$dispatcher = $request->getDispatcher();
return $templateMgr->fetchAjax(
'reviewFormElementsGridContainer',
$dispatcher->url(
$request,
PKPApplication::ROUTE_COMPONENT,
null,
'grid.settings.reviewForms.ReviewFormElementsGridHandler',
'fetchGrid',
null,
['reviewFormId' => (int) $request->getUserVar('reviewFormId')]
)
);
}
/**
* Update an existing review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON message
*/
public function updateReviewForm($args, $request)
{
// Identify the review form Id.
$reviewFormId = (int) $request->getUserVar('reviewFormId');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
// Form handling.
$reviewFormForm = new ReviewFormForm(!isset($reviewFormId) || empty($reviewFormId) ? null : $reviewFormId);
$reviewFormForm->readInputData();
if ($reviewFormForm->validate()) {
$reviewFormForm->execute();
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($reviewFormId);
}
return new JSONMessage(false);
}
/**
* Copy a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function copyReviewForm($args, $request)
{
// Identify the current review form
$reviewFormId = (int) $request->getUserVar('rowId');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
if ($request->checkCSRF() && isset($reviewForm)) {
$reviewForm->setActive(0);
$reviewForm->setSequence(REALLY_BIG_NUMBER);
$newReviewFormId = $reviewFormDao->insertObject($reviewForm);
$reviewFormDao->resequenceReviewForms(Application::getContextAssocType(), $context->getId());
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElements = $reviewFormElementDao->getByReviewFormId($reviewFormId);
while ($reviewFormElement = $reviewFormElements->next()) {
$reviewFormElement->setReviewFormId($newReviewFormId);
$reviewFormElement->setSequence(REALLY_BIG_NUMBER);
$reviewFormElementDao->insertObject($reviewFormElement);
$reviewFormElementDao->resequenceReviewFormElements($newReviewFormId);
}
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($newReviewFormId);
}
return new JSONMessage(false);
}
/**
* Activate a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function activateReviewForm($args, $request)
{
// Identify the current review form
$reviewFormId = (int) $request->getUserVar('reviewFormKey');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
if ($request->checkCSRF() && isset($reviewForm) && !$reviewForm->getActive()) {
$reviewForm->setActive(1);
$reviewFormDao->updateObject($reviewForm);
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($reviewFormId);
}
return new JSONMessage(false);
}
/**
* Deactivate a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deactivateReviewForm($args, $request)
{
// Identify the current review form
$reviewFormId = (int) $request->getUserVar('reviewFormKey');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
if ($request->checkCSRF() && isset($reviewForm) && $reviewForm->getActive()) {
$reviewForm->setActive(0);
$reviewFormDao->updateObject($reviewForm);
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($reviewFormId);
}
return new JSONMessage(false);
}
/**
* Delete a review form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteReviewForm($args, $request)
{
// Identify the current review form
$reviewFormId = (int) $request->getUserVar('rowId');
// Identify the context id.
$context = $request->getContext();
// Get review form object
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormId, Application::getContextAssocType(), $context->getId());
if ($request->checkCSRF() && isset($reviewForm) && $reviewForm->getCompleteCount() == 0 && $reviewForm->getIncompleteCount() == 0) {
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignments = $reviewAssignmentDao->getByReviewFormId($reviewFormId);
foreach ($reviewAssignments as $reviewAssignment) {
$reviewAssignment->setReviewFormId(null);
$reviewAssignmentDao->updateObject($reviewAssignment);
}
$reviewFormDao->deleteById($reviewFormId);
// Create the notification.
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$notificationMgr->createTrivialNotification($user->getId());
return \PKP\db\DAO::getDataChangedEvent($reviewFormId);
}
return new JSONMessage(false);
}
}
@@ -0,0 +1,116 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/ReviewFormGridRow.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 ReviewFormGridRow
*
* @ingroup controllers_grid_settings_reviewForms
*
* @brief ReviewForm grid row definition
*/
namespace PKP\controllers\grid\settings\reviewForms;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class ReviewFormGridRow extends GridRow
{
//
// 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($element instanceof \PKP\reviewForm\ReviewForm);
$rowId = $this->getId();
if (!empty($rowId) && is_numeric($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
// determine whether or not this Review Form is editable.
$canEdit = ($element->getIncompleteCount() == 0 && $element->getCompleteCount() == 0);
// if review form is editable, add 'edit' grid row action
if ($canEdit) {
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editReviewForm', null, ['rowId' => $rowId]),
__('grid.action.edit'),
'modal_edit',
true
),
__('grid.action.edit'),
'edit'
)
);
}
// if review form is not editable, add 'copy' grid row action
$this->addAction(
new LinkAction(
'copy',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.reviewForms.confirmCopy'),
null,
$router->url($request, null, null, 'copyReviewForm', null, ['rowId' => $rowId])
),
__('grid.action.copy'),
'copy'
)
);
// add 'preview' grid row action
$this->addAction(
new LinkAction(
'preview',
new AjaxModal(
$router->url($request, null, null, 'editReviewForm', null, ['rowId' => $rowId, 'preview' => 1]),
__('grid.action.preview'),
'preview',
true
),
__('grid.action.preview'),
'preview'
)
);
// if review form is editable, add 'delete' grid row action.
if ($canEdit) {
$this->addAction(
new LinkAction(
'delete',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.reviewForms.confirmDelete'),
null,
$router->url($request, null, null, 'deleteReviewForm', null, ['rowId' => $rowId])
),
__('grid.action.delete'),
'delete'
)
);
}
}
}
}
@@ -0,0 +1,86 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/form/PKPPreviewReviewForm.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 PreviewReviewForm
*
* @ingroup controllers_grid_settings_reviewForms_form
*
* @brief Form for manager to preview review form.
*/
namespace PKP\controllers\grid\settings\reviewForms\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\core\JSONMessage;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\reviewForm\ReviewForm;
use PKP\reviewForm\ReviewFormDAO;
use PKP\reviewForm\ReviewFormElementDAO;
use PKP\security\Validation;
class PreviewReviewForm extends Form
{
/** @var int The ID of the review form being edited */
public $reviewFormId;
/**
* Constructor.
*
* @param int $reviewFormId omit for a new review form
*/
public function __construct($reviewFormId = null)
{
parent::__construct('manager/reviewForms/previewReviewForm.tpl');
$this->reviewFormId = (int) $reviewFormId;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* @copydoc Form::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$json = new JSONMessage();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('reviewFormId', $this->reviewFormId);
return parent::fetch($request, $template, $display);
}
/**
* Initialize form data from current settings.
*/
public function initData()
{
if ($this->reviewFormId) {
// Get review form
$request = Application::get()->getRequest();
$context = $request->getContext();
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($this->reviewFormId, Application::getContextAssocType(), $context->getId()); /** @var ReviewForm $reviewForm */
// Get review form elements
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElements = $reviewFormElementDao->getByReviewFormId($this->reviewFormId);
// Set data
$this->setData('title', $reviewForm->getLocalizedTitle());
$this->setData('description', $reviewForm->getLocalizedDescription());
$this->setData('reviewFormElements', $reviewFormElements);
}
}
}
@@ -0,0 +1,214 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/form/ReviewFormElementForm.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 ReviewFormElementForm
*
* @ingroup controllers_grid_settings_reviewForms_form
*
* @see ReviewFormElement
*
* @brief Form for creating and modifying review form elements.
*
*/
namespace PKP\controllers\grid\settings\reviewForms\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\controllers\listbuilder\ListbuilderHandler;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\reviewForm\ReviewFormDAO;
use PKP\reviewForm\ReviewFormElement;
use PKP\reviewForm\ReviewFormElementDAO;
use PKP\security\Validation;
class ReviewFormElementForm extends Form
{
/** @var int $reviewFormId The ID of the review form being edited */
public $reviewFormId;
/** @var int $reviewFormElementId The ID of the review form element being edited */
public $reviewFormElementId;
/**
* Constructor.
*
* @param int $reviewFormId
* @param int $reviewFormElementId
*/
public function __construct($reviewFormId, $reviewFormElementId = null)
{
parent::__construct('manager/reviewForms/reviewFormElementForm.tpl');
$this->reviewFormId = $reviewFormId;
$this->reviewFormElementId = $reviewFormElementId;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'question', 'required', 'manager.reviewFormElements.form.questionRequired'));
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'elementType', 'required', 'manager.reviewFormElements.form.elementTypeRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Get the names of fields for which localized data is allowed.
*
* @return array
*/
public function getLocaleFieldNames()
{
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
return $reviewFormElementDao->getLocaleFieldNames();
}
/**
* @copydoc Form::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$reviewFormElement = new ReviewFormElement();
$templateMgr->assign([
'reviewFormId' => $this->reviewFormId,
'reviewFormElementId' => $this->reviewFormElementId,
'multipleResponsesElementTypes' => $reviewFormElement->getMultipleResponsesElementTypes(),
'multipleResponsesElementTypesString' => ';' . implode(';', $reviewFormElement->getMultipleResponsesElementTypes()) . ';',
'reviewFormElementTypeOptions' => $reviewFormElement->getReviewFormElementTypeOptions(),
]);
return parent::fetch($request, $template, $display);
}
/**
* Initialize form data from current review form.
*/
public function initData()
{
if ($this->reviewFormElementId) {
$request = Application::get()->getRequest();
$context = $request->getContext();
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElement = $reviewFormElementDao->getById($this->reviewFormElementId, $this->reviewFormId);
$this->_data = [
'question' => $reviewFormElement->getQuestion(null), // Localized
'description' => $reviewFormElement->getDescription(null), // Localized
'required' => $reviewFormElement->getRequired(),
'included' => $reviewFormElement->getIncluded(),
'elementType' => $reviewFormElement->getElementType(),
'possibleResponses' => $reviewFormElement->getPossibleResponses(null) //Localized
];
} else {
$this->_data = [
'included' => 1
];
}
}
/**
* Assign form data to user-submitted data.
*/
public function readInputData()
{
$this->readUserVars(['question', 'description', 'required', 'included', 'elementType', 'possibleResponses']);
}
/**
* @copydoc Form::execute()
*
* @return int Review form element ID
*/
public function execute(...$functionArgs)
{
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$request = Application::get()->getRequest();
if ($this->reviewFormElementId) {
$context = $request->getContext();
$reviewFormElement = $reviewFormElementDao->getById($this->reviewFormElementId);
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($reviewFormElement->getReviewFormId(), Application::getContextAssocType(), $context->getId());
if (!$reviewForm) {
fatalError('Invalid review form element ID!');
}
} else {
$reviewFormElement = $reviewFormElementDao->newDataObject();
$reviewFormElement->setReviewFormId($this->reviewFormId);
$reviewFormElement->setSequence(REALLY_BIG_NUMBER);
}
$reviewFormElement->setQuestion($this->getData('question'), null); // Localized
$reviewFormElement->setDescription($this->getData('description'), null); // Localized
$reviewFormElement->setRequired($this->getData('required') ? 1 : 0);
$reviewFormElement->setIncluded($this->getData('included') ? 1 : 0);
$reviewFormElement->setElementType($this->getData('elementType'));
if (in_array($this->getData('elementType'), $reviewFormElement->getMultipleResponsesElementTypes())) {
$this->setData('possibleResponsesProcessed', $reviewFormElement->getPossibleResponses(null));
ListbuilderHandler::unpack($request, $this->getData('possibleResponses'), [$this, 'deleteEntry'], [$this, 'insertEntry'], [$this, 'updateEntry']);
$reviewFormElement->setPossibleResponses($this->getData('possibleResponsesProcessed'), null);
} else {
$reviewFormElement->setPossibleResponses(null, null);
}
if ($reviewFormElement->getId()) {
$reviewFormElementDao->deleteSetting($reviewFormElement->getId(), 'possibleResponses');
$reviewFormElementDao->updateObject($reviewFormElement);
} else {
$this->reviewFormElementId = $reviewFormElementDao->insertObject($reviewFormElement);
$reviewFormElementDao->resequenceReviewFormElements($this->reviewFormId);
}
parent::execute(...$functionArgs);
return $this->reviewFormElementId;
}
/**
* @copydoc ListbuilderHandler::insertEntry()
*/
public function insertEntry($request, $newRowId)
{
$possibleResponsesProcessed = (array) $this->getData('possibleResponsesProcessed');
foreach ($newRowId['possibleResponse'] as $key => $value) {
$possibleResponsesProcessed[$key][] = $value;
}
$this->setData('possibleResponsesProcessed', $possibleResponsesProcessed);
return true;
}
/**
* @copydoc ListbuilderHandler::deleteEntry()
*/
public function deleteEntry($request, $rowId)
{
$possibleResponsesProcessed = (array) $this->getData('possibleResponsesProcessed');
foreach (array_keys($possibleResponsesProcessed) as $locale) {
// WARNING: Listbuilders don't like zero row IDs. They are offset
// by 1 to avoid this case, so 1 is subtracted here to normalize.
unset($possibleResponsesProcessed[$locale][$rowId - 1]);
}
$this->setData('possibleResponsesProcessed', $possibleResponsesProcessed);
return true;
}
/**
* @copydoc ListbuilderHandler::updateEntry
*/
public function updateEntry($request, $rowId, $newRowId)
{
$possibleResponsesProcessed = (array) $this->getData('possibleResponsesProcessed');
foreach ($newRowId['possibleResponse'] as $locale => $value) {
// WARNING: Listbuilders don't like zero row IDs. They are offset
// by 1 to avoid this case, so 1 is subtracted here to normalize.
$possibleResponsesProcessed[$locale][$rowId - 1] = $value;
}
$this->setData('possibleResponsesProcessed', $possibleResponsesProcessed);
return true;
}
}
@@ -0,0 +1,82 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/form/ReviewFormElements.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 ReviewFormElements
*
* @ingroup controllers_grid_settings_reviewForms_form
*
* @brief Form for manager to edit review form elements.
*/
namespace PKP\controllers\grid\settings\reviewForms\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\core\JSONMessage;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\reviewForm\ReviewFormDAO;
use PKP\reviewForm\ReviewFormElementDAO;
use PKP\security\Validation;
class ReviewFormElements extends Form
{
/** @var int The ID of the review form being edited */
public $reviewFormId;
/**
* Constructor.
*
* @param int $reviewFormId
*/
public function __construct($reviewFormId)
{
parent::__construct('manager/reviewForms/reviewFormElements.tpl');
$this->reviewFormId = (int) $reviewFormId;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* @copydoc Form::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$json = new JSONMessage();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('reviewFormId', $this->reviewFormId);
return parent::fetch($request, $template, $display);
}
/**
* Initialize form data from current settings.
*/
public function initData()
{
if (isset($this->reviewFormId)) {
// Get review form
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($this->reviewFormId, Application::getContextAssocType(), Application::get()->getRequest()->getContext()->getId());
// Get review form elements
$reviewFormElementDao = DAORegistry::getDAO('ReviewFormElementDAO'); /** @var ReviewFormElementDAO $reviewFormElementDao */
$reviewFormElements = $reviewFormElementDao->getByReviewFormId($this->reviewFormId, null);
// Set data
$this->setData('reviewFormId', $this->reviewFormId);
$this->setData('reviewFormElements', $reviewFormElements);
}
}
}
@@ -0,0 +1,128 @@
<?php
/**
* @file controllers/grid/settings/reviewForms/form/ReviewFormForm.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 ReviewFormForm
*
* @ingroup controllers_grid_settings_reviewForms_form
*
* @brief Form for manager to edit a review form.
*/
namespace PKP\controllers\grid\settings\reviewForms\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\core\JSONMessage;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\reviewForm\ReviewFormDAO;
class ReviewFormForm extends Form
{
/** @var int The ID of the review form being edited, if any */
public $reviewFormId;
/**
* Constructor.
*
* @param int $reviewFormId omit for a new review form
*/
public function __construct($reviewFormId = null)
{
parent::__construct('manager/reviewForms/reviewFormForm.tpl');
$this->reviewFormId = $reviewFormId ? (int) $reviewFormId : null;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'title', 'required', 'manager.reviewForms.form.titleRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Assign form data to user-submitted data.
*/
public function readInputData()
{
$this->readUserVars(['title', 'description']);
}
/**
* Initialize form data from current settings.
*/
public function initData()
{
if ($this->reviewFormId) {
$request = Application::get()->getRequest();
$context = $request->getContext();
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
$reviewForm = $reviewFormDao->getById($this->reviewFormId, Application::getContextAssocType(), $context->getId());
$this->setData('title', $reviewForm->getTitle(null));
$this->setData('description', $reviewForm->getDescription(null));
}
}
/**
* @copydoc Form::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$json = new JSONMessage();
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('reviewFormId', $this->reviewFormId);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$request = Application::get()->getRequest();
$context = $request->getContext();
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
if ($this->reviewFormId) {
$reviewForm = $reviewFormDao->getById($this->reviewFormId, Application::getContextAssocType(), $context->getId());
} else {
$reviewForm = $reviewFormDao->newDataObject();
$reviewForm->setAssocType(Application::getContextAssocType());
$reviewForm->setAssocId($context->getId());
$reviewForm->setActive(0);
$reviewForm->setSequence(REALLY_BIG_NUMBER);
}
$reviewForm->setTitle($this->getData('title'), null); // Localized
$reviewForm->setDescription($this->getData('description'), null); // Localized
if ($this->reviewFormId) {
$reviewFormDao->updateObject($reviewForm);
$this->reviewFormId = $reviewForm->getId();
} else {
$this->reviewFormId = $reviewFormDao->insertObject($reviewForm);
$reviewFormDao->resequenceReviewForms(Application::getContextAssocType(), $context->getId());
}
parent::execute(...$functionArgs);
}
/**
* Get a list of field names for which localized settings are used
*
* @return array
*/
public function getLocaleFieldNames()
{
$reviewFormDao = DAORegistry::getDAO('ReviewFormDAO'); /** @var ReviewFormDAO $reviewFormDao */
return $reviewFormDao->getLocaleFieldNames();
}
}
@@ -0,0 +1,119 @@
<?php
/**
* @file controllers/grid/settings/roles/UserGroupGridCellProvider.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 UserGroupGridCellProvider
*
* @ingroup controllers_grid_settings_roles
*
* @brief Cell provider for columns in a user group grid.
*/
namespace PKP\controllers\grid\settings\roles;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxAction;
use PKP\security\RoleDAO;
use PKP\userGroup\UserGroup;
class UserGroupGridCellProvider extends 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)
{
$userGroup = $row->getData(); /** @var UserGroup $userGroup */
$columnId = $column->getId();
$workflowStages = Application::getApplicationStages();
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
$assignedStages = Repo::userGroup()->getAssignedStagesByUserGroupId($userGroup->getContextId(), $userGroup->getId())->toArray();
switch ($columnId) {
case 'name':
return ['label' => $userGroup->getLocalizedName()];
case 'roleId':
$roleNames = Application::getRoleNames(false, [$userGroup->getRoleId()]);
return ['label' => __(array_shift($roleNames))];
case in_array($columnId, $workflowStages):
// Set the state of the select element that will
// be used to assign the stage to the user group.
$selectDisabled = false;
if (in_array($columnId, $roleDao->getForbiddenStages($userGroup->getRoleId()))) {
// This stage should not be assigned to the user group.
$selectDisabled = true;
}
return ['selected' => in_array($columnId, $assignedStages),
'disabled' => $selectDisabled];
default:
break;
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
$workflowStages = Application::getApplicationStages();
$columnId = $column->getId();
if (in_array($columnId, $workflowStages)) {
$userGroup = $row->getData(); /** @var UserGroup $userGroup */
$assignedStages = Repo::userGroup()->getAssignedStagesByUserGroupId($userGroup->getContextId(), $userGroup->getId())->toArray();
$router = $request->getRouter();
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
if (!in_array($columnId, $roleDao->getForbiddenStages($userGroup->getRoleId()))) {
if (in_array($columnId, $assignedStages)) {
$operation = 'unassignStage';
$actionTitleKey = 'grid.userGroup.unassignStage';
} else {
$operation = 'assignStage';
$actionTitleKey = 'grid.userGroup.assignStage';
}
$actionArgs = array_merge(
['stageId' => $columnId],
$row->getRequestArgs()
);
$actionUrl = $router->url($request, null, null, $operation, null, $actionArgs);
$actionRequest = new AjaxAction($actionUrl);
$linkAction = new LinkAction(
$operation,
$actionRequest,
__($actionTitleKey),
null
);
return [$linkAction];
}
}
return parent::getCellActions($request, $row, $column, $position);
}
}
@@ -0,0 +1,499 @@
<?php
/**
* @file controllers/grid/settings/roles/UserGroupGridHandler.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 UserGroupGridHandler
*
* @ingroup controllers_grid_settings
*
* @brief Handle operations for user group management operations.
*/
namespace PKP\controllers\grid\settings\roles;
use APP\core\Application;
use APP\core\Request;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use PKP\controllers\grid\feature\PagingFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\settings\roles\form\UserGroupForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\notification\PKPNotification;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\authorization\internal\WorkflowStageRequiredPolicy;
use PKP\security\Role;
use PKP\security\RoleDAO;
use PKP\userGroup\relationships\UserGroupStage;
use PKP\userGroup\UserGroup;
use PKP\workflow\WorkflowStageDAO;
class UserGroupGridHandler extends GridHandler
{
/** @var int Context id. */
private $_contextId;
/** @var UserGroup User group object handled by some grid operations. */
private $_userGroup;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid',
'fetchCategory',
'fetchRow',
'addUserGroup',
'editUserGroup',
'updateUserGroup',
'removeUserGroup',
'assignStage',
'unassignStage'
]
);
}
//
// Overridden methods from PKPHandler.
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
$operation = $request->getRequestedOp();
$workflowStageRequiredOps = ['assignStage', 'unassignStage'];
if (in_array($operation, $workflowStageRequiredOps)) {
$this->addPolicy(new WorkflowStageRequiredPolicy($request->getUserVar('stageId')));
}
$userGroupRequiredOps = array_merge($workflowStageRequiredOps, ['editUserGroup', 'removeUserGroup']);
if (in_array($operation, $userGroupRequiredOps)) {
// Validate the user group object.
$userGroupId = $request->getUserVar('userGroupId');
$userGroup = Repo::userGroup()->get($userGroupId);
if (!$userGroup) {
fatalError('Invalid user group id!');
} else {
$this->_userGroup = $userGroup;
}
}
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$context = $request->getContext();
$this->_contextId = $context->getId();
// Basic grid configuration.
$this->setTitle('grid.roles.currentRoles');
// Add grid-level actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addUserGroup',
new AjaxModal(
$router->url($request, null, null, 'addUserGroup'),
__('grid.roles.add'),
'modal_add_role'
),
__('grid.roles.add'),
'add_role'
)
);
$cellProvider = new UserGroupGridCellProvider();
$workflowStagesLocales = WorkflowStageDAO::getWorkflowStageTranslationKeys();
// Set array containing the columns info with the same cell provider.
$columnsInfo = [
1 => ['id' => 'name', 'title' => 'settings.roles.roleName', 'template' => null],
2 => ['id' => 'roleId', 'title' => 'settings.roles.from', 'template' => null]
];
foreach ($workflowStagesLocales as $stageId => $stageTitleKey) {
$columnsInfo[] = ['id' => $stageId, 'title' => $stageTitleKey, 'template' => 'controllers/grid/common/cell/selectStatusCell.tpl'];
}
// Add array columns to the grid.
foreach ($columnsInfo as $columnInfo) {
$this->addColumn(
new GridColumn(
$columnInfo['id'],
$columnInfo['title'],
null,
$columnInfo['template'],
$cellProvider
)
);
}
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$contextId = $this->_getContextId();
$roleIdFilter = null;
$stageIdFilter = null;
if (!is_array($filter)) {
$filter = [];
}
if (isset($filter['selectedRoleId'])) {
$roleIdFilter = $filter['selectedRoleId'];
}
if (isset($filter['selectedStageId'])) {
$stageIdFilter = $filter['selectedStageId'];
}
$rangeInfo = $this->getGridRangeInfo($request, $this->getId());
if ($stageIdFilter && $stageIdFilter != 0) {
return Repo::userGroup()->getCollector()
->filterByContextIds([$contextId])
->filterByStageIds([$stageIdFilter])
->filterByRoleIds([$roleIdFilter])
->limit($rangeInfo->getCount())
->offset($rangeInfo->getOffset() + max(0, $rangeInfo->getPage() - 1) * $rangeInfo->getCount())
->getMany()
->toArray();
} elseif ($roleIdFilter && $roleIdFilter != 0) {
return Repo::userGroup()->getByRoleIds([$roleIdFilter], $contextId)->toArray();
} else {
return Repo::userGroup()->getCollector()
->filterByContextIds([$contextId])
->getMany()
->toArray();
}
}
/**
* @copydoc GridHandler::getRowInstance()
*
* @return UserGroupGridRow
*/
protected function getRowInstance()
{
return new UserGroupGridRow();
}
/**
* @see GridHandler::renderFilter()
*/
public function renderFilter($request, $filterData = [])
{
// Get filter data.
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
$roleOptions = [0 => 'grid.user.allPermissionLevels'] + Application::getRoleNames(true);
// Reader roles are not important for stage assignments.
if (array_key_exists(Role::ROLE_ID_READER, $roleOptions)) {
unset($roleOptions[Role::ROLE_ID_READER]);
}
$filterData = ['roleOptions' => $roleOptions];
$workflowStages = [0 => 'grid.userGroup.allStages'] + WorkflowStageDAO::getWorkflowStageTranslationKeys();
$filterData['stageOptions'] = $workflowStages;
return parent::renderFilter($request, $filterData);
}
/**
* @see GridHandler::getFilterSelectionData()
*
* @return array Filter selection data.
*/
public function getFilterSelectionData($request)
{
$selectedRoleId = $request->getUserVar('selectedRoleId');
$selectedStageId = $request->getUserVar('selectedStageId');
// Cast or set to grid filter default value (all roles).
$selectedRoleId = (is_null($selectedRoleId) ? 0 : (int)$selectedRoleId);
$selectedStageId = (is_null($selectedStageId) ? 0 : (int)$selectedStageId);
return ['selectedRoleId' => $selectedRoleId, 'selectedStageId' => $selectedStageId];
}
/**
* @see GridHandler::getFilterForm()
*
* @return string Filter template.
*/
protected function getFilterForm()
{
return 'controllers/grid/settings/roles/userGroupsGridFilter.tpl';
}
/**
* @see GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new PagingFeature()];
}
//
// Handler operations.
//
/**
* Handle the add user group operation.
*
* @param array $args
* @param PKPRequest $request
*/
public function addUserGroup($args, $request)
{
return $this->editUserGroup($args, $request);
}
/**
* Handle the edit user group operation.
*
* @param array $args
*
* @return JSONMessage JSON object
*/
public function editUserGroup($args, $request)
{
$userGroupForm = $this->_getUserGroupForm($request);
$userGroupForm->initData();
return new JSONMessage(true, $userGroupForm->fetch($request));
}
/**
* Update user group data on database and grid.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateUserGroup($args, $request)
{
$userGroupForm = $this->_getUserGroupForm($request);
$userGroupForm->readInputData();
if ($userGroupForm->validate()) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification($request->getUser()->getId());
$userGroupForm->execute();
$json = \PKP\db\DAO::getDataChangedEvent();
$json->setGlobalEvent('userGroupUpdated');
return $json;
} else {
return new JSONMessage(true, $userGroupForm->fetch($request));
}
}
/**
* Remove user group.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function removeUserGroup($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$user = $request->getUser();
$userGroup = $this->_userGroup;
$contextId = $this->_getContextId();
$notificationMgr = new NotificationManager();
$usersAssignedToUserGroupCount = Repo::user()->getCollector()
->filterByContextIds([$contextId])
->filterByUserGroupIds([$userGroup->getId()])
->getCount();
if ($usersAssignedToUserGroupCount == 0) {
if ($userGroup->getData('isDefault')) {
// Can't delete default user groups.
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_WARNING,
['contents' => __(
'grid.userGroup.cantRemoveDefaultUserGroup',
['userGroupName' => $userGroup->getLocalizedName() ]
)]
);
} else {
// We can delete, no user assigned yet.
Repo::userGroup()->delete($userGroup);
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __(
'grid.userGroup.removed',
['userGroupName' => $userGroup->getLocalizedName() ]
)]
);
}
} else {
// Can't delete while an user
// is still assigned to that user group.
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_WARNING,
['contents' => __(
'grid.userGroup.cantRemoveUserGroup',
['userGroupName' => $userGroup->getLocalizedName(), 'usersCount' => $usersAssignedToUserGroupCount]
)]
);
}
$json = \PKP\db\DAO::getDataChangedEvent($userGroup->getId());
$json->setGlobalEvent('userGroupUpdated');
return $json;
}
/**
* Assign stage to user group.
*
* @param array $args
* @param PKPRequest $request
*/
public function assignStage($args, $request)
{
return $this->_toggleAssignment($args, $request);
}
/**
* Unassign stage to user group.
*
* @param array $args
* @param PKPRequest $request
*/
public function unassignStage($args, $request)
{
return $this->_toggleAssignment($args, $request);
}
//
// Private helper methods.
//
/**
* Toggle user group stage assignment.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
private function _toggleAssignment($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$userGroup = $this->_userGroup;
$stageId = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_WORKFLOW_STAGE);
$contextId = $this->_getContextId();
$operation = $request->getRequestedOp();
switch ($operation) {
case 'assignStage':
UserGroupStage::create([
'contextId' => $contextId,
'userGroupId' => $userGroup->getId(),
'stageId' => $stageId
]);
$messageKey = 'grid.userGroup.assignedStage';
break;
case 'unassignStage':
Repo::userGroup()->removeGroupFromStage($contextId, $userGroup->getId(), $stageId);
$messageKey = 'grid.userGroup.unassignedStage';
break;
}
$notificationMgr = new NotificationManager();
$user = $request->getUser();
$stageLocaleKeys = WorkflowStageDAO::getWorkflowStageTranslationKeys();
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __(
$messageKey,
['userGroupName' => $userGroup->getLocalizedName(), 'stageName' => __($stageLocaleKeys[$stageId])]
)]
);
return \PKP\db\DAO::getDataChangedEvent($userGroup->getId());
}
/**
* Get a UserGroupForm instance.
*
* @param Request $request
*
* @return UserGroupForm
*/
private function _getUserGroupForm($request)
{
// Get the user group Id.
$userGroupId = (int) $request->getUserVar('userGroupId');
// Instantiate the files form.
$contextId = $this->_getContextId();
return new UserGroupForm($contextId, $userGroupId);
}
/**
* Get context id.
*
* @return int
*/
private function _getContextId()
{
return $this->_contextId;
}
}
@@ -0,0 +1,75 @@
<?php
/**
* @file controllers/grid/settings/roles/UserGroupGridRow.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 UserGroupGridRow
*
* @ingroup controllers_grid_settings_roles
*
* @brief User group grid row definition
*/
namespace PKP\controllers\grid\settings\roles;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\userGroup\UserGroup;
class UserGroupGridRow extends GridRow
{
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$userGroup = $this->getData(); /** @var UserGroup $userGroup */
assert($userGroup != null);
$rowId = $this->getId();
$actionArgs = ['userGroupId' => $userGroup->getId()];
$this->setRequestArgs($actionArgs);
// Only add row actions if this is an existing row.
if (!empty($rowId) && is_numeric($rowId)) {
$router = $request->getRouter();
$this->addAction(new LinkAction(
'editUserGroup',
new AjaxModal(
$router->url($request, null, null, 'editUserGroup', null, $actionArgs),
__('grid.action.edit'),
'modal_edit'
),
__('grid.action.edit'),
'edit'
));
$this->addAction(new LinkAction(
'removeUserGroup',
new RemoteActionConfirmationModal(
$request->getSession(),
__('settings.roles.removeText'),
null,
$router->url($request, null, null, 'removeUserGroup', null, $actionArgs)
),
__('grid.action.remove'),
'delete'
));
}
}
}
@@ -0,0 +1,327 @@
<?php
/**
* @file controllers/grid/settings/roles/form/UserGroupForm.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 UserGroupForm
*
* @ingroup controllers_grid_settings_roles_form
*
* @brief Form to add/edit user group.
*/
namespace PKP\controllers\grid\settings\roles\form;
use APP\core\Application;
use APP\core\Request;
use APP\facades\Repo;
use APP\template\TemplateManager;
use PKP\core\JSONMessage;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\security\Role;
use PKP\security\RoleDAO;
use PKP\security\Validation;
use PKP\stageAssignment\StageAssignmentDAO;
use PKP\userGroup\relationships\UserGroupStage;
use PKP\workflow\WorkflowStageDAO;
class UserGroupForm extends Form
{
/** @var int Id of the user group being edited */
public $_userGroupId;
/** @var int The context of the user group being edited */
public $_contextId;
/**
* Constructor.
*
* @param int $contextId id.
* @param int $userGroupId group id.
*/
public function __construct($contextId, $userGroupId = null)
{
parent::__construct('controllers/grid/settings/roles/form/userGroupForm.tpl');
$this->_contextId = $contextId;
$this->_userGroupId = $userGroupId;
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'name', 'required', 'settings.roles.nameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'abbrev', 'required', 'settings.roles.abbrevRequired'));
if ($this->getUserGroupId() == null) {
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'roleId', 'required', 'settings.roles.roleIdRequired'));
}
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters and Setters
//
/**
* Get the user group id.
*
* @return int userGroupId
*/
public function getUserGroupId()
{
return $this->_userGroupId;
}
/**
* Get the context id.
*
* @return int contextId
*/
public function getContextId()
{
return $this->_contextId;
}
//
// Implement template methods from Form.
//
/**
* Get all locale field names
*/
public function getLocaleFieldNames()
{
return ['name', 'abbrev'];
}
/**
* @copydoc Form::initData()
*/
public function initData()
{
$userGroup = Repo::userGroup()->get($this->getUserGroupId());
$stages = WorkflowStageDAO::getWorkflowStageTranslationKeys();
$this->setData('stages', $stages);
$this->setData('assignedStages', []); // sensible default
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
$jsonMessage = new JSONMessage();
$jsonMessage->setContent($roleDao->getForbiddenStages());
$this->setData('roleForbiddenStagesJSON', $jsonMessage->getString());
if ($userGroup) {
$assignedStages = Repo::userGroup()->getAssignedStagesByUserGroupId($this->getContextId(), $userGroup->getId())->toArray();
$data = [
'userGroupId' => $userGroup->getId(),
'roleId' => $userGroup->getRoleId(),
'name' => $userGroup->getName(null), //Localized
'abbrev' => $userGroup->getAbbrev(null), //Localized
'assignedStages' => $assignedStages,
'showTitle' => $userGroup->getShowTitle(),
'permitSelfRegistration' => $userGroup->getPermitSelfRegistration(),
'permitMetadataEdit' => $userGroup->getPermitMetadataEdit(),
'recommendOnly' => $userGroup->getRecommendOnly(),
];
foreach ($data as $field => $value) {
$this->setData($field, $value);
}
}
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['roleId', 'name', 'abbrev', 'assignedStages', 'showTitle', 'permitSelfRegistration', 'recommendOnly', 'permitMetadataEdit']);
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
$templateMgr->assign('roleOptions', Application::getRoleNames(true));
// Users can't edit the role once user group is created.
// userGroupId is 0 for new User Groups because it is cast to int in UserGroupGridHandler.
$disableRoleSelect = ($this->getUserGroupId() > 0) ? true : false;
$templateMgr->assign('disableRoleSelect', $disableRoleSelect);
$templateMgr->assign('selfRegistrationRoleIds', $this->getPermitSelfRegistrationRoles());
$templateMgr->assign('recommendOnlyRoleIds', $this->getRecommendOnlyRoles());
$templateMgr->assign('notChangeMetadataEditPermissionRoles', Repo::userGroup()::NOT_CHANGE_METADATA_EDIT_PERMISSION_ROLES);
return parent::fetch($request, $template, $display);
}
/**
* Get a list of roles optionally permitting user self-registration.
*
* @return array
*/
public function getPermitSelfRegistrationRoles()
{
return [Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR, Role::ROLE_ID_READER];
}
/**
* Get a list of roles optionally permitting recommendOnly option.
*
* @return array
*/
public function getRecommendOnlyRoles()
{
return [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR];
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionParams)
{
parent::execute(...$functionParams);
$request = Application::get()->getRequest();
$userGroupId = $this->getUserGroupId();
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
// Check if we are editing an existing user group or creating another one.
if ($userGroupId == null) {
$userGroup = Repo::userGroup()->newDataObject();
$userGroup->setRoleId($this->getData('roleId'));
$userGroup->setContextId($this->getContextId());
$userGroup->setDefault(false);
$userGroup->setShowTitle(is_null($this->getData('showTitle')) ? false : $this->getData('showTitle'));
$userGroup->setPermitSelfRegistration($this->getData('permitSelfRegistration') && in_array($userGroup->getRoleId(), $this->getPermitSelfRegistrationRoles()));
$userGroup->setPermitMetadataEdit($this->getData('permitMetadataEdit') && !in_array($this->getData('roleId'), Repo::userGroup()::NOT_CHANGE_METADATA_EDIT_PERMISSION_ROLES));
if (in_array($this->getData('roleId'), Repo::userGroup()::NOT_CHANGE_METADATA_EDIT_PERMISSION_ROLES)) {
$userGroup->setPermitMetadataEdit(true);
}
$userGroup->setRecommendOnly($this->getData('recommendOnly') && in_array($userGroup->getRoleId(), $this->getRecommendOnlyRoles()));
$userGroup = $this->_setUserGroupLocaleFields($userGroup, $request);
$userGroupId = Repo::userGroup()->add($userGroup);
} else {
$userGroup = Repo::userGroup()->get($userGroupId);
$userGroup = $this->_setUserGroupLocaleFields($userGroup, $request);
$userGroup->setShowTitle(is_null($this->getData('showTitle')) ? false : $this->getData('showTitle'));
$userGroup->setPermitSelfRegistration($this->getData('permitSelfRegistration') && in_array($userGroup->getRoleId(), $this->getPermitSelfRegistrationRoles()));
$userGroup->setPermitMetadataEdit($this->getData('permitMetadataEdit') && !in_array($userGroup->getRoleId(), Repo::userGroup()::NOT_CHANGE_METADATA_EDIT_PERMISSION_ROLES));
if (in_array($userGroup->getRoleId(), Repo::userGroup()::NOT_CHANGE_METADATA_EDIT_PERMISSION_ROLES)) {
$userGroup->setPermitMetadataEdit(true);
} else {
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */
$allUserAssignments = $stageAssignmentDao
->getByUserGroupId($userGroupId, $this->getContextId())
->toAssociativeArray();
foreach ($allUserAssignments as $userAssignment) {
$userAssignment->setCanChangeMetadata($userGroup->getPermitMetadataEdit());
$stageAssignmentDao->updateObject($userAssignment);
}
}
$userGroup->setRecommendOnly($this->getData('recommendOnly') && in_array($userGroup->getRoleId(), $this->getRecommendOnlyRoles()));
Repo::userGroup()->edit($userGroup, []);
}
// After we have created/edited the user group, we assign/update its stages.
$assignedStages = $this->getData('assignedStages');
// Always set all stages active for some permission levels.
if (in_array($userGroup->getRoleId(), $roleDao->getAlwaysActiveStages())) {
$assignedStages = array_keys(WorkflowStageDAO::getWorkflowStageTranslationKeys());
}
if ($assignedStages) {
$this->_assignStagesToUserGroup($userGroupId, $assignedStages);
}
}
//
// Private helper methods
//
/**
* Setup the stages assignments to a user group in database.
*
* @param int $userGroupId User group id that will receive the stages.
* @param array $userAssignedStages of stages currently assigned to a user.
*/
public function _assignStagesToUserGroup($userGroupId, $userAssignedStages)
{
$contextId = $this->getContextId();
// Current existing workflow stages.
$stages = WorkflowStageDAO::getWorkflowStageTranslationKeys();
foreach (array_keys($stages) as $stageId) {
Repo::userGroup()->removeGroupFromStage($contextId, $userGroupId, $stageId);
}
foreach ($userAssignedStages as $stageId) {
// Make sure we don't assign forbidden stages based on
// user groups role id. Override in case of some permission levels.
$roleId = $this->getData('roleId');
$roleDao = DAORegistry::getDAO('RoleDAO'); /** @var RoleDAO $roleDao */
$forbiddenStages = $roleDao->getForbiddenStages($roleId);
if (in_array($stageId, $forbiddenStages) && !in_array($roleId, $roleDao->getAlwaysActiveStages())) {
continue;
}
// Check if is a valid stage.
if (in_array($stageId, array_keys($stages))) {
UserGroupStage::create([
'contextId' => $contextId,
'userGroupId' => $userGroupId,
'stageId' => $stageId
]);
} else {
fatalError('Invalid stage id');
}
}
}
/**
* Set locale fields on a User Group object.
*
* @param \PKP\userGroup\UserGroup $userGroup
* @param Request $request
*
*/
public function _setUserGroupLocaleFields($userGroup, $request): \PKP\userGroup\UserGroup
{
$router = $request->getRouter();
$context = $router->getContext($request);
$supportedLocales = $context->getSupportedLocaleNames();
if (!empty($supportedLocales)) {
foreach ($context->getSupportedLocaleNames() as $localeKey => $localeName) {
$name = $this->getData('name');
$abbrev = $this->getData('abbrev');
if (isset($name[$localeKey])) {
$userGroup->setName($name[$localeKey], $localeKey);
}
if (isset($abbrev[$localeKey])) {
$userGroup->setAbbrev($abbrev[$localeKey], $localeKey);
}
}
} else {
$localeKey = Locale::getLocale();
$userGroup->setName($this->getData('name'), $localeKey);
$userGroup->setAbbrev($this->getData('abbrev'), $localeKey);
}
return $userGroup;
}
}
@@ -0,0 +1,201 @@
<?php
/**
* @file controllers/grid/settings/sections/form/PKPSectionForm.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 PKPSectionForm
*
* @ingroup controllers_grid_settings_section_form
*
* @brief Form for adding/editing a section
*/
namespace PKP\controllers\grid\settings\sections\form;
use APP\core\Application;
use APP\facades\Repo;
use APP\section\Section;
use APP\template\TemplateManager;
use PKP\context\SubEditorsDAO;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\form\Form;
use PKP\security\Role;
use PKP\userGroup\UserGroup;
class PKPSectionForm extends Form
{
/** @var int the id for the section being edited */
public $_sectionId;
/** @var int The current user ID */
public $_userId;
/** @var string Cover image extension */
public $_imageExtension;
/** @var array Cover image information from getimagesize */
public $_sizeArray;
public ?Section $section = null;
/** @var array Roles that can be assigned to this section */
public $assignableRoles = [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT];
/**
* Constructor.
*
* @param PKPRequest $request
* @param string $template Template path
* @param int $sectionId optional
*/
public function __construct($request, $template, $sectionId = null)
{
$this->setSectionId($sectionId);
$user = $request->getUser();
$this->_userId = $user->getId();
parent::__construct($template);
// Validation checks for this form
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['title', 'subEditors']);
}
/**
* Get the section ID for this section.
*
* @return int
*/
public function getSectionId()
{
return $this->_sectionId;
}
/**
* Set the section ID for this section.
*
* @param int $sectionId
*/
public function setSectionId($sectionId)
{
$this->_sectionId = $sectionId;
}
public function getSection(): ?Section
{
return $this->section;
}
public function setSection(Section $section): void
{
$this->section = $section;
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$assignableUserGroups = Repo::userGroup()
->getCollector()
->filterByContextIds([$request->getContext()->getId()])
->filterByRoleIds($this->assignableRoles)
->filterByStageIds([WORKFLOW_STAGE_ID_SUBMISSION])
->getMany()
->map(function (UserGroup $userGroup) use ($request) {
return [
'userGroup' => $userGroup,
'users' => Repo::user()
->getCollector()
->filterByUserGroupIds([$userGroup->getId()])
->filterByContextIds([$request->getContext()->getId()])
->getMany()
->mapWithKeys(fn ($user, $key) => [$user->getId() => $user->getFullName()])
->toArray()
];
});
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'assignableUserGroups' => $assignableUserGroups->toArray(),
]);
return parent::fetch($request, $template, $display);
}
public function initData()
{
$subeditorUserGroups = [];
if ($this->getSection() !== null) {
$assignedSubeditors = Repo::user()
->getCollector()
->filterByContextIds([Application::get()->getRequest()->getContext()->getId()])
->filterByRoleIds($this->assignableRoles)
->assignedToSectionIds([$this->getSectionId()])
->getIds()
->toArray();
if (!empty($assignedSubeditors)) {
$subEditorsDao = DAORegistry::getDAO('SubEditorsDAO'); /** @var SubEditorsDAO $subEditorsDao */
$subeditorUserGroups = $subEditorsDao->getAssignedUserGroupIds(
Application::get()->getRequest()->getContext()->getId(),
Application::ASSOC_TYPE_SECTION,
$this->getSection()->getId(),
$assignedSubeditors
)->toArray();
}
}
$this->setData([
'subeditorUserGroups' => $subeditorUserGroups,
]);
parent::initData();
}
/**
* Save changes to subeditors
*
*/
public function execute(...$functionArgs)
{
$contextId = Application::get()->getRequest()->getContext()->getId();
$subEditorsDao = DAORegistry::getDAO('SubEditorsDAO'); /** @var SubEditorsDAO $subEditorsDao */
$subEditorsDao->deleteBySubmissionGroupId($this->getSectionId(), Application::ASSOC_TYPE_SECTION, $contextId);
$subEditors = $this->getData('subEditors');
if (!empty($subEditors)) {
$allowedEditors = Repo::user()
->getCollector()
->filterByRoleIds($this->assignableRoles)
->filterByContextIds([Application::get()->getRequest()->getContext()->getId()])
->getIds();
foreach ($subEditors as $userGroupId => $userIds) {
foreach ($userIds as $userId) {
if (!$allowedEditors->contains($userId)) {
continue;
}
$subEditorsDao->insertEditor($contextId, $this->getSectionId(), $userId, Application::ASSOC_TYPE_SECTION, (int) $userGroupId);
}
}
}
parent::execute($functionArgs);
}
}
@@ -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);
}
}