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,215 @@
<?php
/**
* @defgroup controllers_api_file File API controller
*/
/**
* @file controllers/api/file/FileApiHandler.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 FileApiHandler
*
* @ingroup controllers_api_file
*
* @brief Class defining an AJAX API for supplying file information.
*/
namespace PKP\controllers\api\file;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\handler\Handler;
use Exception;
use PKP\config\Config;
use PKP\core\JSONMessage;
use PKP\db\DAORegistry;
use PKP\file\FileArchive;
use PKP\file\FileManager;
use PKP\pages\libraryFiles\LibraryFileHandler;
use PKP\security\authorization\ContextAccessPolicy;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\SubmissionFileAccessPolicy;
use PKP\security\Role;
use PKP\submission\GenreDAO;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submissionFile\SubmissionFile;
class FileApiHandler extends Handler
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR],
['downloadFile', 'downloadLibraryFile', 'downloadAllFiles', 'recordDownload', 'enableLinkAction']
);
}
//
// Implement methods from PKPHandler
//
public function authorize($request, &$args, $roleAssignments)
{
$submissionId = (int) $request->getUserVar('submissionId');
$submissionFileId = (int) $request->getUserVar('submissionFileId');
$fileStage = (int) $request->getUserVar('fileStage');
$libraryFileId = $request->getUserVar('libraryFileId');
if (!empty($submissionFileId)) {
$this->addPolicy(new SubmissionFileAccessPolicy($request, $args, $roleAssignments, SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_READ, $submissionFileId));
} elseif (is_numeric($libraryFileId)) {
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
} elseif (!empty($fileStage) && empty($submissionFileId)) {
$submissionFileIds = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$submissionId])
->filterByFileStages([$fileStage])
->includeDependentFiles($fileStage === SubmissionFile::SUBMISSION_FILE_DEPENDENT)
->getIds();
$allFilesAccessPolicy = new PolicySet(PolicySet::COMBINING_DENY_OVERRIDES);
foreach ($submissionFileIds as $submissionFileId) {
$allFilesAccessPolicy->addPolicy(new SubmissionFileAccessPolicy($request, $args, $roleAssignments, SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_READ, $submissionFileId));
}
$this->addPolicy($allFilesAccessPolicy);
}
return parent::authorize($request, $args, $roleAssignments);
}
//
// Public handler methods
//
/**
* Download a file.
*
* @param array $args
* @param Request $request
*/
public function downloadFile($args, $request)
{
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
$fileId = $request->getUserVar('fileId') ?? $submissionFile->getData('fileId');
$revisions = Repo::submissionFile()
->getRevisions($submissionFile->getId());
$file = null;
foreach ($revisions as $revision) {
if ($revision->fileId == $fileId) {
$file = $revision;
}
}
if (!$file) {
throw new Exception('File ' . $fileId . ' is not a revision of submission file ' . $submissionFile->getId());
}
if (!Services::get('file')->fs->has($file->path)) {
$request->getDispatcher()->handle404();
}
$filename = $request->getUserVar('filename') ?? $submissionFile->getLocalizedData('name');
// Enforce anonymous filenames for anonymous review assignments
$reviewAssignment = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
if ($reviewAssignment
&& $reviewAssignment->getReviewMethod() == ReviewAssignment::SUBMISSION_REVIEW_METHOD_DOUBLEANONYMOUS
&& $reviewAssignment->getReviewerId() == $request->getUser()->getId()) {
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$genre = $genreDao->getById($submissionFile->getData('genreId'));
$filename = sprintf(
'%s-%s-%d-%s-%d',
\Stringy\Stringy::create($request->getContext()->getLocalizedData('acronym'))->toLowerCase(),
\Stringy\Stringy::create(__('submission.list.reviewAssignment'))->dasherize(),
$submissionFile->getData('submissionId'),
$genre ? $genre->getLocalizedName() : 'none',
$submissionFile->getId()
);
}
$filename = Services::get('file')->formatFilename($file->path, $filename);
Services::get('file')->download((int) $fileId, $filename);
}
/**
* Download a library file.
*
* @param array $args
* @param Request $request
*/
public function downloadLibraryFile($args, $request)
{
$libraryFileHandler = new LibraryFileHandler($this);
return $libraryFileHandler->downloadLibraryFile($args, $request);
}
/**
* Download all passed files.
*
* @param array $args
* @param Request $request
*/
public function downloadAllFiles($args, $request)
{
// Retrieve the authorized objects.
$submissionFiles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILES);
$files = [];
foreach ($submissionFiles as $submissionFile) {
$path = $submissionFile->getData('path');
$files[$path] = Services::get('file')->formatFilename($path, $submissionFile->getLocalizedData('name'));
}
$filename = !empty($args['nameLocaleKey'])
? __($args['nameLocaleKey'])
: __('submission.files');
$filename = $args['submissionId'] . '-' . $filename;
$filename = \Stringy\Stringy::create($filename)->toLowerCase()->dasherize()->regexReplace('[^a-z0-9\-\_.]', '');
$fileArchive = new FileArchive();
$archivePath = $fileArchive->create($files, rtrim(Config::getVar('files', 'files_dir'), '/'));
if (file_exists($archivePath)) {
$fileManager = new FileManager();
if ($fileArchive->zipFunctional()) {
$fileManager->downloadByPath($archivePath, 'application/x-zip', false, $filename . '.zip');
} else {
$fileManager->downloadByPath($archivePath, 'application/x-gtar', false, $filename . '.tar.gz');
}
$fileManager->deleteByPath($archivePath);
} else {
throw new Exception('Creating archive with submission files failed!');
}
}
/**
* Record file download and return js event to update grid rows.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage
*/
public function recordDownload($args, $request)
{
return $this->enableLinkAction($args, $request);
}
/**
* Returns a data changd event to re-enable the link action. Refactored out of
* recordDownload since library files do not have downloads recorded and are in a
* different context.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function enableLinkAction($args, $request)
{
return \PKP\db\DAO::getDataChangedEvent();
}
}
@@ -0,0 +1,307 @@
<?php
/**
* @file controllers/api/file/PKPManageFileApiHandler.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 PKPManageFileApiHandler
*
* @ingroup controllers_api_file
*
* @brief Class defining an AJAX API for file manipulation.
*/
namespace PKP\controllers\api\file;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\handler\Handler;
use APP\notification\NotificationManager;
use APP\template\TemplateManager;
use PKP\controllers\wizard\fileUpload\form\SubmissionFilesMetadataForm;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\db\DAORegistry;
use PKP\log\event\EventLogEntry;
use PKP\notification\NotificationDAO;
use PKP\notification\PKPNotification;
use PKP\observers\events\MetadataChanged;
use PKP\security\authorization\SubmissionFileAccessPolicy;
use PKP\security\Role;
use PKP\stageAssignment\StageAssignmentDAO;
use PKP\submissionFile\SubmissionFile;
abstract class PKPManageFileApiHandler extends Handler
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR],
['deleteFile', 'editMetadata', 'editMetadataTab', 'saveMetadata', 'cancelFileUpload']
);
}
//
// Implement methods from PKPHandler
//
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new SubmissionFileAccessPolicy($request, $args, $roleAssignments, SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_MODIFY, (int) $args['submissionFileId']));
return parent::authorize($request, $args, $roleAssignments);
}
//
// Public handler methods
//
/**
* Delete a file or revision
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function deleteFile($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
Repo::submissionFile()->delete($submissionFile);
$this->setupTemplate($request);
$user = $request->getUser();
if (!$request->getUserVar('suppressNotification')) {
$notificationMgr = new NotificationManager();
$notificationMgr->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.removedFile')]
);
}
return \PKP\db\DAO::getDataChangedEvent();
}
/**
* Restore original file when cancelling the upload wizard
*/
public function cancelFileUpload(array $args, Request $request): JSONMessage
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
$originalFile = $request->getUserVar('originalFile') ? (array)$request->getUserVar('originalFile') : null;
$revisedFileId = $request->getUserVar('fileId') ? (int)$request->getUserVar('fileId') : null;
// Get revisions and check file IDs
$revisions = Repo::submissionFile()->getRevisions($submissionFile->getId());
$revisionIds = [];
foreach ($revisions as $revision) {
$revisionIds[] = $revision->fileId;
}
if (!$revisedFileId || !in_array($revisedFileId, $revisionIds)) {
return new JSONMessage(false);
}
if (!isset($originalFile['fileId']) || !in_array($originalFile['fileId'], $revisionIds)) {
return new JSONMessage(false);
}
$originalFileId = (int) $originalFile['fileId'];
// Get the file name and uploader user ID
$originalUserId = $originalFile['uploaderUserId'] ? (int)$originalFile['uploaderUserId'] : null;
$originalFileName = $originalFile['name'] ? (array)$originalFile['name'] : null;
if (!$originalUserId || !$originalFileName) {
return new JSONMessage(false);
}
$originalUser = Repo::user()->get($originalUserId);
if (!$originalUser) {
return new JSONMessage(false);
}
$originalUsername = $originalUser->getUsername();
$matchedLogEntry = $this->findMatchedLogEntry($submissionFile, $originalFileId, $originalUsername, $originalFileName);
if (!$matchedLogEntry) {
return new JSONMessage(false);
}
// Restore original submission file
Repo::submissionFile()->edit(
$submissionFile,
[
'fileId' => $matchedLogEntry->getData('fileId'),
'name' => $matchedLogEntry->getData('filename'),
'uploaderUserId' => Repo::user()->getByUsername($matchedLogEntry->getData('username'))->getId(),
]
);
// Remove uploaded file
Services::get('file')->delete($revisedFileId);
$this->setupTemplate($request);
return \PKP\db\DAO::getDataChangedEvent();
}
/**
* Edit submission file metadata modal.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function editMetadata($args, $request)
{
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
if ($submissionFile->getFileStage() == SubmissionFile::SUBMISSION_FILE_PROOF) {
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('submissionFile', $submissionFile);
$templateMgr->assign('stageId', $request->getUserVar('stageId'));
return new JSONMessage(true, $templateMgr->fetch('controllers/api/file/editMetadata.tpl'));
} else {
return $this->editMetadataTab($args, $request);
}
}
/**
* Edit submission file metadata tab.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function editMetadataTab($args, $request)
{
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
$reviewRound = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ROUND);
$stageId = $request->getUserVar('stageId');
$form = new SubmissionFilesMetadataForm($submissionFile, $stageId, $reviewRound);
$form->setShowButtons(true);
return new JSONMessage(true, $form->fetch($request));
}
/**
* Save the metadata of the latest revision of
* the requested submission file.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function saveMetadata($args, $request)
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
$reviewRound = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ROUND);
$stageId = $request->getUserVar('stageId');
$form = new SubmissionFilesMetadataForm($submissionFile, $stageId, $reviewRound);
$form->readInputData();
if ($form->validate()) {
$form->execute();
$submissionFile = $form->getSubmissionFile();
// Get a list of author user IDs
$authorUserIds = [];
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */
$submitterAssignments = $stageAssignmentDao->getBySubmissionAndRoleIds($submission->getId(), [Role::ROLE_ID_AUTHOR]);
while ($assignment = $submitterAssignments->next()) {
$authorUserIds[] = $assignment->getUserId();
}
// Update the notifications
$notificationMgr = new NotificationManager(); /** @var NotificationManager $notificationMgr */
$notificationMgr->updateNotification(
$request,
$this->getUpdateNotifications(),
$authorUserIds,
Application::ASSOC_TYPE_SUBMISSION,
$submission->getId()
);
if ($reviewRound) {
// Delete any 'revision requested' notifications since revisions are now in.
$context = $request->getContext();
$notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */
$stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /** @var StageAssignmentDAO $stageAssignmentDao */
$submitterAssignments = $stageAssignmentDao->getBySubmissionAndRoleIds($submission->getId(), [Role::ROLE_ID_AUTHOR]);
while ($assignment = $submitterAssignments->next()) {
$notificationDao->deleteByAssoc(Application::ASSOC_TYPE_SUBMISSION, $submission->getId(), $assignment->getUserId(), PKPNotification::NOTIFICATION_TYPE_EDITOR_DECISION_PENDING_REVISIONS, $context->getId());
}
}
// Inform SearchIndex of changes
event(new MetadataChanged($submission));
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(true, $form->fetch($request));
}
}
/**
* Get the list of notifications to be updated on metadata form submission.
*
* @return array
*/
protected function getUpdateNotifications()
{
return [PKPNotification::NOTIFICATION_TYPE_PENDING_EXTERNAL_REVISIONS];
}
/**
* Compare user supplied data when cancelling file upload with saved in the event log;
* assuming we found the right entry if they match
*/
protected function findMatchedLogEntry(
SubmissionFile $submissionFile,
int $originalFileId,
string $originalUsername,
array $originalFileName
): ?EventLogEntry
{
$logEntries = Repo::eventLog()->getCollector()
->filterByAssoc(PKPApplication::ASSOC_TYPE_SUBMISSION_FILE, [$submissionFile->getId()])
->getMany();
$match = null;
foreach ($logEntries as $logEntry) {
$loggedUsername = $logEntry->getData('username');
$loggedFileName = $logEntry->getData('filename');
$loggedFileId = $logEntry->getData('fileId');
if (!$loggedUsername || !$loggedFileName || !$loggedFileId) {
continue;
}
if (
$loggedUsername === $originalUsername &&
$loggedFileName == $originalFileName &&
$loggedFileId === $originalFileId
) {
$match = $logEntry;
break;
}
}
return $match;
}
}
@@ -0,0 +1,167 @@
<?php
/**
* @file controllers/api/file/linkAction/AddFileLinkAction.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 AddFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to add a submission file.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\submissionFile\SubmissionFile;
class AddFileLinkAction extends BaseAddFileLinkAction
{
/**
* Constructor
*
* @param Request $request
* @param int $submissionId The submission the file should be
* uploaded to.
* @param int $stageId The workflow stage in which the file
* uploader is being instantiated (one of the WORKFLOW_STAGE_ID_*
* constants).
* @param array $uploaderRoles The ids of all roles allowed to upload
* in the context of this action.
* @param int $fileStage The file stage the file should be
* uploaded to (one of the SubmissionFile::SUBMISSION_FILE_* constants).
* @param int $assocType The type of the element the file should
* be associated with (one fo the Application::ASSOC_TYPE_* constants).
* @param int $assocId The id of the element the file should be
* associated with.
* @param int $reviewRoundId The current review round ID (if any)
* @param int $revisedFileId Revised file ID, if any
* @param bool $dependentFilesOnly whether to only include dependent
* files in the Genres dropdown.
* @param int $queryId The query id. Use when the assoc details point
* to a note
*/
public function __construct(
$request,
$submissionId,
$stageId,
$uploaderRoles,
$fileStage,
$assocType = null,
$assocId = null,
$reviewRoundId = null,
$revisedFileId = null,
$dependentFilesOnly = false,
$queryId = null
) {
// Create the action arguments array.
$actionArgs = ['fileStage' => $fileStage, 'reviewRoundId' => $reviewRoundId];
if (is_numeric($assocType) && is_numeric($assocId)) {
$actionArgs['assocType'] = (int)$assocType;
$actionArgs['assocId'] = (int)$assocId;
}
if ($revisedFileId) {
$actionArgs['revisedFileId'] = $revisedFileId;
$actionArgs['revisionOnly'] = true;
}
if ($dependentFilesOnly) {
$actionArgs['dependentFilesOnly'] = true;
}
if ($queryId) {
$actionArgs['queryId'] = $queryId;
}
// Identify text labels based on the file stage.
$textLabels = AddFileLinkAction::_getTextLabels($fileStage);
// Call the parent class constructor.
parent::__construct(
$request,
$submissionId,
$stageId,
$uploaderRoles,
$actionArgs,
__($textLabels['wizardTitle']),
__($textLabels['buttonLabel'])
);
}
//
// Private methods
//
/**
* Static method to return text labels
* for upload to different file stages.
*
* @param int $fileStage One of the
* SubmissionFile::SUBMISSION_FILE_* constants.
*
* @return array
*/
public static function _getTextLabels($fileStage)
{
static $textLabels = [
SubmissionFile::SUBMISSION_FILE_SUBMISSION => [
'wizardTitle' => 'submission.submit.uploadSubmissionFile',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_REVIEW_FILE => [
'wizardTitle' => 'editor.submissionReview.uploadFile',
'buttonLabel' => 'editor.submissionReview.uploadFile'
],
SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE => [
'wizardTitle' => 'editor.submissionReview.uploadFile',
'buttonLabel' => 'editor.submissionReview.uploadFile'
],
SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT => [
'wizardTitle' => 'editor.submissionReview.uploadAttachment',
'buttonLabel' => 'editor.submissionReview.uploadAttachment'
],
SubmissionFile::SUBMISSION_FILE_ATTACHMENT => [
'wizardTitle' => 'editor.submissionReview.uploadFile',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION => [
'wizardTitle' => 'editor.submissionReview.uploadFile',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION => [
'wizardTitle' => 'editor.submissionReview.uploadFile',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_FINAL => [
'wizardTitle' => 'submission.upload.finalDraft',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_COPYEDIT => [
'wizardTitle' => 'submission.upload.copyeditedVersion',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_PRODUCTION_READY => [
'wizardTitle' => 'submission.upload.productionReady',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_PROOF => [
'wizardTitle' => 'submission.upload.proof',
'buttonLabel' => 'submission.changeFile'
],
SubmissionFile::SUBMISSION_FILE_DEPENDENT => [
'wizardTitle' => 'submission.upload.dependent',
'buttonLabel' => 'submission.addFile'
],
SubmissionFile::SUBMISSION_FILE_QUERY => [
'wizardTitle' => 'submission.upload.query',
'buttonLabel' => 'submission.addFile'
],
];
assert(isset($textLabels[$fileStage]));
return $textLabels[$fileStage];
}
}
@@ -0,0 +1,54 @@
<?php
/**
* @file controllers/api/file/linkAction/AddRevisionLinkAction.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 AddRevisionLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to upload a revision of file currently under review.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\submission\reviewRound\ReviewRound;
use PKP\submissionFile\SubmissionFile;
class AddRevisionLinkAction extends BaseAddFileLinkAction
{
/**
* Constructor
*
* @param Request $request
* @param ReviewRound $reviewRound The review round to upload to.
* @param array $uploaderRoles The ids of all roles allowed to upload
* in the context of this action.
*/
public function __construct($request, $reviewRound, $uploaderRoles)
{
// Create the action arguments array.
$actionArgs = [
'fileStage' => SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION,
'stageId' => $reviewRound->getStageId(),
'reviewRoundId' => $reviewRound->getId(),
'revisionOnly' => '1'
];
// Call the parent class constructor.
parent::__construct(
$request,
$reviewRound->getSubmissionId(),
$reviewRound->getStageId(),
$uploaderRoles,
$actionArgs,
__('submission.review.uploadRevisionToRound', ['round' => $reviewRound->getRound()]),
__('submission.addFile')
);
}
}
@@ -0,0 +1,80 @@
<?php
/**
* @defgroup controllers_api_file_linkAction Link action API controller
*/
/**
* @file controllers/api/file/linkAction/BaseAddFileLinkAction.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 BaseAddFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief Abstract base class for file upload actions.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\core\PKPApplication;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\WizardModal;
class BaseAddFileLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param int $submissionId The submission the file should be
* uploaded to.
* @param int $stageId The workflow stage in which the file
* uploader is being instantiated (one of the WORKFLOW_STAGE_ID_*
* constants).
* @param array $uploaderRoles The ids of all roles allowed to upload
* in the context of this action.
* @param array $actionArgs The arguments to be passed into the file
* upload wizard.
* @param string $wizardTitle The title to be displayed in the file
* upload wizard.
* @param string $buttonLabel The link action's button label.
*/
public function __construct(
$request,
$submissionId,
$stageId,
$uploaderRoles,
$actionArgs,
$wizardTitle,
$buttonLabel
) {
// Augment the action arguments array.
$actionArgs['submissionId'] = $submissionId;
$actionArgs['stageId'] = $stageId;
assert(is_array($uploaderRoles) && count($uploaderRoles) >= 1);
$actionArgs['uploaderRoles'] = implode('-', (array) $uploaderRoles);
// Instantiate the file upload modal.
$dispatcher = $request->getDispatcher();
$modal = new WizardModal(
$dispatcher->url(
$request,
PKPApplication::ROUTE_COMPONENT,
null,
'wizard.fileUpload.FileUploadWizardHandler',
'startWizard',
null,
$actionArgs
),
$wizardTitle,
'modal_add_file'
);
// Configure the link action.
parent::__construct('addFile', $modal, $buttonLabel, 'add');
}
}
@@ -0,0 +1,56 @@
<?php
/**
* @file controllers/api/file/linkAction/DeleteFileLinkAction.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 DeleteFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to delete a file.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\submissionFile\SubmissionFile;
class DeleteFileLinkAction extends FileLinkAction
{
/**
* Constructor
*
* @param Request $request
* @param SubmissionFile $submissionFile the submission file to be deleted
* @param int $stageId (optional)
* @param string $localeKey (optional) Locale key to use for delete link
* be deleted.
*/
public function __construct($request, $submissionFile, $stageId, $localeKey = 'grid.action.delete')
{
$router = $request->getRouter();
parent::__construct(
'deleteFile',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.delete'),
$router->url(
$request,
null,
'api.file.ManageFileApiHandler',
'deleteFile',
null,
$this->getActionArgs($submissionFile, $stageId)
),
'modal_delete'
),
__($localeKey),
'delete'
);
}
}
@@ -0,0 +1,91 @@
<?php
/**
* @file controllers/api/file/linkAction/DownloadFileLinkAction.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 DownloadFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to download a file.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\linkAction\request\PostAndRedirectAction;
use PKP\submissionFile\SubmissionFile;
class DownloadFileLinkAction extends FileLinkAction
{
/** @var string Optional label to use instead of file name */
public $label;
/**
* Constructor
*
* @param Request $request
* @param SubmissionFile $submissionFile the submission file to
* link to.
* @param int $stageId (optional)
* @param string $label (optional) Label to use instead of filename
* @param int $fileId (optional) Download a specific revision of a file
* @param string $filename (optional) The filename to use for the file
*/
public function __construct($request, $submissionFile, $stageId = null, $label = null, $fileId = null, $filename = null)
{
// Instantiate the redirect action request.
$router = $request->getRouter();
$this->label = $label;
$actionArgs = $this->getActionArgs($submissionFile, $stageId);
if ($fileId) {
$actionArgs['fileId'] = $fileId;
}
if ($filename) {
$actionArgs['filename'] = $filename;
}
$redirectRequest = new PostAndRedirectAction(
$router->url(
$request,
null,
'api.file.FileApiHandler',
'recordDownload',
null,
$actionArgs
),
$router->url(
$request,
null,
'api.file.FileApiHandler',
'downloadFile',
null,
$actionArgs
)
);
// Configure the file link action.
parent::__construct(
'downloadFile',
$redirectRequest,
htmlspecialchars($this->getLabel($submissionFile))
);
}
/**
* Get the label for the file download action.
*
* @param SubmissionFile $submissionFile
*
* @return string
*/
public function getLabel($submissionFile)
{
if ($this->label !== null) {
return $this->label;
}
return $submissionFile->getLocalizedData('name');
}
}
@@ -0,0 +1,84 @@
<?php
/**
* @file controllers/api/file/linkAction/DownloadLibraryFileLinkAction.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 DownloadLibraryFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to download a library file.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\context\LibraryFile;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\PostAndRedirectAction;
class DownloadLibraryFileLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param LibraryFile $libraryFile the library file to
* link to.
*/
public function __construct($request, $libraryFile)
{
// Instantiate the redirect action request.
$router = $request->getRouter();
$redirectRequest = new PostAndRedirectAction(
$router->url(
$request,
null,
'api.file.FileApiHandler',
'enableLinkAction',
null,
$this->getActionArgs($libraryFile)
),
$router->url(
$request,
null,
'api.file.FileApiHandler',
'downloadLibraryFile',
null,
$this->getActionArgs($libraryFile)
)
);
// Configure the file link action.
parent::__construct(
'downloadFile',
$redirectRequest,
htmlspecialchars($libraryFile->getLocalizedName()),
$libraryFile->getDocumentType()
);
}
/**
* Return the action arguments to address a file.
*
* @param LibraryFile $libraryFile
*
* @return array
*/
public function getActionArgs(&$libraryFile)
{
assert($libraryFile instanceof LibraryFile);
// Create the action arguments array.
$args = ['libraryFileId' => $libraryFile->getId()];
if ($libraryFile->getSubmissionId()) {
$args['submissionId'] = $libraryFile->getSubmissionId();
}
return $args;
}
}
@@ -0,0 +1,59 @@
<?php
/**
* @file controllers/api/file/linkAction/EditFileLinkAction.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 EditFileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An action to edit a file's metadata.
*/
namespace PKP\controllers\api\file\linkAction;
use APP\core\Request;
use PKP\core\PKPApplication;
use PKP\linkAction\request\AjaxModal;
use PKP\submissionFile\SubmissionFile;
class EditFileLinkAction extends FileLinkAction
{
/**
* Constructor
*
* @param Request $request
* @param SubmissionFile $submissionFile the submission file to edit.
* @param int $stageId Stage ID
*/
public function __construct($request, $submissionFile, $stageId)
{
// Instantiate the AJAX modal request.
$router = $request->getRouter();
$dispatcher = $router->getDispatcher();
$modal = new AjaxModal(
$dispatcher->url(
$request,
PKPApplication::ROUTE_COMPONENT,
null,
'api.file.ManageFileApiHandler',
'editMetadata',
null,
$this->getActionArgs($submissionFile, $stageId)
),
__('grid.action.editFile'),
'modal_information'
);
// Configure the file link action.
parent::__construct(
'editFile',
$modal,
__('common.edit'),
'edit'
);
}
}
@@ -0,0 +1,49 @@
<?php
/**
* @file controllers/api/file/linkAction/FileLinkAction.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 FileLinkAction
*
* @ingroup controllers_api_file_linkAction
*
* @brief An abstract file action.
*/
namespace PKP\controllers\api\file\linkAction;
use PKP\linkAction\LinkAction;
use PKP\submissionFile\SubmissionFile;
class FileLinkAction extends LinkAction
{
//
// Protected helper function
//
/**
* Return the action arguments to address a file.
*
* @param SubmissionFile $submissionFile
* @param int $stageId (optional)
*
* @return array
*/
public function getActionArgs($submissionFile, $stageId = null)
{
assert($submissionFile instanceof SubmissionFile);
// Create the action arguments array.
$args = [
'submissionFileId' => $submissionFile->getId(),
'submissionId' => $submissionFile->getData('submissionId')
];
if ($stageId) {
$args['stageId'] = $stageId;
}
return $args;
}
}
@@ -0,0 +1,50 @@
<?php
/**
* @file controllers/api/task/SendReminderLinkAction.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 SendReminderLinkAction
*
* @ingroup controllers_api_task
*
* @brief An action to open up a modal to send a reminder to users assigned to a task.
*/
namespace PKP\controllers\api\task;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
class SendReminderLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param array $actionArgs The action arguments.
*/
public function __construct($request, $modalTitle, $actionArgs)
{
// Instantiate the send review modal.
$router = $request->getRouter();
$ajaxModal = new AjaxModal(
$router->url($request, null, null, 'editReminder', null, $actionArgs),
__($modalTitle),
'review_reminder'
);
// Configure the link action.
parent::__construct(
'sendReminder',
$ajaxModal,
__('editor.review.sendReminder'),
'overdue'
);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* @file controllers/api/task/SendThankYouLinkAction.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 SendThankYouLinkAction
*
* @ingroup controllers_api_task
*
* @brief An action to open up a modal to send a thank you email to users assigned to a review task.
*/
namespace PKP\controllers\api\task;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
class SendThankYouLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param array $actionArgs The action arguments.
*/
public function __construct($request, $modalTitle, $actionArgs)
{
// Instantiate the send thank you modal.
$router = $request->getRouter();
$ajaxModal = new AjaxModal(
$router->url($request, null, null, 'editThankReviewer', null, $actionArgs),
__($modalTitle),
'modal_email'
);
// Configure the link action.
parent::__construct(
'thankReviewer',
$ajaxModal,
__('editor.review.thankReviewer'),
'accepted'
);
}
}
@@ -0,0 +1,67 @@
<?php
/**
* @defgroup controllers_api_user User API controller
*/
/**
* @file controllers/api/user/UserApiHandler.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 UserApiHandler
*
* @ingroup controllers_api_user
*
* @brief Class defining the headless AJAX API for backend user manipulation.
*/
namespace PKP\controllers\api\user;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\handler\PKPHandler;
use PKP\security\authorization\PKPSiteAccessPolicy;
use PKP\security\Validation;
class UserApiHandler extends PKPHandler
{
//
// Implement template methods from PKPHandler
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new PKPSiteAccessPolicy(
$request,
['suggestUsername'],
PKPSiteAccessPolicy::SITE_ACCESS_ALL_ROLES
));
return parent::authorize($request, $args, $roleAssignments);
}
//
// Public handler methods
//
/**
* Get a suggested username, making sure it's not already used.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function suggestUsername($args, $request)
{
$suggestion = Validation::suggestUsername(
$request->getUserVar('givenName'),
$request->getUserVar('familyName')
);
return new JSONMessage(true, $suggestion);
}
}
@@ -0,0 +1,46 @@
<?php
/**
* @file controllers/confirmationModal/linkAction/ViewCompetingInterestGuidelinesLinkAction.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 ViewCompetingInterestGuidelinesLinkAction
*
* @ingroup controllers_confirmationModal_linkAction
*
* @brief An action to open the competing interests confirmation modal.
*/
namespace PKP\controllers\confirmationModal\linkAction;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\ConfirmationModal;
class ViewCompetingInterestGuidelinesLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
*/
public function __construct($request)
{
$context = $request->getContext();
// Instantiate the view competing interests modal.
$viewCompetingInterestsModal = new ConfirmationModal(
$context->getLocalizedData('competingInterests'),
__('reviewer.submission.competingInterests'),
null,
null,
false,
false
);
// Configure the link action.
parent::__construct('viewCompetingInterestGuidelines', $viewCompetingInterestsModal, __('reviewer.submission.competingInterests'));
}
}
@@ -0,0 +1,69 @@
<?php
/**
* @defgroup controllers_confirmationModal_linkAction Confirmation Modal Link Action
*/
/**
* @file controllers/confirmationModal/linkAction/ViewReviewGuidelinesLinkAction.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 ViewReviewGuidelinesLinkAction
*
* @ingroup controllers_confirmationModal_linkAction
*
* @brief An action to open the review guidelines confirmation modal.
*/
namespace PKP\controllers\confirmationModal\linkAction;
use APP\core\Request;
use PKP\context\Context;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\ConfirmationModal;
class ViewReviewGuidelinesLinkAction extends LinkAction
{
/** @var Context */
public $_context;
/** @var int WORKFLOW_STAGE_ID_... */
public $_stageId;
/**
* Constructor
*
* @param Request $request
* @param int $stageId Stage ID of review assignment
*/
public function __construct($request, $stageId)
{
$this->_context = $request->getContext();
$this->_stageId = $stageId;
$viewGuidelinesModal = new ConfirmationModal(
$this->getGuidelines(),
__('reviewer.submission.guidelines'),
null,
null,
false
);
// Configure the link action.
parent::__construct('viewReviewGuidelines', $viewGuidelinesModal, __('reviewer.submission.guidelines'));
}
/**
* Get the guidelines for the specified stage.
*
* @return ?string
*/
public function getGuidelines()
{
return $this->_context->getLocalizedData(
$this->_stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW ? 'reviewGuidelines' : 'internalReviewGuidelines'
);
}
}
@@ -0,0 +1,49 @@
<?php
/**
* @file controllers/grid/admin/context/ContextGridCellProvider.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 ContextGridCellProvider
*
* @ingroup controllers_grid_admin_context
*
* @brief Subclass for a context grid column's cell provider
*/
namespace PKP\controllers\grid\admin\context;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
class ContextGridCellProvider 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\context\Context && !empty($columnId));
switch ($columnId) {
case 'name':
$label = $element->getLocalizedName() != '' ? $element->getLocalizedName() : __('common.untitled');
return ['label' => $label];
case 'urlPath':
$label = $element->getPath();
return ['label' => $label];
default:
break;
}
}
}
@@ -0,0 +1,309 @@
<?php
/**
* @file controllers/grid/admin/context/ContextGridHandler.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 ContextGridHandler
*
* @ingroup controllers_grid_admin_context
*
* @brief Handle context grid requests.
*/
namespace PKP\controllers\grid\admin\context;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\template\TemplateManager;
use PKP\controllers\grid\feature\OrderGridItemsFeature;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
class ContextGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[
Role::ROLE_ID_SITE_ADMIN],
['fetchGrid', 'fetchRow', 'createContext', 'editContext', 'updateContext', 'users',
'deleteContext', 'saveSequence']
);
}
//
// Implement template methods from PKPHandler.
//
/**
* @copydoc 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);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$this->setTitle('context.contexts');
// Grid actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'createContext',
new AjaxModal(
$router->url($request, null, null, 'createContext', null, null),
__('admin.contexts.create'),
'modal_add_item',
true,
'context',
['editContext']
),
__('admin.contexts.create'),
'add_item'
)
);
//
// Grid columns.
//
$contextGridCellProvider = new ContextGridCellProvider();
// Context name.
$this->addColumn(
new GridColumn(
'name',
'common.name',
null,
null,
$contextGridCellProvider
)
);
// Context path.
$this->addColumn(
new GridColumn(
'urlPath',
'context.path',
null,
null,
$contextGridCellProvider
)
);
}
//
// Implement methods from GridHandler.
//
/**
* @copydoc GridHandler::getRowInstance()
*
* @return ContextGridRow
*/
protected function getRowInstance()
{
return new ContextGridRow();
}
/**
* @copydoc GridHandler::loadData()
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
// Get all contexts.
$contextDao = Application::getContextDAO();
$contexts = $contextDao->getAll();
return $contexts->toAssociativeArray();
}
/**
* @copydoc GridHandler::setDataElementSequence()
*/
public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence)
{
$contextDao = Application::getContextDAO();
$gridDataElement->setSequence($newSequence);
$contextDao->updateObject($gridDataElement);
}
/**
* @copydoc GridHandler::getDataElementSequence()
*/
public function getDataElementSequence($gridDataElement)
{
return $gridDataElement->getSequence();
}
/**
* @copydoc GridHandler::addFeatures()
*/
public function initFeatures($request, $args)
{
return [new OrderGridItemsFeature()];
}
/**
* Get the list of "publish data changed" events.
* Used to update the site context switcher upon create/delete.
*
* @return array
*/
public function getPublishChangeEvents()
{
return ['updateHeader'];
}
//
// Public grid actions.
//
/**
* Add a new context.
*
* @param array $args
* @param Request $request
*/
public function createContext($args, $request)
{
// Calling editContext with an empty row id will add a new context.
return $this->editContext($args, $request);
}
/**
* Edit an existing context.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function editContext($args, $request)
{
$contextService = Services::get('context');
$context = null;
if ($request->getUserVar('rowId')) {
$context = $contextService->get((int) $request->getUserVar('rowId'));
if (!$context) {
return new JSONMessage(false);
}
}
$dispatcher = $request->getDispatcher();
if ($context) {
$apiUrl = $dispatcher->url($request, PKPApplication::ROUTE_API, $context->getPath(), 'contexts/' . $context->getId());
$locales = $context->getSupportedFormLocaleNames();
} else {
$apiUrl = $dispatcher->url($request, PKPApplication::ROUTE_API, Application::CONTEXT_ID_ALL, 'contexts');
$locales = $request->getSite()->getSupportedLocaleNames();
}
$locales = array_map(fn (string $locale, string $name) => ['key' => $locale, 'label' => $name], array_keys($locales), $locales);
$contextForm = new \APP\components\forms\context\ContextForm($apiUrl, $locales, $request->getBaseUrl(), $context);
$contextFormConfig = $contextForm->getConfig();
// Pass the URL to the context settings wizard so that the AddContextForm
// component can redirect to it when a new context is added.
if (!$context) {
$contextFormConfig['editContextUrl'] = $request->getDispatcher()->url($request, PKPApplication::ROUTE_PAGE, 'index', 'admin', 'wizard', '__id__');
}
$templateMgr = TemplateManager::getManager($request);
$containerData = [
'components' => [
FORM_CONTEXT => $contextFormConfig,
],
'tinyMCE' => [
'skinUrl' => $templateMgr->getTinyMceSkinUrl($request),
],
];
$templateMgr->assign([
'containerData' => $containerData,
'isAddingNewContext' => !$context,
]);
return new JSONMessage(true, $templateMgr->fetch('admin/editContext.tpl'));
}
/**
* Delete a context.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function deleteContext($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$contextService = Services::get('context');
$context = $contextService->get((int) $request->getUserVar('rowId'));
if (!$context) {
return new JSONMessage(false);
}
$contextService->delete($context);
return \PKP\db\DAO::getDataChangedEvent($context->getId());
}
/**
* Display users management grid for the given context.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function users($args, $request)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('oldUserId', (int) $request->getUserVar('oldUserId')); // for merging users.
parent::setupTemplate($request);
return $templateMgr->fetchJson('management/accessUsers.tpl');
}
}
@@ -0,0 +1,98 @@
<?php
/**
* @file controllers/grid/admin/context/ContextGridRow.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 ContextGridRow
*
* @ingroup controllers_grid_admin_context
*
* @brief Context grid row definition
*/
namespace PKP\controllers\grid\admin\context;
use PKP\controllers\grid\GridRow;
use PKP\core\PKPApplication;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RedirectAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class ContextGridRow 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\context\Context);
$rowId = $this->getId();
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editContext', null, ['rowId' => $rowId]),
__('grid.action.edit'),
'modal_edit',
true,
'context',
['editContext']
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'delete',
new RemoteActionConfirmationModal(
$request->getSession(),
__('admin.contexts.confirmDelete', ['contextName' => $element->getLocalizedName()]),
null,
$router->url($request, null, null, 'deleteContext', null, ['rowId' => $rowId])
),
__('grid.action.remove'),
'delete'
)
);
$dispatcher = $router->getDispatcher();
$this->addAction(
new LinkAction(
'wizard',
new RedirectAction($dispatcher->url($request, PKPApplication::ROUTE_PAGE, 'index', 'admin', 'wizard', $element->getId())),
__('grid.action.wizard'),
'wrench'
)
);
$this->addAction(
new LinkAction(
'users',
new AjaxModal(
$router->url($request, $element->getPath(), null, 'users', null),
__('manager.users'),
'modal_edit',
true
),
__('manager.users'),
'users'
)
);
}
}
@@ -0,0 +1,467 @@
<?php
/**
* @file controllers/grid/admin/languages/AdminLanguageGridHandler.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 AdminLanguageGridHandler
*
* @ingroup controllers_grid_admin_languages
*
* @brief Handle administrative language grid requests. If in single context (e.g.
* press) installation, this grid can also handle language management requests.
* See _canManage().
*/
namespace PKP\controllers\grid\admin\languages;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\facades\Repo;
use APP\notification\NotificationManager;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\languages\form\InstallLanguageForm;
use PKP\controllers\grid\languages\LanguageGridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\notification\PKPNotification;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
use PKP\services\interfaces\EntityWriteInterface;
use PKP\site\Site;
use PKP\site\SiteDAO;
class AdminLanguageGridHandler extends LanguageGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid', 'fetchRow',
'installLocale', 'saveInstallLocale', 'uninstallLocale',
'disableLocale', 'enableLocale', 'setPrimaryLocale'
]
);
}
//
// Implement template methods from PKPHandler.
//
/**
* @copydoc GridHandler::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);
}
/**
* @copydoc LanguageGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Grid actions.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'installLocale',
new AjaxModal(
$router->url($request, null, null, 'installLocale', null, null),
__('admin.languages.installLocale'),
null,
true
),
__('admin.languages.installLocale'),
'add'
)
);
// Columns.
// Enable locale.
$this->addColumn(
new GridColumn(
'enable',
'common.enable',
null,
'controllers/grid/common/cell/selectStatusCell.tpl',
$this->getCellProvider(),
['width' => 10]
)
);
$this->addNameColumn(); // Locale name.
$this->addLocaleCodeColumn(); // Locale code.
// Primary locale.
if ($this->_canManage($request)) {
$primaryId = 'contextPrimary';
} else {
$primaryId = 'sitePrimary';
}
$this->addPrimaryColumn($primaryId);
if ($this->_canManage($request)) {
$this->addManagementColumns();
}
$this->setFootNote('admin.locale.maybeIncomplete');
}
//
// Implement methods from GridHandler.
//
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$site = $request->getSite(); /** @var Site $site */
$data = [];
$installedLocales = $site->getInstalledLocaleNames();
$supportedLocales = $site->getSupportedLocales();
$primaryLocale = $site->getPrimaryLocale();
foreach ($installedLocales as $localeKey => $localeName) {
$data[$localeKey] = [];
$data[$localeKey]['code'] = $localeKey;
$data[$localeKey]['name'] = $localeName;
$data[$localeKey]['incomplete'] = !Locale::getMetadata($localeKey)->isComplete();
$data[$localeKey]['supported'] = in_array($localeKey, $supportedLocales);
if ($this->_canManage($request)) {
$context = $request->getContext();
$primaryLocale = $context->getPrimaryLocale();
}
$data[$localeKey]['primary'] = $localeKey === $primaryLocale;
}
if ($this->_canManage($request)) {
$data = $this->addManagementData($request, $data);
}
return $data;
}
//
// Public grid actions.
//
/**
* Open a form to select locales for installation.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function installLocale($args, $request)
{
// Form handling.
$installLanguageForm = new InstallLanguageForm();
$installLanguageForm->initData();
return new JSONMessage(true, $installLanguageForm->fetch($request));
}
/**
* Save the install language form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function saveInstallLocale($args, $request)
{
$installLanguageForm = new InstallLanguageForm();
$installLanguageForm->readInputData();
if ($installLanguageForm->validate()) {
$installLanguageForm->execute();
$this->_updateContextLocaleSettings($request);
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeInstalled')]
);
}
return \PKP\db\DAO::getDataChangedEvent();
}
/**
* Uninstall a locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function uninstallLocale($args, $request)
{
$site = $request->getSite();
$locale = $request->getUserVar('rowId');
$gridData = $this->getGridDataElements($request);
if ($request->checkCSRF() && array_key_exists($locale, $gridData)) {
$localeData = $gridData[$locale];
if ($localeData['primary']) {
return new JSONMessage(false);
}
$installedLocales = $site->getInstalledLocales();
if (in_array($locale, $installedLocales)) {
$installedLocales = array_diff($installedLocales, [$locale]);
$site->setInstalledLocales($installedLocales);
$supportedLocales = $site->getSupportedLocales();
$supportedLocales = array_diff($supportedLocales, [$locale]);
$site->setSupportedLocales($supportedLocales);
$siteDao = DAORegistry::getDAO('SiteDAO'); /** @var SiteDAO $siteDao */
$siteDao->updateObject($site);
$this->_updateContextLocaleSettings($request);
Locale::uninstallLocale($locale);
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeUninstalled', ['locale' => $localeData['name']])]
);
}
return \PKP\db\DAO::getDataChangedEvent($locale);
}
return new JSONMessage(false);
}
/**
* Enable an existing locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function enableLocale($args, $request)
{
$rowId = $request->getUserVar('rowId');
$gridData = $this->getGridDataElements($request);
if (array_key_exists($rowId, $gridData)) {
$this->_updateLocaleSupportState($request, $rowId, true);
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeEnabled')]
);
}
return \PKP\db\DAO::getDataChangedEvent($rowId);
}
/**
* Disable an existing locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function disableLocale($args, $request)
{
$locale = $request->getUserVar('rowId');
$gridData = $this->getGridDataElements($request);
$notificationManager = new NotificationManager();
$user = $request->getUser();
if ($request->checkCSRF() && array_key_exists($locale, $gridData)) {
// Don't disable primary locales.
if ($gridData[$locale]['primary']) {
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_ERROR,
['contents' => __('admin.languages.cantDisable')]
);
} else {
$this->_updateLocaleSupportState($request, $locale, false);
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeDisabled')]
);
}
return \PKP\db\DAO::getDataChangedEvent($locale);
}
return new JSONMessage(false);
}
/**
* Set primary locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function setPrimaryLocale($args, $request)
{
$rowId = $request->getUserVar('rowId');
$gridData = $this->getGridDataElements($request);
$localeData = $gridData[$rowId];
$notificationManager = new NotificationManager();
$user = $request->getUser();
$site = $request->getSite();
if (array_key_exists($rowId, $gridData)) {
if (Locale::isLocaleValid($rowId)) {
$oldSitePrimaryLocale = $site->getPrimaryLocale();
Repo::user()->dao->changeSitePrimaryLocale($oldSitePrimaryLocale, $rowId);
$site->setPrimaryLocale($rowId);
$siteDao = DAORegistry::getDAO('SiteDAO'); /** @var SiteDAO $siteDao */
$siteDao->updateObject($site);
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.primaryLocaleDefined', ['locale' => $localeData['name']])]
);
}
}
// Need to refresh whole grid to remove the check in others
// primary locale radio buttons.
return \PKP\db\DAO::getDataChangedEvent();
}
//
// Helper methods.
//
/**
* Update the locale support state (enabled or disabled).
*
* @param Request $request
* @param string $rowId The locale row id.
* @param bool $enable Enable locale flag.
*/
protected function _updateLocaleSupportState($request, $rowId, $enable)
{
$newSupportedLocales = [];
$gridData = $this->getGridDataElements($request);
foreach ($gridData as $locale => $data) {
if ($data['supported']) {
array_push($newSupportedLocales, $locale);
}
}
if (Locale::isLocaleValid($rowId)) {
if ($enable) {
array_push($newSupportedLocales, $rowId);
} else {
$key = array_search($rowId, $newSupportedLocales);
if ($key !== false) {
unset($newSupportedLocales[$key]);
}
}
}
$site = $request->getSite();
$site->setSupportedLocales($newSupportedLocales);
$siteDao = DAORegistry::getDAO('SiteDAO'); /** @var SiteDAO $siteDao */
$siteDao->updateObject($site);
$this->_updateContextLocaleSettings($request);
}
/**
* Helper function to update locale settings in all
* installed contexts, based on site locale settings.
*
* @param object $request
*/
protected function _updateContextLocaleSettings($request)
{
$site = $request->getSite();
$siteSupportedLocales = $site->getSupportedLocales();
$contextService = Services::get('context');
$contextDao = Application::getContextDAO();
$contexts = $contextDao->getAll();
while ($context = $contexts->next()) {
$params = [];
$primaryLocale = $context->getPrimaryLocale();
foreach (['supportedLocales', 'supportedFormLocales', 'supportedSubmissionLocales'] as $settingName) {
$localeList = $context->getData($settingName);
if (is_array($localeList)) {
$params[$settingName] = array_intersect($localeList, $siteSupportedLocales);
}
}
if (!in_array($primaryLocale, $siteSupportedLocales)) {
$params['primaryLocale'] = $site->getPrimaryLocale();
$primaryLocale = $params['primaryLocale'];
}
$errors = $contextService->validate(EntityWriteInterface::VALIDATE_ACTION_EDIT, $params, $params['supportedLocales'], $primaryLocale);
// If there are errors, it's too late to do anything about it
assert(empty($errors));
$contextService->edit($context, $params, $request);
}
}
/**
* This grid can also present management functions
* if the conditions above are true.
*
* @param Request $request
*
* @return bool
*/
protected function _canManage($request)
{
$contextDao = Application::getContextDAO();
$contexts = $contextDao->getAll();
$userRoles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES);
[$firstContext, $secondContext] = [$contexts->next(), $contexts->next()];
return ($firstContext && !$secondContext && $request->getContext() && in_array(Role::ROLE_ID_MANAGER, $userRoles));
}
}
@@ -0,0 +1,85 @@
<?php
/**
* @file controllers/grid/admin/plugins/AdminPluginGridHandler.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 AdminPluginGridHandler
*
* @ingroup controllers_grid_admin_plugins
*
* @brief Handle site level plugins grid requests.
*/
namespace PKP\controllers\grid\admin\plugins;
use APP\core\Application;
use PKP\controllers\grid\plugins\PluginGridHandler;
use PKP\controllers\grid\plugins\PluginGridRow;
use PKP\core\PKPRequest;
use PKP\security\authorization\PluginAccessPolicy;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
class AdminPluginGridHandler extends PluginGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$roles = [Role::ROLE_ID_SITE_ADMIN];
$this->addRoleAssignment($roles, ['plugin']);
parent::__construct($roles);
}
//
// Overriden template methods.
//
/**
* @see GridHandler::getRowInstance()
*/
public function getRowInstance()
{
return new PluginGridRow($this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES));
}
/**
* @see GridHandler::authorize()
*
* @param PKPRequest $request
* @param array $args
* @param array $roleAssignments
*/
public function authorize($request, &$args, $roleAssignments)
{
$category = $request->getUserVar('category');
$pluginName = $request->getUserVar('plugin');
$verb = $request->getUserVar('verb');
if ($category && $pluginName) {
if ($verb) {
$accessMode = PluginAccessPolicy::ACCESS_MODE_MANAGE;
} else {
$accessMode = PluginAccessPolicy::ACCESS_MODE_ADMIN;
}
$this->addPolicy(new PluginAccessPolicy($request, $args, $roleAssignments, $accessMode));
} else {
$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);
}
}
@@ -0,0 +1,76 @@
<?php
/**
* @file controllers/grid/announcements/AnnouncementTypeGridCellProvider.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 AnnouncementTypeGridCellProvider
*
* @ingroup controllers_grid_announcements
*
* @brief Cell provider for title column of an announcement type grid.
*/
namespace PKP\controllers\grid\announcements;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
class AnnouncementTypeGridCellProvider extends GridCellProvider
{
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
switch ($column->getId()) {
case 'name':
$announcementType = $row->getData();
$router = $request->getRouter();
$actionArgs = ['announcementTypeId' => $row->getId()];
return [new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editAnnouncementType', null, $actionArgs),
__('grid.action.edit'),
null,
true
),
htmlspecialchars($announcementType->getLocalizedTypeName())
)];
}
return parent::getCellActions($request, $row, $column, $position);
}
/**
* 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)
{
$announcementType = $row->getData();
$columnId = $column->getId();
assert($announcementType instanceof \PKP\announcement\AnnouncementType && !empty($columnId));
switch ($columnId) {
case 'title':
return ['label' => $announcementType->getLocalizedTypeName()];
default:
break;
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
}
@@ -0,0 +1,246 @@
<?php
/**
* @file controllers/grid/announcements/AnnouncementTypeGridHandler.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 AnnouncementTypeGridHandler
*
* @ingroup controllers_grid_announcements
*
* @brief Handle announcement type grid requests.
*/
namespace PKP\controllers\grid\announcements;
use APP\core\Application;
use APP\notification\NotificationManager;
use PKP\announcement\AnnouncementTypeDAO;
use PKP\controllers\grid\announcements\form\AnnouncementTypeForm;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
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\PKPSiteAccessPolicy;
use PKP\security\authorization\UserRolesRequiredPolicy;
use PKP\security\Role;
class AnnouncementTypeGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid', 'fetchRow',
'addAnnouncementType', 'editAnnouncementType',
'updateAnnouncementType',
'deleteAnnouncementType'
]
);
}
//
// Overridden template methods
//
/**
* @copydoc GridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$context = $request->getContext();
if ($context) {
$this->addPolicy(new ContextAccessPolicy($request, $roleAssignments));
} else {
$this->addPolicy(new PKPSiteAccessPolicy($request, null, $roleAssignments));
}
$announcementTypeId = $request->getUserVar('announcementTypeId');
if ($announcementTypeId) {
// Ensure announcement type is valid and for this context
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
$announcementType = $announcementTypeDao->getById($announcementTypeId);
if (!$announcementType || $announcementType->getContextId() != $context?->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);
// Basic grid configuration
$this->setTitle('manager.announcementTypes');
// Set the no items row text
$this->setEmptyRowText('manager.announcementTypes.noneCreated');
// Columns
$announcementTypeCellProvider = new AnnouncementTypeGridCellProvider();
$this->addColumn(
new GridColumn(
'name',
'common.name',
null,
null,
$announcementTypeCellProvider,
['width' => 60]
)
);
// Add grid action.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addAnnouncementType',
new AjaxModal(
$router->url($request, null, null, 'addAnnouncementType', null, null),
__('grid.action.addAnnouncementType'),
'modal_add_item',
true
),
__('grid.action.addAnnouncementType'),
'add_item'
)
);
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
return $announcementTypeDao->getByContextId($request->getContext()?->getId());
}
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new AnnouncementTypeGridRow();
}
//
// Public grid actions.
//
/**
* Display form to add announcement type.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage
*/
public function addAnnouncementType($args, $request)
{
return $this->editAnnouncementType($args, $request);
}
/**
* Display form to edit an announcement type.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editAnnouncementType($args, $request)
{
$announcementTypeId = (int)$request->getUserVar('announcementTypeId');
$announcementTypeForm = new AnnouncementTypeForm($request->getContext()?->getId(), $announcementTypeId);
$announcementTypeForm->initData();
return new JSONMessage(true, $announcementTypeForm->fetch($request));
}
/**
* Save an edited/inserted announcement type.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateAnnouncementType($args, $request)
{
// Identify the announcement type id.
$announcementTypeId = $request->getUserVar('announcementTypeId');
// Form handling.
$announcementTypeForm = new AnnouncementTypeForm($request->getContext()?->getId(), $announcementTypeId);
$announcementTypeForm->readInputData();
if ($announcementTypeForm->validate()) {
$announcementTypeForm->execute();
if ($announcementTypeId) {
// Successful edit of an existing announcement type.
$notificationLocaleKey = 'notification.editedAnnouncementType';
} else {
// Successful added a new announcement type.
$notificationLocaleKey = 'notification.addedAnnouncementType';
}
// Record the notification to user.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __($notificationLocaleKey)]);
// Prepare the grid row data.
return \PKP\db\DAO::getDataChangedEvent($announcementTypeId);
} else {
return new JSONMessage(false);
}
}
/**
* Delete an announcement type.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteAnnouncementType($args, $request)
{
$announcementTypeId = (int) $request->getUserVar('announcementTypeId');
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
$announcementType = $announcementTypeDao->getById($announcementTypeId, $request->getContext()?->getId());
if ($announcementType && $request->checkCSRF()) {
$announcementTypeDao->deleteObject($announcementType);
// Create notification.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.removedAnnouncementType')]);
return \PKP\db\DAO::getDataChangedEvent();
}
return new JSONMessage(false);
}
}
@@ -0,0 +1,79 @@
<?php
/**
* @file controllers/grid/announcements/AnnouncementTypeGridRow.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 AnnouncementTypeGridRow
*
* @ingroup controllers_grid_content_announcements
*
* @brief Announcement type grid row definition
*/
namespace PKP\controllers\grid\announcements;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class AnnouncementTypeGridRow 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\announcement\AnnouncementType);
$rowId = $this->getId();
if (!empty($rowId) && is_numeric($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
$actionArgs = [
'announcementTypeId' => $rowId
];
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editAnnouncementType', null, $actionArgs),
__('grid.action.edit'),
'modal_edit',
true
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'remove',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.remove'),
$router->url($request, null, null, 'deleteAnnouncementType', null, $actionArgs),
'modal_delete'
),
__('grid.action.remove'),
'delete'
)
);
}
}
}
@@ -0,0 +1,128 @@
<?php
/**
* @file controllers/grid/announcements/form/AnnouncementTypeForm.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 AnnouncementTypeForm
*
* @ingroup controllers_grid_announcements_form
*
* @see AnnouncementType
*
* @brief Form for manager to create/edit announcement types.
*/
namespace PKP\controllers\grid\announcements\form;
use APP\template\TemplateManager;
use PKP\announcement\AnnouncementTypeDAO;
use PKP\db\DAORegistry;
use PKP\form\Form;
class AnnouncementTypeForm extends Form
{
/** @var ?int Context ID or null for site announcement */
public $contextId;
/** @var int The ID of the announcement type being edited */
public $typeId;
/**
* Constructor
*
* @param ?int $contextId Context ID or null for site announcement
* @param int $typeId leave as default for new announcement type
*/
public function __construct($contextId, $typeId = null)
{
$this->typeId = isset($typeId) ? (int) $typeId : null;
$this->contextId = $contextId;
parent::__construct('manager/announcement/announcementTypeForm.tpl');
// Type name is provided
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'name', 'required', 'manager.announcementTypes.form.typeNameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
/**
* Get a list of localized field names for this form
*
* @return array
*/
public function getLocaleFieldNames()
{
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
return $announcementTypeDao->getLocaleFieldNames();
}
/**
* @copydoc Form::fetch()
*/
public function fetch($request, $template = 'controllers/grid/announcements/form/announcementTypeForm.tpl', $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('typeId', $this->typeId);
return parent::fetch($request, $template, $display);
}
/**
* Initialize form data from current announcement type.
*/
public function initData()
{
if (isset($this->typeId)) {
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
$announcementType = $announcementTypeDao->getById($this->typeId);
if ($announcementType != null) {
$this->_data = [
'name' => $announcementType->getName(null) // Localized
];
} else {
$this->typeId = null;
}
}
}
/**
* Assign form data to user-submitted data.
*/
public function readInputData()
{
$this->readUserVars(['name']);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$announcementTypeDao = DAORegistry::getDAO('AnnouncementTypeDAO'); /** @var AnnouncementTypeDAO $announcementTypeDao */
if (isset($this->typeId)) {
$announcementType = $announcementTypeDao->getById($this->typeId);
}
if (!isset($announcementType)) {
$announcementType = $announcementTypeDao->newDataObject();
}
$announcementType->setContextId($this->contextId);
$announcementType->setName($this->getData('name'), null); // Localized
// Update or insert announcement type
if ($announcementType->getId() != null) {
$announcementTypeDao->updateObject($announcementType);
} else {
$announcementTypeDao->insertObject($announcementType);
}
parent::execute(...$functionArgs);
}
}
@@ -0,0 +1,116 @@
<?php
/**
* @file controllers/grid/eventLog/EventLogGridCellProvider.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 EventLogGridCellProvider
*
* @ingroup controllers_grid_publicationEntry
*
* @brief Cell provider for event log entries.
*/
namespace PKP\controllers\grid\eventLog;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\grid\DataObjectGridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\db\DAORegistry;
use PKP\log\event\EventLogEntry;
use PKP\log\event\PKPSubmissionEventLogEntry;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submissionFile\SubmissionFile;
class EventLogGridCellProvider extends DataObjectGridCellProvider
{
/** @var bool Is the current user assigned as an author to this submission */
public $_isCurrentUserAssignedAuthor;
/**
* Constructor
*
* @param bool $isCurrentUserAssignedAuthor Is the current user assigned
* as an author to this submission?
*/
public function __construct($isCurrentUserAssignedAuthor)
{
parent::__construct();
$this->_isCurrentUserAssignedAuthor = $isCurrentUserAssignedAuthor;
}
//
// Template methods from GridCellProvider
//
/**
* Extracts variables for a given column from a data element
* so that they may be assigned to template before rendering.
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return array
*/
public function getTemplateVarsFromRowColumn($row, $column)
{
$element = $row->getData();
$columnId = $column->getId();
assert($element instanceof \PKP\core\DataObject && !empty($columnId));
/** @var EventLogEntry $element */
switch ($columnId) {
case 'date':
return ['label' => $element instanceof EventLogEntry ? $element->getDateLogged() : $element->getDateSent()];
case 'event':
return ['label' => $element instanceof EventLogEntry ? $element->getTranslatedMessage(null, $this->_isCurrentUserAssignedAuthor) : $element->getPrefixedSubject()];
case 'user':
if ($element instanceof EventLogEntry) {
$userName = $element->getUserFullName();
// Anonymize reviewer details where necessary
if ($this->_isCurrentUserAssignedAuthor) {
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
// Maybe anonymize reviewer log entries
$reviewerLogTypes = [
PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_ACCEPT,
PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_DECLINE,
PKPSubmissionEventLogEntry::SUBMISSION_LOG_REVIEW_UNCONSIDERED,
];
if (in_array($element->getEventType(), $reviewerLogTypes)) {
$userName = __('editor.review.anonymousReviewer');
if ($reviewAssignmentId = $element->getData('reviewAssignmentId')) {
$reviewAssignment = $reviewAssignmentDao->getById($reviewAssignmentId);
if ($reviewAssignment && $reviewAssignment->getReviewMethod() === ReviewAssignment::SUBMISSION_REVIEW_METHOD_OPEN) {
$userName = $element->getUserFullName();
}
}
}
// Maybe anonymize files submitted by reviewers
$fileStage = $element->getData('fileStage');
if ($fileStage && $fileStage === SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT) {
$submissionFileId = $element->getData('submissionFileId');
assert($element->getData('fileId') && $element->getData('submissionId') && $submissionFileId);
$submissionFile = Repo::submissionFile()->get($submissionFileId);
if ($submissionFile && $submissionFile->getData('assocType') === Application::ASSOC_TYPE_REVIEW_ASSIGNMENT) {
$reviewAssignment = $reviewAssignmentDao->getById($submissionFile->getData('assocId'));
if (!$reviewAssignment || in_array($reviewAssignment->getReviewMethod(), [ReviewAssignment::SUBMISSION_REVIEW_METHOD_ANONYMOUS, ReviewAssignment::SUBMISSION_REVIEW_METHOD_DOUBLEANONYMOUS])) {
$userName = __('editor.review.anonymousReviewer');
}
}
}
}
} else {
$userName = $element->getSenderFullName();
}
return ['label' => $userName];
default:
assert(false);
}
}
}
@@ -0,0 +1,116 @@
<?php
/**
* @file controllers/grid/eventLog/EventLogGridRow.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 EventLogGridRow
*
* @ingroup controllers_grid_eventLog
*
* @brief EventLog grid row definition
*/
namespace PKP\controllers\grid\eventLog;
use APP\core\Application;
use APP\facades\Repo;
use APP\submission\Submission;
use PKP\controllers\api\file\linkAction\DownloadFileLinkAction;
use PKP\controllers\grid\eventLog\linkAction\EmailLinkAction;
use PKP\controllers\grid\GridRow;
use PKP\db\DAORegistry;
use PKP\log\EmailLogEntry;
use PKP\log\event\EventLogEntry;
use PKP\log\event\SubmissionFileEventLogEntry;
use PKP\submission\reviewAssignment\ReviewAssignment;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submissionFile\SubmissionFile;
class EventLogGridRow extends GridRow
{
/** @var Submission */
public $_submission;
/** @var bool Is the current user assigned as an author to this submission */
public $_isCurrentUserAssignedAuthor;
/**
* Constructor
*
* @param Submission $submission
* @param bool $isCurrentUserAssignedAuthor Is the current user assigned
* as an author to this submission?
*/
public function __construct($submission, $isCurrentUserAssignedAuthor)
{
$this->_submission = $submission;
$this->_isCurrentUserAssignedAuthor = $isCurrentUserAssignedAuthor;
parent::__construct();
}
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$logEntry = $this->getData(); // a Category object
assert($logEntry != null && ($logEntry instanceof EventLogEntry || $logEntry instanceof EmailLogEntry));
if ($logEntry instanceof EventLogEntry) {
switch ($logEntry->getEventType()) {
case SubmissionFileEventLogEntry::SUBMISSION_LOG_FILE_REVISION_UPLOAD:
case SubmissionFileEventLogEntry::SUBMISSION_LOG_FILE_UPLOAD:
$submissionFileId = $logEntry->getData('submissionFileId');
$fileId = $logEntry->getData('fileId');
$submissionFile = $submissionFileId ? Repo::submissionFile()->get($submissionFileId) : null;
if (!$submissionFile) {
break;
}
$filename = $logEntry->getLocalizedData('filename') ?? $submissionFile->getLocalizedData('name');
if ($submissionFile) {
$anonymousAuthor = false;
$maybeAnonymousAuthor = $this->_isCurrentUserAssignedAuthor && $submissionFile->getData('fileStage') === SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT;
if ($maybeAnonymousAuthor && $submissionFile->getData('assocType') === Application::ASSOC_TYPE_REVIEW_ASSIGNMENT) {
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment = $reviewAssignmentDao->getById($submissionFile->getData('assocId'));
if ($reviewAssignment && in_array($reviewAssignment->getReviewMethod(), [ReviewAssignment::SUBMISSION_REVIEW_METHOD_ANONYMOUS, ReviewAssignment::SUBMISSION_REVIEW_METHOD_DOUBLEANONYMOUS])) {
$anonymousAuthor = true;
}
}
if (!$anonymousAuthor) {
$workflowStageId = Repo::submissionFile()->getWorkflowStageId($submissionFile);
// If a submission file is attached to a query that has been deleted, we cannot
// determine its stage. Don't present a download link in this case.
if ($workflowStageId || $submissionFile->getData('fileStage') != SubmissionFile::SUBMISSION_FILE_QUERY) {
$this->addAction(new DownloadFileLinkAction($request, $submissionFile, $workflowStageId, __('common.download'), $fileId, $filename));
}
}
}
break;
}
} elseif ($logEntry instanceof EmailLogEntry) {
$this->addAction(
new EmailLinkAction(
$request,
__('submission.event.viewEmail'),
[
'submissionId' => $logEntry->getAssocId(),
'emailLogEntryId' => $logEntry->getId(),
]
)
);
}
}
}
@@ -0,0 +1,270 @@
<?php
/**
* @file controllers/grid/eventLog/SubmissionEventLogGridHandler.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 SubmissionEventLogGridHandler
*
* @ingroup controllers_grid_eventLog
*
* @brief Grid handler presenting the submission event log grid.
*/
namespace PKP\controllers\grid\eventLog;
use APP\core\Application;
use APP\facades\Repo;
use APP\submission\Submission;
use PKP\controllers\grid\DateGridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPApplication;
use PKP\core\PKPRequest;
use PKP\core\PKPString;
use PKP\db\DAORegistry;
use PKP\log\EmailLogEntry;
use PKP\log\SubmissionEmailLogDAO;
use PKP\log\event\EventLogEntry;
use PKP\security\authorization\internal\UserAccessibleWorkflowStageRequiredPolicy;
use PKP\security\authorization\SubmissionAccessPolicy;
use PKP\security\Role;
class SubmissionEventLogGridHandler extends GridHandler
{
/** @var Submission */
public $_submission;
/** @var int The current workflow stage */
public $_stageId;
/** @var bool Is the current user assigned as an author to this submission */
public $_isCurrentUserAssignedAuthor;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR],
['fetchGrid', 'fetchRow', 'viewEmail']
);
}
//
// Getters/Setters
//
/**
* Get the submission associated with this grid.
*
* @return Submission
*/
public function getSubmission()
{
return $this->_submission;
}
/**
* Set the Submission
*
* @param Submission $submission
*/
public function setSubmission($submission)
{
$this->_submission = $submission;
}
//
// Overridden methods from PKPHandler
//
/**
* @see PKPHandler::authorize()
*
* @param PKPRequest $request
* @param array $args
* @param array $roleAssignments
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new SubmissionAccessPolicy($request, $args, $roleAssignments));
$this->addPolicy(new UserAccessibleWorkflowStageRequiredPolicy($request, PKPApplication::WORKFLOW_TYPE_EDITORIAL));
$success = parent::authorize($request, $args, $roleAssignments);
// Prevent authors from accessing review details, even if they are also
// assigned as an editor, sub-editor or assistant.
$userAssignedRoles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES);
$this->_isCurrentUserAssignedAuthor = false;
foreach ($userAssignedRoles as $stageId => $roles) {
if (in_array(Role::ROLE_ID_AUTHOR, $roles)) {
$this->_isCurrentUserAssignedAuthor = true;
break;
}
}
return $success;
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Retrieve the authorized monograph.
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
$this->setSubmission($submission);
$this->_stageId = (int) ($args['stageId'] ?? null);
// Columns
$cellProvider = new EventLogGridCellProvider($this->_isCurrentUserAssignedAuthor);
$this->addColumn(
new GridColumn(
'date',
'common.date',
null,
null,
new DateGridCellProvider(
$cellProvider,
Application::get()->getRequest()->getContext()->getLocalizedDateFormatShort()
)
)
);
$this->addColumn(
new GridColumn(
'user',
'common.user',
null,
null,
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'event',
'common.event',
null,
null,
$cellProvider,
['width' => 60]
)
);
}
//
// Overridden methods from GridHandler
//
/**
* @see GridHandler::getRowInstance()
*
* @return EventLogGridRow
*/
protected function getRowInstance()
{
return new EventLogGridRow($this->getSubmission(), $this->_isCurrentUserAssignedAuthor);
}
/**
* Get the arguments that will identify the data in the grid
* In this case, the monograph.
*
* @return array
*/
public function getRequestArgs()
{
$submission = $this->getSubmission();
return [
'submissionId' => $submission->getId(),
'stageId' => $this->_stageId,
];
}
/**
* @copydoc GridHandler::loadData
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
$submissionEmailLogDao = DAORegistry::getDAO('SubmissionEmailLogDAO'); /** @var SubmissionEmailLogDAO $submissionEmailLogDao */
$submission = $this->getSubmission();
$eventLogEntries = Repo::eventLog()->getCollector()
->filterByAssoc(PKPApplication::ASSOC_TYPE_SUBMISSION, [$submission->getId()])
->getMany();
$emailLogEntries = $submissionEmailLogDao->getBySubmissionId($submission->getId());
$entries = array_merge($eventLogEntries->toArray(), $emailLogEntries->toArray());
// Sort the merged data by date, most recent first
usort($entries, function ($a, $b) {
$aDate = $a instanceof EventLogEntry ? $a->getDateLogged() : $a->getDateSent();
$bDate = $b instanceof EventLogEntry ? $b->getDateLogged() : $b->getDateSent();
if ($aDate == $bDate) {
return 0;
}
return $aDate < $bDate ? 1 : -1;
});
return $entries;
}
/**
* Get the contents of the email
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function viewEmail($args, $request)
{
$submissionEmailLogDao = DAORegistry::getDAO('SubmissionEmailLogDAO'); /** @var SubmissionEmailLogDAO $submissionEmailLogDao */
$emailLogEntry = $submissionEmailLogDao->getById((int) $args['emailLogEntryId']);
return new JSONMessage(true, $this->_formatEmail($emailLogEntry));
}
/**
* Format the contents of the email
*
*
* @return string Formatted email
*/
public function _formatEmail(EmailLogEntry $emailLogEntry)
{
$text = [];
$text[] = __('email.from') . ': ' . htmlspecialchars($emailLogEntry->getFrom());
$text[] = __('email.to') . ': ' . htmlspecialchars($emailLogEntry->getRecipients());
if ($emailLogEntry->getCcs()) {
$text[] = __('email.cc') . ': ' . htmlspecialchars($emailLogEntry->getCcs());
}
if ($emailLogEntry->getBccs()) {
$text[] = __('email.bcc') . ': ' . htmlspecialchars($emailLogEntry->getBccs());
}
$text[] = __('email.subject') . ': ' . htmlspecialchars($emailLogEntry->getSubject());
return
'<div class="pkp_workflow_email_log_view">'
. nl2br(join(PHP_EOL, $text)) . '<br><br>'
. PKPString::stripUnsafeHtml($emailLogEntry->getBody())
. '</div>';
}
}
@@ -0,0 +1,146 @@
<?php
/**
* @file controllers/grid/eventLog/SubmissionFileEventLogGridHandler.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 SubmissionFileEventLogGridHandler
*
* @ingroup controllers_grid_eventLog
*
* @brief Grid handler presenting the submission file event log grid.
*/
namespace PKP\controllers\grid\eventLog;
use APP\core\Application;
use APP\facades\Repo;
use PKP\core\PKPApplication;
use PKP\core\PKPRequest;
use PKP\security\authorization\SubmissionFileAccessPolicy;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class SubmissionFileEventLogGridHandler extends SubmissionEventLogGridHandler
{
/** @var SubmissionFile SubmissionFile */
public $_submissionFile;
//
// Getters/Setters
//
/**
* Get the submission file associated with this grid.
*
* @return SubmissionFile
*/
public function getSubmissionFile()
{
return $this->_submissionFile;
}
/**
* Set the submission file
*
* @param SubmissionFile $submissionFile
*/
public function setSubmissionFile($submissionFile)
{
$this->_submissionFile = $submissionFile;
}
//
// Overridden methods from PKPHandler
//
/**
* @see PKPHandler::authorize()
*
* @param PKPRequest $request
* @param array $args
* @param array $roleAssignments
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new SubmissionFileAccessPolicy($request, $args, $roleAssignments, SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_READ, (int) $args['submissionFileId']));
return parent::authorize($request, $args, $roleAssignments);
}
/**
* Configure the grid
*
* @see SubmissionEventLogGridHandler::initialize
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Retrieve the authorized monograph.
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
$this->setSubmissionFile($submissionFile);
}
//
// Overridden methods from GridHandler
//
/**
* Get the arguments that will identify the data in the grid
* In this case, the monograph.
*
* @return array
*/
public function getRequestArgs()
{
$submissionFile = $this->getSubmissionFile();
return [
'submissionId' => $submissionFile->getData('submissionId'),
'submissionFileId' => $submissionFile->getId(),
'stageId' => $this->_stageId,
];
}
/**
* @copydoc GridHandler::loadData
*
* @param null|mixed $filter
*/
protected function loadData($request, $filter = null)
{
return Repo::eventLog()->getCollector()
->filterByAssoc(PKPApplication::ASSOC_TYPE_SUBMISSION_FILE, [$this->getSubmissionFile()->getId()])
->getMany()
->toArray();
}
/**
* @copydoc GridHandler::getFilterForm()
*
* @return string Filter template.
*/
protected function getFilterForm()
{
// If the user only has an author role, do not permit access
// to earlier stages.
$userRoles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES);
if (array_intersect([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT], $userRoles)) {
return 'controllers/grid/eventLog/eventLogGridFilter.tpl';
}
return parent::getFilterForm();
}
/**
* @copydoc GridHandler::getFilterSelectionData()
*/
public function getFilterSelectionData($request)
{
return ['allEvents' => $request->getUserVar('allEvents') ? true : false];
}
}
@@ -0,0 +1,51 @@
<?php
/**
* @file controllers/grid/eventLog/linkAction/EmailLinkAction.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 EmailLinkAction
*
* @ingroup controllers_api_submission
*
* @brief An action to open up a modal to view an email sent to a user.
*/
namespace PKP\controllers\grid\eventLog\linkAction;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
class EmailLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param string $modalTitle Title of the modal
* @param array $actionArgs The action arguments.
*/
public function __construct($request, $modalTitle, $actionArgs)
{
$router = $request->getRouter();
// Instantiate the view email modal.
$ajaxModal = new AjaxModal(
$router->url($request, null, null, 'viewEmail', null, $actionArgs),
$modalTitle,
'modal_email'
);
// Configure the link action.
parent::__construct(
'viewEmail',
$ajaxModal,
$modalTitle,
'notify'
);
}
}
@@ -0,0 +1,113 @@
<?php
/**
* @file controllers/grid/files/FileDateGridColumn.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.
* Borrowed from FileDateGridColumn.php
*
* @class FileDateGridColumn
*
* @ingroup controllers_grid_files
*
* @brief Implements a file name column.
*/
namespace PKP\controllers\grid\files;
use APP\core\Application;
use PKP\controllers\grid\ColumnBasedGridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\core\PKPString;
class FileDateGridColumn extends GridColumn
{
/** @var ?int */
public $_stageId;
/** @var bool */
public $_includeNotes;
/**
* Constructor
*
* @param bool $includeNotes
* without the history tab.
*/
public function __construct($includeNotes = true)
{
$this->_includeNotes = $includeNotes;
$cellProvider = new ColumnBasedGridCellProvider();
parent::__construct(
'date',
'common.date',
null,
null,
$cellProvider,
['width' => 10, 'alignment' => GridColumn::COLUMN_ALIGNMENT_LEFT, 'anyhtml' => true]
);
}
//
// Public methods
//
/**
* Method expected by ColumnBasedGridCellProvider
* to render a cell in this column.
*
* @copydoc ColumnBasedGridCellProvider::getTemplateVarsFromRowColumn()
*/
public function getTemplateVarsFromRow($row)
{
$submissionFileData = $row->getData();
$submissionFile = $submissionFileData['submissionFile'];
assert($submissionFile instanceof \PKP\submissionFile\SubmissionFile);
$mtimestamp = strtotime($submissionFile->getData('updatedAt'));
$dateFormatLong = PKPString::convertStrftimeFormat(Application::get()->getRequest()->getContext()->getLocalizedDateFormatLong());
$date = date($dateFormatLong, $mtimestamp);
// File age
$age = (int)floor((date('U') - $mtimestamp) / 86400);
switch (true) {
case $age <= 7:
$cls = ' pkp_helpers_text_warn';
break;
case $age <= 28:
$cls = ' pkp_helpers_text_primary';
break;
default:
$cls = '';
break;
}
return ['label' => sprintf(
"<span class='label%s'>%s</span>",
$cls,
htmlspecialchars($date)
)];
}
//
// Private methods
//
/**
* Determine whether or not submission note status should be included.
*/
public function _getIncludeNotes()
{
return $this->_includeNotes;
}
/**
* Get stage id, if any.
*
* @return mixed int or null
*/
public function _getStageId()
{
return $this->_stageId;
}
}
@@ -0,0 +1,123 @@
<?php
/**
* @file controllers/grid/files/FileNameGridColumn.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 FileNameGridColumn
*
* @ingroup controllers_grid_files
*
* @brief Implements a file name column.
*/
namespace PKP\controllers\grid\files;
use PKP\controllers\api\file\linkAction\DownloadFileLinkAction;
use PKP\controllers\grid\ColumnBasedGridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\submissionFile\SubmissionFile;
class FileNameGridColumn extends GridColumn
{
/** @var bool */
public $_includeNotes;
/** @var int */
public $_stageId;
/** @var bool */
public $_removeHistoryTab;
/**
* Constructor
*
* @param bool $includeNotes
* @param int $stageId (optional)
* @param bool $removeHistoryTab (optional) Open the information center
* without the history tab.
*/
public function __construct($includeNotes = true, $stageId = null, $removeHistoryTab = false)
{
$this->_includeNotes = $includeNotes;
$this->_stageId = $stageId;
$this->_removeHistoryTab = $removeHistoryTab;
$cellProvider = new ColumnBasedGridCellProvider();
parent::__construct(
'name',
'common.name',
null,
null,
$cellProvider,
['width' => 70, 'alignment' => GridColumn::COLUMN_ALIGNMENT_LEFT, 'anyhtml' => true]
);
}
//
// Public methods
//
/**
* Method expected by ColumnBasedGridCellProvider
* to render a cell in this column.
*
* @copydoc ColumnBasedGridCellProvider::getTemplateVarsFromRowColumn()
*/
public function getTemplateVarsFromRow($row)
{
$submissionFileData = $row->getData();
$submissionFile = $submissionFileData['submissionFile'];
assert($submissionFile instanceof SubmissionFile);
$fileExtension = pathinfo($submissionFile->getData('path'), PATHINFO_EXTENSION);
return ['label' => '<span class="file_extension ' . $fileExtension . '">' . $submissionFile->getId() . '</span>'];
}
//
// Override methods from GridColumn
//
/**
* @copydoc GridColumn::getCellActions()
*/
public function getCellActions($request, $row, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
$cellActions = parent::getCellActions($request, $row, $position);
// Retrieve the submission file.
$submissionFileData = & $row->getData();
assert(isset($submissionFileData['submissionFile']));
$submissionFile = $submissionFileData['submissionFile']; /** @var SubmissionFile $submissionFile */
// Create the cell action to download a file.
$cellActions[] = new DownloadFileLinkAction($request, $submissionFile, $this->_getStageId());
return $cellActions;
}
//
// Private methods
//
/**
* Determine whether or not submission note status should be included.
*/
public function _getIncludeNotes()
{
return $this->_includeNotes;
}
/**
* Get stage id, if any.
*
* @return mixed int or null
*/
public function _getStageId()
{
return $this->_stageId;
}
}
@@ -0,0 +1,112 @@
<?php
/**
* @file controllers/grid/files/FilesGridDataProvider.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 FilesGridDataProvider
*
* @ingroup controllers_grid_files
*
* @brief Basic files grid data provider.
*/
namespace PKP\controllers\grid\files;
use APP\core\Application;
use PKP\controllers\grid\GridDataProvider;
class FilesGridDataProvider extends GridDataProvider
{
/** @var int */
public $_uploaderRoles;
/** @var bool */
public $_viewableOnly = false;
//
// Getters and Setters
//
/**
* Set the uploader roles.
*
* @param array $roleAssignments The grid's
* role assignment from which the uploader roles
* will be extracted.
*/
public function setUploaderRoles($roleAssignments)
{
$this->_uploaderRoles = array_keys($roleAssignments);
}
/**
* Get the uploader roles.
*
* @return array
*/
public function getUploaderRoles()
{
assert(is_array($this->_uploaderRoles) && !empty($this->_uploaderRoles));
return $this->_uploaderRoles;
}
/**
* Load only viewable files flag.
*
* @param bool $viewableOnly
*/
public function setViewableOnly($viewableOnly)
{
$this->_viewableOnly = $viewableOnly;
}
//
// Public helper methods
//
/**
* Configures and returns the action to add a file.
*
* NB: Must be overridden by subclasses (if implemented).
*
* @param Request $request
*
* @return AddFileLinkAction
*/
public function getAddFileAction($request)
{
assert(false);
}
/**
* Configures and returns the select files action.
*
* NB: Must be overridden by subclasses (if implemented).
*
* @param Request $request
*
* @return SelectFilesLinkAction
*/
public function getSelectAction($request)
{
assert(false);
}
//
// Protected helper methods
//
/**
* Get the authorized submission.
*
* @return Submission
*/
protected function getSubmission()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
}
}
@@ -0,0 +1,71 @@
<?php
/**
* @file controllers/grid/files/LibraryFileGridCategoryRow.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 LibraryFileGridCategoryRow
*
* @ingroup controllers_grid_settings_library
*
* @brief Library file grid category row definition
*/
namespace PKP\controllers\grid\files;
use APP\file\LibraryFileManager;
use PKP\context\Context;
use PKP\controllers\grid\GridCategoryRow;
class LibraryFileGridCategoryRow extends GridCategoryRow
{
/** @var Context the context for our Library file manager */
public $_context;
/**
* Constructor
*/
public function __construct($context)
{
$this->_context = & $context;
parent::__construct();
}
//
// Overridden methods from GridCategoryRow
//
/**
* Category rows only have one cell and one label. This is it.
* return string
*/
public function getCategoryLabel()
{
$context = $this->getContext();
$libraryFileManager = new LibraryFileManager($context->getId());
return __($libraryFileManager->getTitleKeyFromType($this->getData()));
}
/**
* Get the context
*
* @return object context
*/
public function getContext()
{
return $this->_context;
}
/**
* @copydoc GridCategoryRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$this->setId($this->getData());
}
}
@@ -0,0 +1,66 @@
<?php
/**
* @file controllers/grid/files/LibraryFileGridCellProvider.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 LibraryFileGridCellProvider
*
* @ingroup controllers_grid_settings_library
*
* @brief Subclass for a LibraryFile grid column's cell provider
*/
namespace PKP\controllers\grid\files;
use PKP\controllers\api\file\linkAction\DownloadLibraryFileLinkAction;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
class LibraryFileGridCellProvider 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\core\DataObject && !empty($columnId));
switch ($columnId) {
case 'files':
// handled by our link action.
return ['label' => ''];
}
}
/**
* Get cell actions associated with this row/column combination
*
* @param \PKP\controllers\grid\GridRow $row
* @param GridColumn $column
*
* @return array an array of LinkAction instances
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
switch ($column->getId()) {
case 'files':
$element = $row->getData();
assert($element instanceof \PKP\context\LibraryFile);
// Create the cell action to download a file.
return [new DownloadLibraryFileLinkAction($request, $element)];
}
return parent::getCellActions($request, $row, $column, $position);
}
}
@@ -0,0 +1,374 @@
<?php
/**
* @file controllers/grid/files/LibraryFileGridHandler.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 LibraryFileGridHandler
*
* @ingroup controllers_grid_files
*
* @brief Base class for handling library file grid requests.
*/
namespace PKP\controllers\grid\files;
use APP\file\LibraryFileManager;
use PKP\context\Context;
use PKP\controllers\grid\CategoryGridHandler;
use PKP\controllers\grid\files\form\LibraryFileForm;
use PKP\controllers\grid\GridColumn;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\file\TemporaryFileManager;
use PKP\form\Form;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\security\Role;
class LibraryFileGridHandler extends CategoryGridHandler
{
/** @var Context The context for this grid */
public $_context;
/** @var bool Whether or not the grid is editable */
public $_canEdit;
/**
* Constructor
*/
public function __construct($dataProvider)
{
parent::__construct($dataProvider);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
[
'fetchGrid', 'fetchCategory', 'fetchRow', // Parent grid-level actions
]
);
}
//
// Getters/Setters
//
/**
* Get the context
*
* @return object context
*/
public function getContext()
{
return $this->_context;
}
/**
* Can the user edit/add files in this grid?
*
* @return bool
*/
public function canEdit()
{
return $this->_canEdit;
}
/**
* Set whether or not the user can edit or add files.
*
* @param bool $canEdit
*/
public function setCanEdit($canEdit)
{
$this->_canEdit = $canEdit;
}
//
// Overridden template methods
//
/**
* Configure the grid
*
* @see CategoryGridHandler::initialize
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$router = $request->getRouter();
$this->_context = $router->getContext($request);
// Set name
$this->setTitle('manager.publication.library');
// Columns
// Basic grid row configuration
$this->addColumn($this->getFileNameColumn());
$router = $request->getRouter();
// Add grid-level actions
if ($this->canEdit()) {
$this->addAction(
new LinkAction(
'addFile',
new AjaxModal(
$router->url($request, null, null, 'addFile', null, $this->getActionArgs()),
__('grid.action.addFile'),
'modal_add_file'
),
__('grid.action.addFile'),
'add'
)
);
}
}
//
// Implement template methods from CategoryGridHandler
//
/**
* @copydoc CategoryGridHandler::getCategoryRowInstance()
*/
protected function getCategoryRowInstance()
{
return new LibraryFileGridCategoryRow($this->getContext());
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$context = $this->getContext();
$libraryFileManager = new LibraryFileManager($context->getId());
$fileTypeKeys = $libraryFileManager->getTypeSuffixMap();
foreach (array_keys($fileTypeKeys) as $key) {
$data[$key] = $key;
}
return $data;
}
//
// Overridden methods from GridHandler
//
/**
* Get the row handler - override the default row handler
*
* @return LibraryFileGridRow
*/
protected function getRowInstance()
{
return new LibraryFileGridRow($this->canEdit());
}
/**
* Get an instance of the cell provider for this grid.
*
* @return GridColumn
*/
public function getFileNameColumn()
{
return new GridColumn(
'files',
'grid.libraryFiles.column.files',
null,
null,
new LibraryFileGridCellProvider()
);
}
//
// Public File Grid Actions
//
/**
* An action to add a new file
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function addFile($args, $request)
{
$this->initialize($request);
$router = $request->getRouter();
$context = $request->getContext();
$fileForm = $this->_getNewFileForm($context);
$fileForm->initData();
return new JSONMessage(true, $fileForm->fetch($request));
}
/**
* Save a new library file.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function saveFile($args, $request)
{
$router = $request->getRouter();
$context = $request->getContext();
$fileForm = $this->_getNewFileForm($context);
$fileForm->readInputData();
if ($fileForm->validate()) {
$fileId = $fileForm->execute();
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
}
return new JSONMessage(false);
}
/**
* An action to add a new file
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editFile($args, $request)
{
$this->initialize($request);
assert(isset($args['fileId']));
$fileId = (int) $args['fileId'];
$router = $request->getRouter();
$context = $request->getContext();
$fileForm = $this->_getEditFileForm($context, $fileId);
$fileForm->initData();
return new JSONMessage(true, $fileForm->fetch($request));
}
/**
* Save changes to an existing library file.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateFile($args, $request)
{
assert(isset($args['fileId']));
$fileId = (int) $args['fileId'];
$router = $request->getRouter();
$context = $request->getContext();
$fileForm = $this->_getEditFileForm($context, $fileId);
$fileForm->readInputData();
if ($fileForm->validate()) {
$fileForm->execute();
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
}
return new JSONMessage(false);
}
/**
* Delete a file
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteFile($args, $request)
{
$fileId = $args['fileId'] ?? null;
$router = $request->getRouter();
$context = $router->getContext($request);
if ($request->checkCSRF() && $fileId) {
$libraryFileManager = new LibraryFileManager($context->getId());
$libraryFileManager->deleteById($fileId);
return \PKP\db\DAO::getDataChangedEvent();
}
return new JSONMessage(false);
}
/**
* Upload a new library file.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function uploadFile($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'));
}
}
/**
* Returns a specific instance of the new form for this grid.
* Must be implemented by subclasses.
*
* @param Context $context
*
* @return Form
*/
public function _getNewFileForm($context)
{
assert(false);
}
/**
* Returns a specific instance of the edit form for this grid.
* Must be implemented by subclasses.
*
* @param Context $context
* @param int $fileId
*
* @return LibraryFileForm
*/
public function _getEditFileForm($context, $fileId)
{
assert(false);
}
/**
* Retrieve the arguments for the 'add file' action.
*
* @return array
*/
public function getActionArgs()
{
return [];
}
}
@@ -0,0 +1,122 @@
<?php
/**
* @file controllers/grid/files/LibraryFileGridRow.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 LibraryFileGridRow
*
* @ingroup controllers_grid_files
*
* @brief Handle library file grid row requests.
*/
namespace PKP\controllers\grid\files;
use APP\submission\Submission;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class LibraryFileGridRow extends GridRow
{
/** @var int LIBRARY_FILE_TYPE_... */
public $_fileType;
/** @var bool is the grid row read only */
public $_canEdit;
/** @var Submission the submission associated with submission library files */
public $_submission;
/**
* Constructor
*
* @param null|mixed $submission
*/
public function __construct($canEdit = false, $submission = null)
{
$this->_canEdit = $canEdit;
$this->_submission = $submission;
parent::__construct();
}
//
// Getters / setters
//
/**
* Get the file type for this row
*
* @return string
*/
public function getFileType()
{
return $this->_fileType;
}
public function setFileType($fileType)
{
$this->_fileType = $fileType;
}
//
// Overridden template methods
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$this->setFileType($request->getUserVar('fileType'));
// Is this a new row or an existing row?
$fileId = $this->getId();
if (!empty($fileId) && $this->_canEdit) {
// Actions
$router = $request->getRouter();
$actionArgs = [
'fileId' => $fileId,
];
if ($this->_submission) {
$actionArgs['submissionId'] = $this->_submission->getId();
}
$this->addAction(
new LinkAction(
'editFile',
new AjaxModal(
$router->url($request, null, null, 'editFile', null, $actionArgs),
__('grid.action.edit'),
'modal_edit'
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'deleteFile',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.delete'),
$router->url($request, null, null, 'deleteFile', null, $actionArgs),
'modal_delete'
),
__('grid.action.delete'),
'delete'
)
);
}
}
}
@@ -0,0 +1,57 @@
<?php
/**
* @file controllers/grid/files/SelectableLibraryFileGridHandler.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 SelectableLibraryFileGridHandler
*
* @ingroup controllers_grid_files
*
* @brief Handle selectable library file list category grid requests.
*/
namespace PKP\controllers\grid\files;
use PKP\controllers\grid\feature\selectableItems\SelectableItemsFeature;
use PKP\controllers\grid\settings\library\LibraryFileAdminGridDataProvider;
class SelectableLibraryFileGridHandler extends LibraryFileGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(new LibraryFileAdminGridDataProvider(true));
}
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new SelectableItemsFeature()];
}
/**
* @copydoc GridHandler::isDataElementInCategorySelected()
*/
public function isDataElementInCategorySelected($categoryDataId, &$gridDataElement)
{
return false;
}
/**
* Get the selection name.
*
* @return string
*/
public function getSelectName()
{
return 'selectedLibraryFiles';
}
}
@@ -0,0 +1,296 @@
<?php
/**
* @file controllers/grid/files/SelectableSubmissionFileListCategoryGridHandler.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 SelectableSubmissionFileListCategoryGridHandler
*
* @ingroup controllers_grid_files
*
* @brief Handle selectable submission file list category grid requests.
*/
namespace PKP\controllers\grid\files;
use APP\core\Application;
use APP\core\Request;
use APP\submission\Submission;
use PKP\controllers\grid\CategoryGridHandler;
use PKP\controllers\grid\feature\selectableItems\SelectableItemsFeature;
use PKP\controllers\grid\files\fileList\FileGenreGridColumn;
use PKP\controllers\grid\GridDataProvider;
use PKP\controllers\grid\GridHandler;
class SelectableSubmissionFileListCategoryGridHandler extends CategoryGridHandler
{
/** @var FilesGridCapabilities */
public $_capabilities;
/** @var ?int */
public $_stageId;
/**
* Constructor
*
* @param GridDataProvider $dataProvider
* @param ?int $stageId One of the WORKFLOW_STAGE_ID_* constants.
* @param int $capabilities A bit map with zero or more
* FILE_GRID_* capabilities set.
*/
public function __construct($dataProvider, $stageId, $capabilities = 0)
{
// the StageId can be set later if necessary.
if ($stageId) {
$this->_stageId = (int)$stageId;
}
$this->_capabilities = new FilesGridCapabilities($capabilities);
parent::__construct($dataProvider);
}
//
// Getters and Setters
//
/**
* Get grid capabilities object.
*
* @return FilesGridCapabilities
*/
public function getCapabilities()
{
return $this->_capabilities;
}
/**
* Get the workflow stage id.
*
* @return int
*/
public function getStageId()
{
return $this->_stageId;
}
/**
* Get the authorized submission.
*
* @return Submission
*/
public function getSubmission()
{
// We assume proper authentication by the data provider.
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
assert($submission instanceof Submission);
return $submission;
}
//
// Overridden methods from GridHandler
//
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
// Let parent class get data from data provider.
$workflowStages = parent::loadData($request, $filter);
// Filter the data.
if ($filter['allStages']) {
return array_combine($workflowStages, $workflowStages);
} else {
return [$this->getStageId() => $this->getStageId()];
}
}
/**
* @copydoc GridHandler::getFilterForm()
*/
protected function getFilterForm()
{
return 'controllers/grid/files/selectableSubmissionFileListCategoryGridFilter.tpl';
}
/**
* @copydoc GridHandler::isFilterFormCollapsible()
*/
protected function isFilterFormCollapsible()
{
return false;
}
/**
* @copydoc GridHandler::getFilterSelectionData()
*/
public function getFilterSelectionData($request)
{
return ['allStages' => $request->getUserVar('allStages') ? true : false];
}
//
// Overridden methods from CategoryGridHandler
//
/**
* @copydoc CategoryGridHandler::getCategoryRowInstance()
*/
protected function getCategoryRowInstance()
{
return new SelectableSubmissionFileListCategoryGridRow();
}
//
// Implement template methods from PKPHandler
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
// Set the stage id from the request parameter if not set previously.
if (!$this->getStageId()) {
$stageId = (int) $request->getUserVar('stageId');
// This will be validated with the authorization policy added by
// the grid data provider.
$this->_stageId = $stageId;
}
$dataProvider = $this->getDataProvider();
$dataProvider->setStageId($this->getStageId());
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc CategoryGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Add grid actions
$capabilities = $this->getCapabilities();
$dataProvider = $this->getDataProvider();
if ($capabilities->canManage()) {
$this->addAction($dataProvider->getSelectAction($request));
}
if ($capabilities->canAdd()) {
assert(isset($dataProvider));
$this->addAction($dataProvider->getAddFileAction($request));
}
// Test whether an archive tool is available for the export to work, if so, add 'download all' grid action
if ($capabilities->canDownloadAll() && $this->hasGridDataElements($request)) {
$submission = $this->getSubmission();
$stageId = $this->getStageId();
$linkParams = [
'nameLocaleKey' => $this->getTitle(),
'submissionId' => $submission->getId(),
'stageId' => $stageId,
];
$files = $this->getFilesToDownload($request);
$this->addAction($capabilities->getDownloadAllAction($request, $files, $linkParams), GridHandler::GRID_ACTION_POSITION_BELOW);
}
// The file name column is common to all file grid types.
$this->addColumn(new FileNameGridColumn($capabilities->canViewNotes(), $this->getStageId()));
// The file list grid layout has an additional file genre column.
$this->addColumn(new FileGenreGridColumn());
// Set the no items row text
$this->setEmptyRowText('grid.noFiles');
}
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new SelectableItemsFeature()];
}
//
// Overridden methods from GridHandler
//
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new SubmissionFilesGridRow($this->getCapabilities(), $this->getStageId());
}
//
// Protected methods
//
/**
* Get all files of this grid to download.
*
* @param Request $request
*
* @return array
*/
public function getFilesToDownload($request)
{
$dataProvider = $this->getDataProvider();
$workflowStages = $this->getGridDataElements($request);
// Get the submission files to be downloaded.
$submissionFiles = [];
foreach ($workflowStages as $stageId) {
$submissionFiles = array_merge(
$submissionFiles,
$this->getGridCategoryDataElements($request, $stageId)
);
}
return $submissionFiles;
}
/**
* @copydoc GridHandler::isDataElementInCategorySelected()
*/
public function isDataElementInCategorySelected($categoryDataId, &$gridDataElement)
{
$currentStageId = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_WORKFLOW_STAGE);
$submissionFile = $gridDataElement['submissionFile'];
// Check for special cases when the file needs to be unselected.
$dataProvider = $this->getDataProvider();
if ($dataProvider->getFileStage() != $submissionFile->getFileStage()) {
return false;
} elseif ($currentStageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW || $currentStageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
if ($currentStageId != $categoryDataId) {
return false;
}
}
// Passed the checks above. If viewable then select it.
return $submissionFile->getViewable();
}
/**
* Get the selection name.
*
* @return string
*/
public function getSelectName()
{
return 'selectedFiles';
}
}
@@ -0,0 +1,36 @@
<?php
/**
* @file controllers/grid/files/SelectableSubmissionFileListCategoryGridRow.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 SelectableSubmissionFileListCategoryGridRow
*
* @ingroup controllers_grid_files
*
* @brief Selectable submission file list category grid row definition.
*/
namespace PKP\controllers\grid\files;
use PKP\controllers\grid\GridCategoryRow;
use PKP\workflow\WorkflowStageDAO;
class SelectableSubmissionFileListCategoryGridRow extends GridCategoryRow
{
//
// Overridden methods from GridCategoryRow
//
/**
* @copydoc GridCategoryRow::getCategoryLabel()
*/
public function getCategoryLabel()
{
$stageId = $this->getData();
$stageTranslationKey = WorkflowStageDAO::getTranslationKeyFromId($stageId);
return __($stageTranslationKey);
}
}
@@ -0,0 +1,246 @@
<?php
/**
* @file controllers/grid/files/SubmissionFilesCategoryGridDataProvider.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 SubmissionFilesCategoryGridDataProvider
*
* @ingroup controllers_grid_files_review
*
* @brief Provide access to submission files data for category grids.
*/
namespace PKP\controllers\grid\files;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\grid\CategoryGridDataProvider;
use PKP\db\DAORegistry;
use PKP\note\NoteDAO;
use PKP\query\QueryDAO;
use PKP\submission\reviewRound\ReviewRoundDAO;
use PKP\submissionFile\SubmissionFile;
class SubmissionFilesCategoryGridDataProvider extends CategoryGridDataProvider
{
/** @var array */
public $_submissionFiles;
/**
* Constructor
*
* @param int $fileStage The current file stage that the grid is handling
* (others file stages could be shown activating the grid filter, but this
* is the file stage that will be used to bring files from other stages, upload
* new file, etc).
* @param array $dataProviderInitParams Other parameters to initiate the grid
* data provider that this category grid data provider will use to implement
* common behaviours and data.
*/
public function __construct($fileStage, $dataProviderInitParams = null)
{
parent::__construct();
$this->setDataProvider($this->initGridDataProvider($fileStage, $dataProviderInitParams));
}
//
// Extended method from CategoryGridDataProvider.
//
/**
* @copydoc CategoryGridDataProvider::setDataProvider()
*/
public function setDataProvider($gridDataProvider)
{
assert($gridDataProvider instanceof SubmissionFilesGridDataProvider);
parent::setDataProvider($gridDataProvider);
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
// Get the submission files grid data provider authorization policy.
$dataProvider = $this->getDataProvider();
return $dataProvider->getAuthorizationPolicy($request, $args, $roleAssignments);
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$dataProvider = $this->getDataProvider();
return $dataProvider->getRequestArgs();
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
// Return only the user accessible workflow stages.
return array_keys($this->getAuthorizedContextObject(Application::ASSOC_TYPE_ACCESSIBLE_WORKFLOW_STAGES));
}
//
// Implement template methods from CategoryGridDataProvider
//
/**
* @copydoc CategoryGridDataProvider::loadCategoryData()
*
* @param null|mixed $filter
* @param null|mixed $reviewRound
*/
public function loadCategoryData($request, $categoryDataElement, $filter = null, $reviewRound = null)
{
/** @var SubmissionFilesGridDataProvider */
$dataProvider = $this->getDataProvider();
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
$stageId = $categoryDataElement;
$fileStages = $this->_getFileStagesByStageId($stageId);
$stageSubmissionFiles = null;
// For review stages, get the revisions of the review round that user is currently accessing.
if ($stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW || $stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
if (is_null($reviewRound) || $reviewRound->getStageId() != $stageId) {
$reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /** @var ReviewRoundDAO $reviewRoundDao */
$reviewRound = $reviewRoundDao->getLastReviewRoundBySubmissionId($submission->getId(), $stageId);
}
if ($reviewRound) {
$stageSubmissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$submission->getId()])
->filterByReviewRoundIds([$reviewRound->getId()])
->filterByFileStages($fileStages)
->getMany()
->toArray();
} else {
$stageSubmissionFiles = [];
}
} else {
// Filter the passed workflow stage files.
if (!$this->_submissionFiles) {
$this->_submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$submission->getId()])
->getMany()
->toArray();
}
$submissionFiles = $this->_submissionFiles;
$stageSubmissionFiles = [];
foreach ($submissionFiles as $key => $submissionFile) {
if (in_array($submissionFile->getData('fileStage'), $fileStages)) {
$stageSubmissionFiles[$key] = $submissionFile;
} elseif ($submissionFile->getData('fileStage') == SubmissionFile::SUBMISSION_FILE_QUERY) {
// Determine the stage from the query.
if ($submissionFile->getData('assocType') != Application::ASSOC_TYPE_NOTE) {
break;
}
$noteDao = DAORegistry::getDAO('NoteDAO'); /** @var NoteDAO $noteDao */
$note = $noteDao->getById($submissionFile->getData('assocId'));
$queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */
if ($note && $note->getAssocType() == Application::ASSOC_TYPE_QUERY) {
$query = $queryDao->getById($note->getAssocId());
}
if ($query && $query->getStageId() == $stageId) {
$stageSubmissionFiles[$key] = $submissionFile;
}
}
}
}
return $dataProvider->prepareSubmissionFileData($stageSubmissionFiles, false, $filter);
}
//
// Public methods
//
/**
* @copydoc SubmissionFilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
/** @var SubmissionFilesGridDataProvider */
$dataProvider = $this->getDataProvider();
return $dataProvider->getAddFileAction($request);
}
/**
* @copydoc SubmissionFilesGridDataProvider::getFileStage()
*/
public function setStageId($stageId)
{
/** @var SubmissionFilesGridDataProvider */
$dataProvider = $this->getDataProvider();
$dataProvider->setStageId($stageId);
}
/**
* @copydoc SubmissionFilesGridDataProvider::getFileStage()
*/
public function getFileStage()
{
/** @var SubmissionFilesGridDataProvider */
$dataProvider = $this->getDataProvider();
return $dataProvider->getFileStage();
}
//
// Protected methods.
//
/**
* Init the grid data provider that this category grid data provider
* will use and return it. Override this to initiate another grid data provider.
*
* @param int $fileStage
* @param array $initParams (optional) The parameters to initiate the grid data provider.
*
* @return SubmissionFilesGridDataProvider
*/
public function initGridDataProvider($fileStage, $initParams = null)
{
// By default, this category grid data provider use the
// SubmissionFilesGridDataProvider.
return new SubmissionFilesGridDataProvider($fileStage);
}
//
// Private helper methods.
//
/**
* Get the file stage using the passed stage id. This will define
* which file stage will be present on each workflow stage category
* of the grid.
*/
public function _getFileStagesByStageId(int $stageId): array
{
switch ($stageId) {
case WORKFLOW_STAGE_ID_SUBMISSION:
return [SubmissionFile::SUBMISSION_FILE_SUBMISSION];
case WORKFLOW_STAGE_ID_INTERNAL_REVIEW:
return [SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE, SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION];
case WORKFLOW_STAGE_ID_EXTERNAL_REVIEW:
return [SubmissionFile::SUBMISSION_FILE_REVIEW_FILE, SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION];
case WORKFLOW_STAGE_ID_EDITING:
return [SubmissionFile::SUBMISSION_FILE_FINAL, SubmissionFile::SUBMISSION_FILE_COPYEDIT];
case WORKFLOW_STAGE_ID_PRODUCTION:
return [SubmissionFile::SUBMISSION_FILE_PRODUCTION_READY];
default:
return [];
}
}
}
@@ -0,0 +1,199 @@
<?php
/**
* @file controllers/grid/files/SubmissionFilesGridDataProvider.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 SubmissionFilesGridDataProvider
*
* @ingroup controllers_grid_files
*
* @brief Provide access to submission file data for grids.
*/
namespace PKP\controllers\grid\files;
use APP\facades\Repo;
use PKP\controllers\api\file\linkAction\AddFileLinkAction;
use PKP\facades\Locale;
use PKP\security\authorization\WorkflowStageAccessPolicy;
class SubmissionFilesGridDataProvider extends FilesGridDataProvider
{
/** @var int */
public $_stageId;
/** @var int */
public $_fileStage;
/**
* Constructor
*
* @param int $fileStage One of the SubmissionFile::SUBMISSION_FILE_* constants.
* @param bool $viewableOnly True iff only viewable files should be included.
*/
public function __construct($fileStage, $viewableOnly = false)
{
assert(is_numeric($fileStage) && $fileStage > 0);
$this->_fileStage = (int)$fileStage;
parent::__construct();
$this->setViewableOnly($viewableOnly);
}
//
// Getters and setters.
//
/**
* Set the workflow stage.
*
* @param int $stageId WORKFLOW_STAGE_ID_...
*/
public function setStageId($stageId)
{
$this->_stageId = $stageId;
}
/**
* Get the workflow stage.
*
* @return int WORKFLOW_STAGE_ID_...
*/
public function getStageId()
{
return $this->_stageId;
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$submission = $this->getSubmission();
return [
'submissionId' => $submission->getId(),
'stageId' => $this->getStageId(),
'fileStage' => $this->getFileStage(),
];
}
/**
* Get the file stage.
*
* @return int SubmissionFile::SUBMISSION_FILE_...
*/
public function getFileStage()
{
return $this->_fileStage;
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$this->getSubmission()->getId()])
->filterByFileStages([$this->getFileStage()])
->getMany()
->toArray();
return $this->prepareSubmissionFileData($submissionFiles, $this->_viewableOnly, $filter);
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
$this->setUploaderRoles($roleAssignments);
return new WorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $this->getStageId());
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$submission = $this->getSubmission();
return new AddFileLinkAction(
$request,
$submission->getId(),
$this->getStageId(),
$this->getUploaderRoles(),
$this->getFileStage()
);
}
//
// Protected functions
//
/**
* Apply the filter to the list of revisions, returning only matching elements.
*
* @param array $revisions List of potential submission files to include.
* @param array $filter Associative array of filter data
*
* @return array
*/
protected function applyFilter($revisions, $filter)
{
if (!empty($filter['search'])) {
switch ($filter['column']) {
case 'name':
foreach ($revisions as $key => $submissionFile) {
if (!stristr($submissionFile->getData('name', Locale::getLocale()), $filter['search'])) {
unset($revisions[$key]);
}
}
break;
}
}
return $revisions;
}
/**
* Rearrange file revisions by file id and return the file
* data wrapped into an array so that grid implementations
* can add further data.
*
* @param array $revisions List of SubmissionFiles
* @param bool $viewableOnly optional True iff only viewable files should be listed
* @param array $filter optional Associative array of filter conditions
*
* @return array
*/
public function prepareSubmissionFileData($revisions, $viewableOnly = false, $filter = [])
{
$revisions = $this->applyFilter($revisions, $filter);
// Rearrange the files as required by submission file grids.
$submissionFileData = [];
foreach ($revisions as $revision) {
if ($viewableOnly && !$revision->getViewable()) {
continue;
}
$submissionFileData[$revision->getId()] = [
'submissionFile' => $revision
];
}
return $submissionFileData;
}
}
@@ -0,0 +1,229 @@
<?php
/**
* @file controllers/grid/files/SubmissionFilesGridHandler.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 SubmissionFilesGridHandler
*
* @ingroup controllers_grid_files
*
* @brief Handle submission file grid requests.
*/
namespace PKP\controllers\grid\files;
use APP\core\Application;
use APP\submission\Submission;
use PKP\controllers\grid\GridDataProvider;
use PKP\controllers\grid\GridHandler;
class SubmissionFilesGridHandler extends GridHandler
{
/** @var FilesGridCapabilities */
public $_capabilities;
/** @var ?int */
public $_stageId;
/**
* Constructor
*
* @param GridDataProvider $dataProvider
* @param ?int $stageId One of the WORKFLOW_STAGE_ID_* constants.
* @param int $capabilities A bit map with zero or more
* FILE_GRID_* capabilities set.
*/
public function __construct($dataProvider, $stageId, $capabilities = 0)
{
parent::__construct($dataProvider);
if ($stageId) {
$this->_stageId = (int)$stageId;
}
$this->_capabilities = new FilesGridCapabilities($capabilities);
}
//
// Getters and Setters
//
/**
* Get grid capabilities object.
*
* @return FilesGridCapabilities
*/
public function getCapabilities()
{
return $this->_capabilities;
}
/**
* Set grid capabilities object.
*
* @param FilesGridCapabilities $capabilities
*/
public function setCapabilities($capabilities)
{
$this->_capabilities = $capabilities;
}
/**
* Get the workflow stage id.
*
* @return int
*/
public function getStageId()
{
return $this->_stageId;
}
/**
* Get the authorized submission.
*
* @return Submission
*/
public function getSubmission()
{
// We assume proper authentication by the data provider.
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
assert($submission instanceof Submission);
return $submission;
}
//
// Implement template methods from PKPHandler
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
// Set the stage id from the request parameter if not set previously.
if (!$this->getStageId()) {
$stageId = (int) $request->getUserVar('stageId');
// This will be validated with the authorization policy added by
// the grid data provider.
$this->_stageId = $stageId;
}
$dataProvider = $this->getDataProvider();
$dataProvider->setStageId($this->getStageId());
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Add grid actions
$capabilities = $this->getCapabilities();
$dataProvider = $this->getDataProvider();
$submission = $this->getSubmission();
if ($capabilities->canAdd()) {
assert(isset($dataProvider));
$this->addAction($dataProvider->getAddFileAction($request));
}
// Test whether an archive tool is available for the export to work, if so, add 'download all' grid action
if ($capabilities->canDownloadAll() && $this->hasGridDataElements($request)) {
$stageId = $this->getStageId();
$linkParams = [
'nameLocaleKey' => $this->getTitle(),
'fileStage' => $this->getDataProvider()->getFileStage(),
'submissionId' => $submission->getId(),
'stageId' => $stageId,
];
$files = $this->getFilesToDownload($request);
$this->addAction($capabilities->getDownloadAllAction($request, $files, $linkParams), GridHandler::GRID_ACTION_POSITION_BELOW);
}
// The file name column is common to all file grid types.
$this->addColumn(new FileNameGridColumn($capabilities->canViewNotes(), $this->getStageId()));
// Additional column with file upload date/creation date
$this->addColumn(new FileDateGridColumn($capabilities->canViewNotes()));
// Set the no items row text
$this->setEmptyRowText('grid.noFiles');
}
/**
* @copyDoc GridHandler::getFilterForm()
*/
protected function getFilterForm()
{
return 'controllers/grid/files/filesGridFilter.tpl';
}
/**
* @copyDoc GridHandler::renderFilter()
*/
public function renderFilter($request, $filterData = [])
{
return parent::renderFilter(
$request,
[
'columns' => $this->getFilterColumns(),
'gridId' => $this->getId()
]
);
}
/**
* @copyDoc GridHandler::getFilterSelectionData()
*/
public function getFilterSelectionData($request)
{
return [
'search' => (string) $request->getUserVar('search'),
'column' => (string) $request->getUserVar('column'),
];
}
/**
* Get which columns can be used by users to filter data.
*
* @return array
*/
protected function getFilterColumns()
{
return [
'name' => __('common.name'),
];
}
//
// Overridden methods from GridHandler
//
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new SubmissionFilesGridRow($this->getCapabilities(), $this->getStageId());
}
//
// Protected methods.
//
public function getFilesToDownload($request)
{
return $this->getGridDataElements($request);
}
}
@@ -0,0 +1,122 @@
<?php
/**
* @file controllers/grid/files/SubmissionFilesGridRow.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 SubmissionFilesGridRow
*
* @ingroup controllers_grid_files
*
* @brief Handle submission file grid row requests.
*/
namespace PKP\controllers\grid\files;
use PKP\controllers\api\file\linkAction\DeleteFileLinkAction;
use PKP\controllers\api\file\linkAction\EditFileLinkAction;
use PKP\controllers\grid\GridRow;
use PKP\controllers\informationCenter\linkAction\FileInfoCenterLinkAction;
use PKP\submissionFile\SubmissionFile;
class SubmissionFilesGridRow extends GridRow
{
/** @var FilesGridCapabilities */
public $_capabilities;
/** @var int */
public $_stageId;
/**
* Constructor
*
* @param FilesGridCapabilities $capabilities
* @param int $stageId Stage ID (optional)
*/
public function __construct($capabilities = null, $stageId = null)
{
$this->_capabilities = $capabilities;
$this->_stageId = $stageId;
parent::__construct();
}
//
// Getters and Setters
//
/**
* Can the user delete files from this grid?
*
* @return bool
*/
public function canDelete()
{
return $this->_capabilities->canDelete();
}
/**
* Can the user view file notes on this grid?
*
* @return bool
*/
public function canViewNotes()
{
return $this->_capabilities->canViewNotes();
}
/**
* Can the user manage files in this grid?
*
* @return bool
*/
public function canEdit()
{
return $this->_capabilities->canEdit();
}
/**
* Get the stage id, if any.
*
* @return int Stage ID
*/
public function getStageId()
{
return $this->_stageId;
}
//
// Overridden template methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*/
public function initialize($request, $template = 'controllers/grid/gridRow.tpl')
{
parent::initialize($request, $template);
// Retrieve the submission file.
$submissionFileData = & $this->getData();
assert(isset($submissionFileData['submissionFile']));
$submissionFile = & $submissionFileData['submissionFile']; /** @var SubmissionFile $submissionFile */
assert(is_a($submissionFile, 'SubmissionFile'));
// File grid row actions:
// 1) Information center action.
if ($this->canViewNotes()) {
$this->addAction(new FileInfoCenterLinkAction($request, $submissionFile, $this->getStageId()));
}
// 2) Edit metadata action.
if ($this->canEdit()) {
$this->addAction(new EditFileLinkAction($request, $submissionFile, $this->getStageId()));
}
// 3) Delete file action.
if ($this->canDelete()) {
$this->addAction(new DeleteFileLinkAction($request, $submissionFile, $this->getStageId()));
}
}
}
@@ -0,0 +1,41 @@
<?php
/**
* @file controllers/grid/files/attachment/AuthorOpenReviewAttachmentsGridHandler.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 AuthorOpenReviewAttachmentsGridHandler
*
* @ingroup controllers_grid_files_attachment
*
* @brief Handle review attachment grid requests in open reviews (author's perspective)
*/
namespace PKP\controllers\grid\files\attachment;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\security\Role;
class AuthorOpenReviewAttachmentsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// Pass in null stageId to be set in initialize from request var.
// Show also files that are not viewable by default
parent::__construct(
new ReviewerReviewAttachmentGridDataProvider(),
null
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
}
}
@@ -0,0 +1,45 @@
<?php
/**
* @file controllers/grid/files/attachment/AuthorReviewAttachmentsGridHandler.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 AuthorReviewAttachmentsGridHandler
*
* @ingroup controllers_grid_files_attachment
*
* @brief Handle review attachment grid requests (author's perspective)
*/
namespace PKP\controllers\grid\files\attachment;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\review\ReviewGridDataProvider;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class AuthorReviewAttachmentsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewGridDataProvider(SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT, true),
null
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
// Set the grid title.
$this->setTitle('grid.reviewAttachments.title');
}
}
@@ -0,0 +1,45 @@
<?php
/**
* @file controllers/grid/files/attachment/EditorReviewAttachmentsGridHandler.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 EditorReviewAttachmentsGridHandler
*
* @ingroup controllers_grid_files_attachment
*
* @brief Editor's view of the Review Attachments Grid.
*/
namespace PKP\controllers\grid\files\attachment;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class EditorReviewAttachmentsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewerReviewAttachmentGridDataProvider(),
null,
FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
[
'fetchGrid', 'fetchRow'
]
);
}
}
@@ -0,0 +1,142 @@
<?php
/**
* @file controllers/grid/files/attachment/ReviewerReviewAttachmentGridDataProvider.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 ReviewerReviewAttachmentGridDataProvider
*
* @ingroup controllers_grid_files_attachment
*
* @brief Provide the reviewers access to their own review attachments data for grids.
*/
namespace PKP\controllers\grid\files\attachment;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\api\file\linkAction\AddFileLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\db\DAORegistry;
use PKP\security\authorization\internal\ReviewAssignmentRequiredPolicy;
use PKP\security\authorization\ReviewStageAccessPolicy;
use PKP\submission\reviewAssignment\ReviewAssignmentDAO;
use PKP\submissionFile\SubmissionFile;
class ReviewerReviewAttachmentGridDataProvider extends SubmissionFilesGridDataProvider
{
/** @var int */
public $_reviewId;
/**
* Constructor
*/
public function __construct()
{
parent::__construct(SubmissionFile::SUBMISSION_FILE_REVIEW_ATTACHMENT);
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
// Need to use the reviewId because this grid can either be
// viewed by the reviewer (in which case, we could do a
// $request->getUser()->getId() or by the editor when reading
// the review. The following covers both cases...
$assocType = (int) $request->getUserVar('assocType');
$assocId = (int) $request->getUserVar('assocId');
if ($assocType && $assocId) {
// Viewing from a Reviewer perspective.
assert($assocType == Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
$this->setUploaderRoles($roleAssignments);
$authorizationPolicy = new ReviewStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $request->getUserVar('stageId'));
$paramName = 'assocId';
} else {
// Viewing from a context role perspective.
$authorizationPolicy = parent::getAuthorizationPolicy($request, $args, $roleAssignments);
$paramName = 'reviewId';
}
$authorizationPolicy->addPolicy(new ReviewAssignmentRequiredPolicy($request, $args, $paramName));
return $authorizationPolicy;
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
return array_merge(
parent::getRequestArgs(),
[
'assocType' => Application::ASSOC_TYPE_REVIEW_ASSIGNMENT,
'assocId' => $this->_getReviewId()
]
);
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterByAssoc(
Application::ASSOC_TYPE_REVIEW_ASSIGNMENT,
[$this->_getReviewId()]
)->filterBySubmissionIds([$this->getSubmission()->getId()])
->getMany()
->toArray();
return $this->prepareSubmissionFileData($submissionFiles, false, $filter);
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$submission = $this->getSubmission();
$reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /** @var ReviewAssignmentDAO $reviewAssignmentDao */
$reviewAssignment = $reviewAssignmentDao->getById($this->_getReviewId());
return new AddFileLinkAction(
$request,
$submission->getId(),
$this->getStageId(),
$this->getUploaderRoles(),
$this->getFileStage(),
Application::ASSOC_TYPE_REVIEW_ASSIGNMENT,
$this->_getReviewId(),
$reviewAssignment->getReviewRoundId()
);
}
//
// Private helper methods
//
/**
* Get the review id.
*
* @return int
*/
public function _getReviewId()
{
$reviewAssignment = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
return $reviewAssignment->getId();
}
}
@@ -0,0 +1,65 @@
<?php
/**
* @file controllers/grid/files/attachment/ReviewerReviewAttachmentsGridHandler.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 ReviewerReviewAttachmentsGridHandler
*
* @ingroup controllers_grid_files_attachment
*
* @brief Handle file grid requests.
*/
namespace PKP\controllers\grid\files\attachment;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ReviewerReviewAttachmentsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewerReviewAttachmentGridDataProvider(),
null,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_REVIEWER],
[
'fetchGrid', 'fetchRow'
]
);
// Set the grid title.
$this->setTitle('reviewer.submission.reviewerFiles');
}
/**
* @copydoc FileListGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
// Watch for flag from including template to warn about the
// review already being complete. If so, remove some capabilities.
$capabilities = $this->getCapabilities();
if ($request->getUserVar('reviewIsClosed')) {
$capabilities->setCanAdd(false);
$capabilities->setCanDelete(false);
}
parent::initialize($request, $args);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* @file controllers/grid/files/copyedit/CopyeditFilesGridDataProvider.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 CopyeditFilesGridDataProvider
*
* @ingroup controllers_grid_files_copyedit
*
* @brief Provide access to copyedited files management.
*/
namespace PKP\controllers\grid\files\copyedit;
use PKP\controllers\grid\files\fileList\linkAction\SelectFilesLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\submissionFile\SubmissionFile;
class CopyeditFilesGridDataProvider extends SubmissionFilesGridDataProvider
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(SubmissionFile::SUBMISSION_FILE_COPYEDIT);
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getSelectAction()
*/
public function getSelectAction($request)
{
return new SelectFilesLinkAction(
$request,
[
'submissionId' => $this->getSubmission()->getId(),
'stageId' => $this->getStageId()
],
__('editor.submission.uploadSelectFiles')
);
}
}
@@ -0,0 +1,101 @@
<?php
/**
* @file controllers/grid/files/copyedit/CopyeditFilesGridHandler.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 CopyeditFilesGridHandler
*
* @ingroup controllers_grid_files_copyedit
*
* @brief Handle the copyedited files grid
*/
namespace PKP\controllers\grid\files\copyedit;
use APP\core\Application;
use PKP\controllers\grid\files\copyedit\form\ManageCopyeditFilesForm;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\Role;
class CopyeditFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
* FILE_GRID_* capabilities set.
*/
public function __construct()
{
parent::__construct(
new CopyeditFilesGridDataProvider(),
null
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT,
Role::ROLE_ID_AUTHOR,
],
[
'fetchGrid', 'fetchRow',
]
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'selectFiles'
]
);
$this->setTitle('submission.copyedited');
}
//
// Public handler methods
//
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
if (0 != count(array_intersect(
$this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES),
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_SUB_EDITOR]
// Authors may also view this grid, and shouldn't be able to do anything (just view).
))) {
$this->setCapabilities(new FilesGridCapabilities(FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_MANAGE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_DELETE));
}
parent::initialize($request, $args);
}
/**
* Show the form to allow the user to select files from previous stages
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function selectFiles($args, $request)
{
$manageCopyeditFilesForm = new ManageCopyeditFilesForm($this->getSubmission()->getId());
$manageCopyeditFilesForm->initData();
return new JSONMessage(true, $manageCopyeditFilesForm->fetch($request));
}
}
@@ -0,0 +1,109 @@
<?php
/**
* @file controllers/grid/files/copyedit/ManageCopyeditFilesGridHandler.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 ManageCopyeditFilesGridHandler
*
* @ingroup controllers_grid_files_copyedit
*
* @brief Handle the copyedited file selection grid
*/
namespace PKP\controllers\grid\files\copyedit;
use APP\core\Application;
use APP\notification\NotificationManager;
use PKP\controllers\grid\files\copyedit\form\ManageCopyeditFilesForm;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\SelectableSubmissionFileListCategoryGridHandler;
use PKP\controllers\grid\files\SubmissionFilesCategoryGridDataProvider;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\notification\PKPNotification;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ManageCopyeditFilesGridHandler extends SelectableSubmissionFileListCategoryGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(
new SubmissionFilesCategoryGridDataProvider(SubmissionFile::SUBMISSION_FILE_COPYEDIT),
WORKFLOW_STAGE_ID_EDITING,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'fetchGrid', 'fetchCategory', 'fetchRow',
'addFile',
'downloadFile',
'deleteFile',
'updateCopyeditFiles'
]
);
// Set the grid title.
$this->setTitle('submission.copyedited');
}
//
// Public handler methods
//
/**
* Save 'manage copyedited files' form
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateCopyeditFiles($args, $request)
{
$submission = $this->getSubmission();
$manageCopyeditFilesForm = new ManageCopyeditFilesForm($submission->getId());
$manageCopyeditFilesForm->readInputData();
if ($manageCopyeditFilesForm->validate()) {
$manageCopyeditFilesForm->execute(
$this->getGridCategoryDataElements($request, $this->getStageId())
);
if ($submission->getStageId() == WORKFLOW_STAGE_ID_EDITING ||
$submission->getStageId() == WORKFLOW_STAGE_ID_PRODUCTION) {
$notificationMgr = new NotificationManager();
$notificationMgr->updateNotification(
$request,
[
PKPNotification::NOTIFICATION_TYPE_ASSIGN_COPYEDITOR,
PKPNotification::NOTIFICATION_TYPE_AWAITING_COPYEDITS,
],
null,
Application::ASSOC_TYPE_SUBMISSION,
$submission->getId()
);
}
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
}
@@ -0,0 +1,44 @@
<?php
/**
* @file controllers/grid/files/copyedit/form/ManageCopyeditFilesForm.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 ManageCopyeditFilesForm
*
* @ingroup controllers_grid_files_copyedit
*
* @brief Form to add files to the copyedited files grid
*/
namespace PKP\controllers\grid\files\copyedit\form;
use PKP\controllers\grid\files\form\ManageSubmissionFilesForm;
use PKP\submissionFile\SubmissionFile;
class ManageCopyeditFilesForm extends ManageSubmissionFilesForm
{
/**
* Constructor.
*
* @param int $submissionId Submission ID.
*/
public function __construct($submissionId)
{
parent::__construct($submissionId, 'controllers/grid/files/copyedit/manageCopyeditFiles.tpl');
}
/**
* Save selection of copyedited files
*
* @param array $stageSubmissionFiles List of submission files in this stage.
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
*/
public function execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs)
{
parent::execute($stageSubmissionFiles, SubmissionFile::SUBMISSION_FILE_COPYEDIT);
}
}
@@ -0,0 +1,106 @@
<?php
/**
* @file controllers/grid/files/dependent/DependentFilesGridDataProvider.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 DependentFilesGridDataProvider
*
* @ingroup controllers_grid_files_dependent
*
* @brief Provide access to dependent file data for grids.
*/
namespace PKP\controllers\grid\files\dependent;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\api\file\linkAction\AddFileLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\submissionFile\SubmissionFile;
class DependentFilesGridDataProvider extends SubmissionFilesGridDataProvider
{
/**
* The submission file id for the parent file.
*
* @var int
*/
public $_assocId;
/**
* Constructor
*
* @param int $assocId Association ID
*/
public function __construct($assocId)
{
assert(is_numeric($assocId));
$this->_assocId = (int) $assocId;
parent::__construct(SubmissionFile::SUBMISSION_FILE_DEPENDENT);
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
// Retrieve all dependent files for the given file stage and original submission file id (i.e. the main galley/production file)
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterByAssoc(
Application::ASSOC_TYPE_SUBMISSION_FILE,
[$this->getAssocId()]
)->filterBySubmissionIds([$this->getSubmission()->getId()])
->filterByFileStages([$this->getFileStage()])
->includeDependentFiles()
->getMany()
->toArray();
return $this->prepareSubmissionFileData($submissionFiles, $this->_viewableOnly, $filter);
}
/**
* Overridden from SubmissionFilesGridDataProvider - we need to also include the assocType and assocId
*
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$submission = $this->getSubmission();
return new AddFileLinkAction(
$request,
$submission->getId(),
$this->getStageId(),
$this->getUploaderRoles(),
$this->getFileStage(),
Application::ASSOC_TYPE_SUBMISSION_FILE,
$this->getAssocId(),
null,
null,
$this->isDependent()
);
}
/**
* returns the id of the parent submission file for these dependent files.
*
* @return int
*/
public function getAssocId()
{
return $this->_assocId;
}
/**
* Convenience function to make the argument to the AddFileLinkAction more obvious.
*
* @return true
*/
public function isDependent()
{
return true;
}
}
@@ -0,0 +1,107 @@
<?php
/**
* @file controllers/grid/files/dependent/DependentFilesGridHandler.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 DependentFilesGridHandler
*
* @ingroup controllers_grid_files_dependent
*
* @brief Handle dependent files that are associated with a submissions's display
* (galleys or production formats, for example).
* The submission author and all context/editor roles have access to this grid.
*/
namespace PKP\controllers\grid\files\dependent;
use APP\core\Application;
use APP\submission\Submission;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\security\authorization\PublicationAccessPolicy;
use PKP\security\authorization\SubmissionFileAccessPolicy;
use PKP\security\Role;
class DependentFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// import app-specific grid data provider for access policies.
$request = Application::get()->getRequest();
$submissionFileId = $request->getUserVar('submissionFileId'); // authorized in authorize() method.
parent::__construct(
new DependentFilesGridDataProvider($submissionFileId),
$request->getUserVar('stageId')
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
$this->setTitle('submission.submit.dependentFiles');
}
/**
* Get the authorized publication.
*
* @return \Publication
*/
public function getPublication()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_PUBLICATION);
}
/**
* @copydoc SubmissionFilesGridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new SubmissionFileAccessPolicy($request, $args, $roleAssignments, SubmissionFileAccessPolicy::SUBMISSION_FILE_ACCESS_MODIFY, (int) $args['submissionFileId']));
$publicationId = $request->getUserVar('publicationId'); // authorized in authorize() method.
if ($publicationId) {
$this->addPolicy(new PublicationAccessPolicy($request, $args, $roleAssignments));
}
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::getRequestArgs()
*/
public function getRequestArgs()
{
$submissionFile = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION_FILE);
return array_merge(
parent::getRequestArgs(),
['submissionFileId' => $submissionFile->getId()]
);
}
public function initialize($request, $args = null)
{
$capabilities = FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT;
$publication = $this->getPublication();
if ($publication) {
if ($publication->getData('status') == Submission::STATUS_PUBLISHED) {
$capabilities = FilesGridCapabilities::FILE_GRID_VIEW_NOTES;
}
}
$this->setCapabilities(new FilesGridCapabilities($capabilities));
parent::initialize($request, $args);
}
}
@@ -0,0 +1,65 @@
<?php
/**
* @file controllers/grid/files/fileList/FileGenreGridColumn.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 FileGenreGridColumn
*
* @ingroup controllers_grid_files_fileList
*
* @brief Implements a file name column.
*/
namespace PKP\controllers\grid\files\fileList;
use PKP\controllers\grid\ColumnBasedGridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\db\DAORegistry;
use PKP\submission\GenreDAO;
use PKP\submissionFile\SubmissionFile;
class FileGenreGridColumn extends GridColumn
{
/**
* Constructor
*/
public function __construct()
{
$cellProvider = new ColumnBasedGridCellProvider();
parent::__construct('type', 'common.component', null, null, $cellProvider);
}
//
// Public methods
//
/**
* Method expected by ColumnBasedGridCellProvider
* to render a cell in this column.
*
* @see ColumnBasedGridCellProvider::getTemplateVarsFromRowColumn()
*/
public function getTemplateVarsFromRow($row)
{
// Retrieve the submission file.
$submissionFileData = & $row->getData();
assert(isset($submissionFileData['submissionFile']));
$submissionFile = & $submissionFileData['submissionFile']; /** @var SubmissionFile $submissionFile */
assert(is_a($submissionFile, 'SubmissionFile'));
// Retrieve the genre label for the submission file.
$genreDao = DAORegistry::getDAO('GenreDAO'); /** @var GenreDAO $genreDao */
$genre = $genreDao->getById($submissionFile->getGenreId());
// If no label exists (e.g. for review attachments)
if (!$genre) {
return ['label' => null];
}
// Otherwise, the label exists.
return ['label' => $genre->getLocalizedName()];
}
}
@@ -0,0 +1,49 @@
<?php
/**
* @defgroup controllers_grid_files_fileList File List Grid
*/
/**
* @file controllers/grid/files/fileList/FileListGridHandler.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 FileListGridHandler
*
* @ingroup controllers_grid_files_fileList
*
* @brief Base grid for simple file lists. This grid shows the file type in
* addition to the file name.
*/
namespace PKP\controllers\grid\files\fileList;
use PKP\controllers\grid\files\SubmissionFilesGridHandler;
class FileListGridHandler extends SubmissionFilesGridHandler
{
//
// Extended methods from SubmissionFilesGridHandler.
//
/**
* @copydoc SubmissionFilesGridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
// Add the "manage files" action if required.
$capabilities = $this->getCapabilities();
if ($capabilities->canManage()) {
$dataProvider = $this->getDataProvider();
$this->addAction($dataProvider->getSelectAction($request));
}
// The file list grid layout has an additional file genre column.
$this->addColumn(new FileGenreGridColumn());
}
}
@@ -0,0 +1,55 @@
<?php
/**
* @file controllers/grid/files/fileList/SelectableFileListGridHandler.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 SelectableFileListGridHandler
*
* @ingroup controllers_grid_files_fileList
*
* @brief Base grid for selectable file lists. The grid use the SelectableItemFeature
* to show a check box for each row so that the user can make a selection
* among grid entries.
*/
namespace PKP\controllers\grid\files\fileList;
use PKP\controllers\grid\feature\selectableItems\SelectableItemsFeature;
class SelectableFileListGridHandler extends FileListGridHandler
{
//
// Overriden methods from GridHandler.
//
/**
* @copydoc GridHandler::initFeatures()
*/
public function initFeatures($request, $args)
{
return [new SelectableItemsFeature()];
}
//
// Implemented methods from GridHandler.
//
/**
* @copydoc GridHandler::isDataElementSelected()
*/
public function isDataElementSelected($gridDataElement)
{
$file = $gridDataElement['submissionFile'];
return $file->getViewable();
}
/**
* @copydoc GridHandler::getSelectName()
*/
public function getSelectName()
{
return 'selectedFiles';
}
}
@@ -0,0 +1,46 @@
<?php
/**
* @defgroup controllers_grid_files_fileList_linkAction File List Link Actions
*/
/**
* @file controllers/grid/files/fileList/linkAction/DownloadAllLinkAction.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 DownloadAllLinkAction
*
* @ingroup controllers_grid_files_fileList_linkAction
*
* @brief An action to download all files in a submission file grid.
*/
namespace PKP\controllers\grid\files\fileList\linkAction;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\PostAndRedirectAction;
class DownloadAllLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param array $actionArgs
*/
public function __construct($request, $actionArgs)
{
// Instantiate the redirect action request.
$router = $request->getRouter();
$redirectRequest = new PostAndRedirectAction(
$router->url($request, null, 'api.file.FileApiHandler', 'recordDownload', null, $actionArgs),
$router->url($request, null, 'api.file.FileApiHandler', 'downloadAllFiles', null, $actionArgs)
);
// Configure the link action.
parent::__construct('downloadAll', $redirectRequest, __('submission.files.downloadAll'), 'getPackage');
}
}
@@ -0,0 +1,49 @@
<?php
/**
* @file controllers/grid/files/fileList/linkAction/SelectFilesLinkAction.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 SelectFilesLinkAction
*
* @ingroup controllers_grid_files_fileList_linkAction
*
* @brief An abstract base action for actions to open up a modal that allows users to
* select files from a file list grid.
*/
namespace PKP\controllers\grid\files\fileList\linkAction;
use APP\core\Request;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
class SelectFilesLinkAction extends LinkAction
{
/**
* Constructor
*
* @param Request $request
* @param array $actionArgs The parameters required by the
* link action target to identify a list of files.
* @param string $actionLabel The localized label of the link action.
* @param string $modalTitle the (optional) title to be used for the modal.
*/
public function __construct($request, $actionArgs, $actionLabel, $modalTitle = null)
{
// Create an ajax action request that'll contain
// the file selection grid.
$modalTitle ??= $actionLabel;
$router = $request->getRouter();
$ajaxModal = new AjaxModal(
$router->url($request, null, null, 'selectFiles', null, $actionArgs),
$modalTitle,
'modal_add_file'
);
// Configure the link action.
parent::__construct('selectFiles', $ajaxModal, $actionLabel, 'add');
}
}
@@ -0,0 +1,40 @@
<?php
/**
* @file controllers/grid/files/fileList/linkAction/SelectReviewFilesLinkAction.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 SelectReviewFilesLinkAction
*
* @ingroup controllers_grid_files_fileList_linkAction
*
* @brief An action to open up the modal that allows users to select review files
* from a file list grid.
*/
namespace PKP\controllers\grid\files\fileList\linkAction;
use APP\core\Request;
use PKP\submission\reviewRound\ReviewRound;
class SelectReviewFilesLinkAction extends SelectFilesLinkAction
{
/**
* Constructor
*
* @param Request $request
* @param ReviewRound $reviewRound The review round from which to
* select review files.
* @param string $actionLabel The localized label of the link action.
* @param string $modalTitle the (optional) title to be used for the modal.
*/
public function __construct($request, $reviewRound, $actionLabel, $modalTitle = null)
{
$actionArgs = ['submissionId' => $reviewRound->getSubmissionId(),
'stageId' => $reviewRound->getStageId(), 'reviewRoundId' => $reviewRound->getId()];
parent::__construct($request, $actionArgs, $actionLabel, $modalTitle);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* @file controllers/grid/files/final/FinalDraftFilesGridDataProvider.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 FinalDraftFilesGridDataProvider
*
* @ingroup controllers_grid_files_final
*
* @brief Provide access to final draft files management.
*/
namespace PKP\controllers\grid\files\final;
use PKP\controllers\grid\files\fileList\linkAction\SelectFilesLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\submissionFile\SubmissionFile;
class FinalDraftFilesGridDataProvider extends SubmissionFilesGridDataProvider
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(SubmissionFile::SUBMISSION_FILE_FINAL);
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getSelectAction()
*/
public function getSelectAction($request)
{
return new SelectFilesLinkAction(
$request,
[
'submissionId' => $this->getSubmission()->getId(),
'stageId' => $this->getStageId()
],
__('editor.submission.uploadSelectFiles')
);
}
}
@@ -0,0 +1,71 @@
<?php
/**
* @file controllers/grid/files/final/FinalDraftFilesGridHandler.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 FinalDraftFilesGridHandler
*
* @ingroup controllers_grid_files_final
*
* @brief Handle the final draft files grid (displays files sent to copyediting from the review stage)
*/
namespace PKP\controllers\grid\files\final;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\final\form\ManageFinalDraftFilesForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\Role;
class FinalDraftFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
* FILE_GRID_* capabilities set.
*/
public function __construct()
{
parent::__construct(
new FinalDraftFilesGridDataProvider(),
null,
FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_MANAGE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'fetchGrid', 'fetchRow', 'selectFiles'
]
);
$this->setTitle('submission.finalDraft');
}
//
// Public handler methods
//
/**
* Show the form to allow the user to select files from previous stages
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function selectFiles($args, $request)
{
$manageFinalDraftFilesForm = new ManageFinalDraftFilesForm($this->getSubmission()->getId());
$manageFinalDraftFilesForm->initData();
return new JSONMessage(true, $manageFinalDraftFilesForm->fetch($request));
}
}
@@ -0,0 +1,91 @@
<?php
/**
* @file controllers/grid/files/final/ManageFinalDraftFilesGridHandler.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 ManageFinalDraftFilesGridHandler
*
* @ingroup controllers_grid_files_final
*
* @brief Handle the editor review file selection grid (selects which files to send to review or to next review round)
*/
namespace PKP\controllers\grid\files\final;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\final\form\ManageFinalDraftFilesForm;
use PKP\controllers\grid\files\SelectableSubmissionFileListCategoryGridHandler;
use PKP\controllers\grid\files\SubmissionFilesCategoryGridDataProvider;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ManageFinalDraftFilesGridHandler extends SelectableSubmissionFileListCategoryGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(
new SubmissionFilesCategoryGridDataProvider(SubmissionFile::SUBMISSION_FILE_FINAL),
WORKFLOW_STAGE_ID_EDITING,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'fetchGrid', 'fetchCategory', 'fetchRow',
'addFile',
'downloadFile',
'deleteFile',
'updateFinalDraftFiles'
]
);
// Set the grid title.
$this->setTitle('submission.finalDraft');
}
//
// Public handler methods
//
/**
* Save 'manage final draft files' form
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateFinalDraftFiles($args, $request)
{
$submission = $this->getSubmission();
$manageFinalDraftFilesForm = new ManageFinalDraftFilesForm($submission->getId());
$manageFinalDraftFilesForm->readInputData();
if ($manageFinalDraftFilesForm->validate()) {
$manageFinalDraftFilesForm->execute(
$this->getGridCategoryDataElements($request, $this->getStageId())
);
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
}
@@ -0,0 +1,49 @@
<?php
/**
* @file controllers/grid/files/final/form/ManageFinalDraftFilesForm.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 ManageFinalDraftFilesForm
*
* @ingroup controllers_grid_files_finalDraftFiles
*
* @brief Form to add files to the final draft files grid
*/
namespace PKP\controllers\grid\files\final\form;
use PKP\controllers\grid\files\form\ManageSubmissionFilesForm;
use PKP\submissionFile\SubmissionFile;
class ManageFinalDraftFilesForm extends ManageSubmissionFilesForm
{
/**
* Constructor.
*
* @param int $submissionId Submission ID.
*/
public function __construct($submissionId)
{
parent::__construct($submissionId, 'controllers/grid/files/final/manageFinalDraftFiles.tpl');
}
//
// Overridden template methods
//
/**
* Save Selection of Final Draft files
*
* @param array $stageSubmissionFiles The files that belongs to a file stage
* that is currently being used by a grid inside this form.
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
*/
public function execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs)
{
parent::execute($stageSubmissionFiles, SubmissionFile::SUBMISSION_FILE_FINAL);
}
}
@@ -0,0 +1,83 @@
<?php
/**
* @file controllers/grid/files/form/LibraryFileForm.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 LibraryFileForm
*
* @ingroup controllers_grid_file_form
*
* @brief Form for adding/editing a file
*/
namespace PKP\controllers\grid\files\form;
use APP\file\LibraryFileManager;
use APP\template\TemplateManager;
use PKP\form\Form;
class LibraryFileForm extends Form
{
/** @var int the id of the context this library file is attached to */
public $contextId;
/** @var LibraryFileManager the library file manager instantiated in this form. */
public $libraryFileManager;
/**
* Constructor.
*
* @param string $template
* @param int $contextId
*/
public function __construct($template, $contextId)
{
$this->contextId = $contextId;
parent::__construct($template);
$this->libraryFileManager = $libraryFileManager = new LibraryFileManager($contextId);
$this->addCheck(new \PKP\form\validation\FormValidatorLocale($this, 'libraryFileName', 'required', 'settings.libraryFiles.nameRequired'));
$this->addCheck(new \PKP\form\validation\FormValidatorCustom(
$this,
'fileType',
'required',
'settings.libraryFiles.typeRequired',
function ($type) use ($libraryFileManager) {
return is_numeric($type) && $libraryFileManager->getNameFromType($type);
}
));
$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)
{
// load the file types for the selector on the form.
$templateMgr = TemplateManager::getManager($request);
$fileTypeKeys = $this->libraryFileManager->getTypeTitleKeyMap();
$templateMgr->assign('fileTypes', $fileTypeKeys);
return parent::fetch($request, $template, $display);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['libraryFileName', 'fileType', 'publicAccess']);
}
}
@@ -0,0 +1,157 @@
<?php
/**
* @file controllers/grid/files/form/ManageSubmissionFilesForm.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 ManageSubmissionFilesForm
*
* @ingroup controllers_grid_files_form
*
* @brief Form for add or removing files from a review
*/
namespace PKP\controllers\grid\files\form;
use APP\facades\Repo;
use PKP\form\Form;
use PKP\submissionFile\SubmissionFile;
class ManageSubmissionFilesForm extends Form
{
/** @var int */
public $_submissionId;
/**
* Constructor.
*
* @param int $submissionId Submission ID
* @param string $template Template filename
*/
public function __construct($submissionId, $template)
{
parent::__construct($template);
$this->_submissionId = (int)$submissionId;
$this->addCheck(new \PKP\form\validation\FormValidatorPost($this));
$this->addCheck(new \PKP\form\validation\FormValidatorCSRF($this));
}
//
// Getters / Setters
//
/**
* Get the submission id
*
* @return int
*/
public function getSubmissionId()
{
return $this->_submissionId;
}
//
// Overridden template methods
//
/**
* @copydoc Form::initData
*/
public function initData()
{
$this->setData('submissionId', $this->_submissionId);
}
/**
* Assign form data to user-submitted data.
*
* @see Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['selectedFiles']);
}
/**
* Save selection of submission files
*
* @param array $stageSubmissionFiles The files that belongs to a file stage
* that is currently being used by a grid inside this form.
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
*/
public function execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs)
{
$selectedFiles = (array)$this->getData('selectedFiles');
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$this->getSubmissionId()])
->getMany();
foreach ($submissionFiles as $submissionFile) {
// Get the viewable flag value.
$isViewable = in_array(
$submissionFile->getId(),
$selectedFiles
);
// If this is a submission file that's already in this listing...
if ($this->fileExistsInStage($submissionFile, $stageSubmissionFiles, $fileStage)) {
// ...update the "viewable" flag accordingly.
if ($isViewable != $submissionFile->getData('viewable')) {
Repo::submissionFile()
->edit(
$submissionFile,
['viewable' => $isViewable]
);
$submissionFile = Repo::submissionFile()->get($submissionFile->getId());
}
} elseif ($isViewable) {
// Import a file from a different workflow area
$submissionFile = $this->importFile($submissionFile, $fileStage);
}
}
parent::execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs);
}
/**
* Determine if a file with the same file stage is already present in the workflow stage.
*
* @param SubmissionFile $submissionFile The submission file
* @param array $stageSubmissionFiles The list of submission files in the stage.
* @param int $fileStage FILE_STAGE_...
*/
protected function fileExistsInStage($submissionFile, $stageSubmissionFiles, $fileStage)
{
if (!isset($stageSubmissionFiles[$submissionFile->getId()])) {
return false;
}
foreach ($stageSubmissionFiles[$submissionFile->getId()] as $stageFile) {
if ($stageFile->getFileStage() == $submissionFile->getFileStage() && $stageFile->getFileStage() == $fileStage) {
return true;
}
}
return false;
}
/**
* Make a copy of the file to the specified file stage.
*
* @param SubmissionFile $submissionFile
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
*
* @return SubmissionFile Resultant new submission file
*/
protected function importFile($submissionFile, $fileStage)
{
$newSubmissionFile = clone $submissionFile;
$newSubmissionFile->setData('fileStage', $fileStage);
$newSubmissionFile->setData('sourceSubmissionFileId', $submissionFile->getId());
$newSubmissionFileId = Repo::submissionFile()->add($newSubmissionFile);
return Repo::submissionFile()->get($newSubmissionFileId);
}
}
@@ -0,0 +1,55 @@
<?php
/**
* @file controllers/grid/files/productionReady/ProductionReadyFilesGridHandler.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 ProductionReadyFilesGridHandler
*
* @ingroup controllers_grid_files_productionready
*
* @brief Handle the fair copy files grid (displays copyedited files ready to move to proofreading)
*/
namespace PKP\controllers\grid\files\productionReady;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ProductionReadyFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(
new SubmissionFilesGridDataProvider(SubmissionFile::SUBMISSION_FILE_PRODUCTION_READY),
WORKFLOW_STAGE_ID_PRODUCTION,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_DOWNLOAD_ALL
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'fetchGrid', 'fetchRow',
'addFile',
'downloadFile',
'deleteFile',
]
);
$this->setTitle('editor.submission.production.productionReadyFiles');
}
}
@@ -0,0 +1,118 @@
<?php
/**
* @file controllers/grid/files/proof/ManageProofFilesGridHandler.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 ManageProofFilesGridHandler
*
* @ingroup controllers_grid_files_proof
*
* @brief Handle the editor's proof files selection grid (selects which files to include)
*/
namespace PKP\controllers\grid\files\proof;
use APP\core\Application;
use PKP\controllers\grid\files\proof\form\ManageProofFilesForm;
use PKP\controllers\grid\files\SelectableSubmissionFileListCategoryGridHandler;
use PKP\controllers\grid\files\SubmissionFilesCategoryGridDataProvider;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\authorization\internal\RepresentationRequiredPolicy;
use PKP\security\authorization\PublicationAccessPolicy;
use PKP\security\authorization\SubmissionAccessPolicy;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ManageProofFilesGridHandler extends SelectableSubmissionFileListCategoryGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(
new SubmissionFilesCategoryGridDataProvider(SubmissionFile::SUBMISSION_FILE_PROOF),
WORKFLOW_STAGE_ID_PRODUCTION
);
$this->addRoleAssignment(
[Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
[
'fetchGrid', 'fetchCategory', 'fetchRow',
'addFile', 'downloadFile', 'deleteFile',
'updateProofFiles',
]
);
// Set the grid title.
$this->setTitle('submission.pageProofs');
}
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$this->addPolicy(new SubmissionAccessPolicy($request, $args, $roleAssignments));
$this->addPolicy(new PublicationAccessPolicy($request, $args, $roleAssignments));
$this->addPolicy(new RepresentationRequiredPolicy($request, $args));
return parent::authorize($request, $args, $roleAssignments);
}
/**
* Get the grid request parameters.
*
* @return array
*/
public function getRequestArgs()
{
$publication = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_PUBLICATION);
$representation = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REPRESENTATION);
return array_merge(
parent::getRequestArgs(),
[
'publicationId' => $publication->getId(),
'representationId' => $representation->getId()
]
);
}
//
// Public handler methods
//
/**
* Save 'manage proof files' form
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateProofFiles($args, $request)
{
$submission = $this->getSubmission();
$publication = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_PUBLICATION);
$representation = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REPRESENTATION);
$manageProofFilesForm = new ManageProofFilesForm($submission->getId(), $publication->getId(), $representation->getId());
$manageProofFilesForm->readInputData();
if ($manageProofFilesForm->validate()) {
$manageProofFilesForm->execute(
$this->getGridCategoryDataElements($request, $this->getStageId()),
SubmissionFile::SUBMISSION_FILE_PROOF
);
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
}
@@ -0,0 +1,84 @@
<?php
/**
* @file controllers/grid/files/proof/form/ManageProofFilesForm.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 ManageProofFilesForm
*
* @ingroup controllers_grid_files_proof
*
* @brief Form to add files to the proof files grid
*/
namespace PKP\controllers\grid\files\proof\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\controllers\grid\files\form\ManageSubmissionFilesForm;
use PKP\submissionFile\SubmissionFile;
class ManageProofFilesForm extends ManageSubmissionFilesForm
{
/** @var int PublicationId ID. */
public $_publicationId;
/** @var int Representation ID. */
public $_representationId;
/**
* Constructor.
*
* @param int $submissionId Submission ID.
* @param int $publicationId Publication ID
* @param int $representationId Representation ID.
*/
public function __construct($submissionId, $publicationId, $representationId)
{
parent::__construct($submissionId, 'controllers/grid/files/proof/manageProofFiles.tpl');
$this->_publicationId = $publicationId;
$this->_representationId = $representationId;
}
//
// Overridden template methods
//
/**
* @copydoc ManageSubmissionFilesForm::fetch
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('publicationId', $this->_publicationId);
$templateMgr->assign('representationId', $this->_representationId);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc ManageSubmissionFilesForm::fileExistsInStage
*/
protected function fileExistsInStage($submissionFile, $stageSubmissionFiles, $fileStage)
{
return false;
}
/**
* @copydoc ManageSubmissionFilesForm::importFile()
*/
protected function importFile($submissionFile, $fileStage)
{
$newSubmissionFile = clone $submissionFile;
$newSubmissionFile->setData('assocType', Application::ASSOC_TYPE_REPRESENTATION);
$newSubmissionFile->setData('assocId', $this->_representationId);
$newSubmissionFile->setData('viewable', false); // Not approved by default
return parent::importFile($newSubmissionFile, SubmissionFile::SUBMISSION_FILE_PROOF);
}
}
@@ -0,0 +1,115 @@
<?php
/**
* @file controllers/grid/files/query/ManageQueryNoteFilesGridHandler.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 ManageQueryNoteFilesGridHandler
*
* @ingroup controllers_grid_files_query
*
* @brief Handle the query file selection grid
*/
namespace PKP\controllers\grid\files\query;
use APP\core\Application;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\query\form\ManageQueryNoteFilesForm;
use PKP\controllers\grid\files\SelectableSubmissionFileListCategoryGridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\Role;
class ManageQueryNoteFilesGridHandler extends SelectableSubmissionFileListCategoryGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$request = Application::get()->getRequest();
$stageId = $request->getUservar('stageId'); // authorized by data provider.
parent::__construct(
new QueryNoteFilesCategoryGridDataProvider(),
$stageId,
FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[
Role::ROLE_ID_SUB_EDITOR,
Role::ROLE_ID_MANAGER,
Role::ROLE_ID_SITE_ADMIN,
Role::ROLE_ID_ASSISTANT
],
[
'fetchGrid', 'fetchCategory', 'fetchRow',
'addFile',
'downloadFile',
'deleteFile',
'updateQueryNoteFiles'
]
);
// Set the grid title.
$this->setTitle('submission.queryNoteFiles');
}
//
// Override methods from SelectableSubmissionFileListCategoryGridHandler
//
/**
* @copydoc GridHandler::isDataElementInCategorySelected()
*/
public function isDataElementInCategorySelected($categoryDataId, &$gridDataElement)
{
$submissionFile = $gridDataElement['submissionFile'];
// Check for special cases when the file needs to be unselected.
$dataProvider = $this->getDataProvider();
if ($dataProvider->getFileStage() != $submissionFile->getFileStage()) {
return false;
}
// Passed the checks above. If it's part of the current query, mark selected.
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
$headNote = $query->getHeadNote();
return ($submissionFile->getData('assocType') == Application::ASSOC_TYPE_NOTE && $submissionFile->getData('assocId') == $headNote->getId());
}
//
// Public handler methods
//
/**
* Save 'manage query files' form
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateQueryNoteFiles($args, $request)
{
$submission = $this->getSubmission();
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
$manageQueryNoteFilesForm = new ManageQueryNoteFilesForm($submission->getId(), $query->getId(), $request->getUserVar('noteId'));
$manageQueryNoteFilesForm->readInputData();
if ($manageQueryNoteFilesForm->validate()) {
$manageQueryNoteFilesForm->execute(
$this->getGridCategoryDataElements($request, $this->getStageId())
);
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
}
@@ -0,0 +1,46 @@
<?php
/**
* @file controllers/grid/files/query/QueryNoteFilesCategoryGridDataProvider.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 QueryNoteFilesCategoryGridDataProvider
*
* @ingroup controllers_grid_files_query
*
* @brief Provide access to query file data for category grids.
*/
namespace PKP\controllers\grid\files\query;
use APP\core\Application;
use PKP\controllers\grid\files\SubmissionFilesCategoryGridDataProvider;
use PKP\submissionFile\SubmissionFile;
class QueryNoteFilesCategoryGridDataProvider extends SubmissionFilesCategoryGridDataProvider
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(SubmissionFile::SUBMISSION_FILE_QUERY);
}
//
// Overriden public methods from SubmissionFilesCategoryGridDataProvider
//
/**
* @copydoc SubmissionFilesCategoryGridDataProvider::initGridDataProvider()
*
* @param null|mixed $initParams
*/
public function initGridDataProvider($fileStage, $initParams = null)
{
$request = Application::get()->getRequest();
return new QueryNoteFilesGridDataProvider($request->getUserVar('noteId'));
}
}
@@ -0,0 +1,139 @@
<?php
/**
* @file controllers/grid/files/query/QueryNoteFilesGridDataProvider.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 QueryNoteFilesGridDataProvider
*
* @ingroup controllers_grid_files_query
*
* @brief Provide access to query files management.
*/
namespace PKP\controllers\grid\files\query;
use APP\core\Application;
use APP\facades\Repo;
use Exception;
use PKP\controllers\api\file\linkAction\AddFileLinkAction;
use PKP\controllers\grid\files\fileList\linkAction\SelectFilesLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\db\DAORegistry;
use PKP\note\NoteDAO;
use PKP\security\authorization\QueryAccessPolicy;
use PKP\submissionFile\SubmissionFile;
class QueryNoteFilesGridDataProvider extends SubmissionFilesGridDataProvider
{
/** @var int Note ID */
public $_noteId;
/**
* Constructor
*
* @param int $noteId Note ID
*/
public function __construct($noteId)
{
parent::__construct(SubmissionFile::SUBMISSION_FILE_QUERY);
$this->_noteId = $noteId;
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
$this->setUploaderRoles($roleAssignments);
return new QueryAccessPolicy($request, $args, $roleAssignments, $this->getStageId());
}
/**
* @copydoc FilesGridDataProvider::getSelectAction()
*/
public function getSelectAction($request)
{
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
return new SelectFilesLinkAction(
$request,
$this->getRequestArgs(),
__('editor.submission.selectFiles')
);
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
// Retrieve all submission files for the given file query.
$submission = $this->getSubmission();
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
$noteDao = DAORegistry::getDAO('NoteDAO'); /** @var NoteDAO $noteDao */
$note = $noteDao->getById($this->_noteId);
if ($note->getAssocType() != Application::ASSOC_TYPE_QUERY || $note->getAssocId() != $query->getId()) {
throw new Exception('Invalid note ID specified!');
}
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterByAssoc(
Application::ASSOC_TYPE_NOTE,
[$this->_noteId]
)->filterBySubmissionIds([$submission->getId()])
->filterByFileStages([(int) $this->getFileStage()])
->getMany()
->toArray();
return $this->prepareSubmissionFileData($submissionFiles, $this->_viewableOnly, $filter);
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
$representation = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REPRESENTATION);
return array_merge(
parent::getRequestArgs(),
[
'assocType' => Application::ASSOC_TYPE_NOTE,
'assocId' => $this->_noteId,
'queryId' => $query->getId(),
'noteId' => $this->_noteId,
'representationId' => $representation ? $representation->getId() : null,
]
);
}
/**
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$submission = $this->getSubmission();
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
return new AddFileLinkAction(
$request,
$submission->getId(),
$this->getStageId(),
$this->getUploaderRoles(),
$this->getFileStage(),
Application::ASSOC_TYPE_NOTE,
$this->_noteId,
null,
null,
false,
$query->getId()
);
}
}
@@ -0,0 +1,98 @@
<?php
/**
* @file controllers/grid/files/query/QueryNoteFilesGridHandler.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 QueryNoteFilesGridHandler
*
* @ingroup controllers_grid_files_query
*
* @brief Handle query files that are associated with a query
* The participants of a query have access to the files in this grid.
*/
namespace PKP\controllers\grid\files\query;
use APP\core\Application;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\query\form\ManageQueryNoteFilesForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\authorization\QueryAccessPolicy;
use PKP\security\Role;
class QueryNoteFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// import app-specific grid data provider for access policies.
$request = Application::get()->getRequest();
$stageId = $request->getUservar('stageId'); // authorized in authorize() method.
parent::__construct(
new QueryNoteFilesGridDataProvider($request->getUserVar('noteId')),
$stageId,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow', 'selectFiles']
);
// Set grid title.
$this->setTitle('submission.queries.attachedFiles');
}
/**
* @copydoc SubmissionFilesGridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$stageId = $request->getUserVar('stageId'); // This is being validated in WorkflowStageAccessPolicy
$this->_stageId = (int)$stageId;
// Get the stage access policy
$queryAccessPolicy = new QueryAccessPolicy($request, $args, $roleAssignments, $stageId);
$this->addPolicy($queryAccessPolicy);
$result = parent::authorize($request, $args, $roleAssignments);
if (0 != count(array_intersect(
$this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES),
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT]
))) {
$this->getCapabilities()->setCanManage(true);
}
return $result;
}
//
// Public handler methods
//
/**
* Show the form to allow the user to select files from previous stages
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function selectFiles($args, $request)
{
$submission = $this->getSubmission();
$query = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
$manageQueryNoteFilesForm = new ManageQueryNoteFilesForm($submission->getId(), $query->getId(), $request->getUserVar('noteId'), $this->getRequestArgs());
$manageQueryNoteFilesForm->initData();
return new JSONMessage(true, $manageQueryNoteFilesForm->fetch($request));
}
}
@@ -0,0 +1,109 @@
<?php
/**
* @file controllers/grid/files/query/form/ManageQueryNoteFilesForm.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 ManageQueryNoteFilesForm
*
* @ingroup controllers_grid_files_query
*
* @brief Form to add files to the query files grid
*/
namespace PKP\controllers\grid\files\query\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\controllers\grid\files\form\ManageSubmissionFilesForm;
use PKP\submissionFile\SubmissionFile;
class ManageQueryNoteFilesForm extends ManageSubmissionFilesForm
{
/** @var int Query ID */
public $_queryId;
/** @var int Note ID */
public $_noteId;
/** @var array Extra parameters to actions. */
public $_actionArgs;
/**
* Constructor.
*
* @param int $submissionId Submission ID.
* @param int $queryId Query ID.
* @param int $noteId Note ID.
* @param array $actionArgs Optional list of extra request parameters.
*/
public function __construct($submissionId, $queryId, $noteId, $actionArgs = [])
{
parent::__construct($submissionId, 'controllers/grid/files/query/manageQueryNoteFiles.tpl');
$this->_queryId = $queryId;
$this->_noteId = $noteId;
$this->_actionArgs = $actionArgs;
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'queryId' => $this->_queryId,
'noteId' => $this->_noteId,
'actionArgs' => $this->_actionArgs,
]);
return parent::fetch($request, $template, $display);
}
/**
* Save selection of query files
*
* @param array $stageSubmissionFiles The list of submission files in the stage.
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
*/
public function execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs)
{
parent::execute($stageSubmissionFiles, SubmissionFile::SUBMISSION_FILE_QUERY);
}
/**
* @copydoc ManageSubmissionFilesForm::fileExistsInStage
*/
protected function fileExistsInStage($submissionFile, $stageSubmissionFiles, $fileStage)
{
if (!parent::fileExistsInStage($submissionFile, $stageSubmissionFiles, $fileStage)) {
return false;
}
foreach ($stageSubmissionFiles[$submissionFile->getId()] as $stageFile) {
if (
$stageFile->getFileStage() == $submissionFile->getFileStage() &&
$stageFile->getFileStage() == $fileStage &&
($stageFile->getData('assocType') != Application::ASSOC_TYPE_NOTE || $stageFile->getData('assocId') == $this->_noteId)
) {
return true;
}
}
return false;
}
/**
* @copydoc ManageSubmissionFilesForm::importFile()
*/
protected function importFile($submissionFile, $fileStage)
{
$newSubmissionFile = clone $submissionFile;
$newSubmissionFile->setData('assocType', Application::ASSOC_TYPE_NOTE);
$newSubmissionFile->setData('assocId', $this->_noteId);
return parent::importFile($newSubmissionFile, $fileStage);
}
}
@@ -0,0 +1,55 @@
<?php
/**
* @file controllers/grid/files/review/AuthorReviewRevisionsGridHandler.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 AuthorReviewRevisionsGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Display to authors the file revisions that they have uploaded.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class AuthorReviewRevisionsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION : SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION;
parent::__construct(
new ReviewGridDataProvider($fileStage),
null,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_DELETE
);
$this->addRoleAssignment(
[Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
$this->setTitle('editor.submission.revisions');
}
/**
* @copydoc GridHandler::getJSHandler()
*/
public function getJSHandler()
{
return '$.pkp.controllers.grid.files.review.AuthorReviewRevisionsGridHandler';
}
}
@@ -0,0 +1,75 @@
<?php
/**
* @file controllers/grid/files/review/EditorReviewFilesGridHandler.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 EditorReviewFilesGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Handle the editor review file grid (displays files that are to be reviewed in the current round)
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\review\form\ManageReviewFilesForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class EditorReviewFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE;
parent::__construct(
new ReviewGridDataProvider($fileStage),
null,
FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_MANAGE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_DELETE
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
['fetchGrid', 'fetchRow', 'selectFiles']
);
$this->setTitle('reviewer.submission.reviewFiles');
}
//
// Public handler methods
//
/**
* Show the form to allow the user to select review files
* (bring in/take out files from submission stage to review stage)
*
* FIXME: Move to its own handler so that it can be re-used among grids.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function selectFiles($args, $request)
{
$submission = $this->getSubmission();
$manageReviewFilesForm = new ManageReviewFilesForm($submission->getId(), $this->getRequestArg('stageId'), $this->getRequestArg('reviewRoundId'));
$manageReviewFilesForm->initData();
return new JSONMessage(true, $manageReviewFilesForm->fetch($request));
}
}
@@ -0,0 +1,92 @@
<?php
/**
* @file controllers/grid/files/review/LimitReviewFilesGridHandler.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 LimitReviewFilesGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Display a selectable list of review files for the round to editors.
* Items in this list can be selected or deselected to give a specific subset
* to a particular reviewer.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use PKP\controllers\grid\files\fileList\SelectableFileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\db\DAORegistry;
use PKP\security\authorization\internal\ReviewAssignmentRequiredPolicy;
use PKP\security\authorization\ReviewStageAccessPolicy;
use PKP\security\Role;
use PKP\submission\ReviewFilesDAO;
use PKP\submissionFile\SubmissionFile;
class LimitReviewFilesGridHandler extends SelectableFileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE;
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewGridDataProvider($fileStage),
null,
FilesGridCapabilities::FILE_GRID_VIEW_NOTES
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
['fetchGrid', 'fetchRow']
);
// Set the grid information.
$this->setTitle('editor.submissionReview.restrictFiles');
}
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
if ($reviewAssignmentId = $request->getUserVar('reviewAssignmentId')) {
// If a review assignment ID is specified, preload the
// checkboxes with the currently selected files. To do
// this, we'll need the review assignment in the context.
// Add the required policies:
// 1) Review stage access policy (fetches submission in context)
$this->addPolicy(new ReviewStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $request->getUserVar('stageId')));
// 2) Review assignment
$this->addPolicy(new ReviewAssignmentRequiredPolicy($request, $args, 'reviewAssignmentId', ['fetchGrid', 'fetchRow']));
}
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::isDataElementSelected()
*/
public function isDataElementSelected($gridDataElement)
{
$reviewAssignment = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
if ($reviewAssignment) {
$submissionFile = $gridDataElement['submissionFile'];
// A review assignment was specified in the request; preset the
// checkboxes to the currently available set of files.
$reviewFilesDao = DAORegistry::getDAO('ReviewFilesDAO'); /** @var ReviewFilesDAO $reviewFilesDao */
return $reviewFilesDao->check($reviewAssignment->getId(), $submissionFile->getId());
} else {
// No review assignment specified; default to all files available.
return true;
}
}
}
@@ -0,0 +1,106 @@
<?php
/**
* @file controllers/grid/files/review/ManageReviewFilesGridHandler.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 ManageReviewFilesGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Handle the editor review file selection grid (selects which files to send to review or to next review round)
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use APP\notification\NotificationManager;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\review\form\ManageReviewFilesForm;
use PKP\controllers\grid\files\SelectableSubmissionFileListCategoryGridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\notification\PKPNotification;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class ManageReviewFilesGridHandler extends SelectableSubmissionFileListCategoryGridHandler
{
/** @var array */
public $_selectionArgs;
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE;
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewCategoryGridDataProvider($fileStage),
null,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_VIEW_NOTES
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
['fetchGrid', 'fetchCategory', 'fetchRow', 'updateReviewFiles']
);
// Set the grid title.
$this->setTitle('reviewer.submission.reviewFiles');
}
//
// Public handler methods
//
/**
* Save 'manage review files' form.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateReviewFiles($args, $request)
{
$submission = $this->getSubmission();
$manageReviewFilesForm = new ManageReviewFilesForm($submission->getId(), $this->getRequestArg('stageId'), $this->getRequestArg('reviewRoundId'));
$manageReviewFilesForm->readInputData();
if ($manageReviewFilesForm->validate()) {
$dataProvider = $this->getDataProvider();
$manageReviewFilesForm->execute(
$this->getGridCategoryDataElements($request, $this->getStageId())
);
$this->setupTemplate($request);
$user = $request->getUser();
$notificationManager = new NotificationManager();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.updatedReviewFiles')]);
// Let the calling grid reload itself
return \PKP\db\DAO::getDataChangedEvent();
} else {
return new JSONMessage(false);
}
}
//
// Extended methods from CategoryGridHandler.
//
/**
* @copydoc CategoryGridHandler::getRequestArgs()
*/
public function getRequestArgs()
{
$stageId = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_WORKFLOW_STAGE);
return array_merge(['stageId' => $stageId], parent::getRequestArgs());
}
}
@@ -0,0 +1,93 @@
<?php
/**
* @file controllers/grid/files/review/ReviewCategoryGridDataProvider.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 ReviewCategoryGridDataProvider
*
* @ingroup controllers_grid_files_review
*
* @brief Provide access to review file data for category grids.
*/
namespace PKP\controllers\grid\files\review;
use PKP\controllers\grid\files\SubmissionFilesCategoryGridDataProvider;
use PKP\submission\reviewRound\ReviewRound;
class ReviewCategoryGridDataProvider extends SubmissionFilesCategoryGridDataProvider
{
/**
* Constructor
*
* @param int $fileStage
* @param int $viewableOnly Will be passed to the review grid data provider.
* See parameter description there.
*/
public function __construct($fileStage, $viewableOnly = false)
{
parent::__construct($fileStage, ['viewableOnly' => $viewableOnly]);
}
//
// Getters and setters.
//
/**
* @return ReviewRound
*/
public function getReviewRound()
{
/** @var ReviewGridDataProvider */
$gridDataProvider = $this->getDataProvider();
return $gridDataProvider->getReviewRound();
}
//
// Overriden public methods from SubmissionFilesCategoryGridDataProvider
//
/**
* @copydoc SubmissionFilesCategoryGridDataProvider::loadCategoryData()
*
* @param null|mixed $filter
* @param null|mixed $reviewRound
*/
public function loadCategoryData($request, $categoryDataElement, $filter = null, $reviewRound = null)
{
$reviewRound = $this->getReviewRound();
return parent::loadCategoryData($request, $categoryDataElement, $filter, $reviewRound);
}
/**
* @copydoc SubmissionFilesCategoryGridDataProvider::initGridDataProvider()
*
* @param null|mixed $initParams
*/
public function initGridDataProvider($fileStage, $initParams = null)
{
// This category grid data provider will use almost all the
// same implementation of the ReviewGridDataProvider.
$reviewFilesGridDataProvider = new ReviewGridDataProvider($fileStage);
$reviewFilesGridDataProvider->setViewableOnly($initParams['viewableOnly']);
return $reviewFilesGridDataProvider;
}
//
// Public methods
//
/**
* @copydoc ReviewGridDataProvider::getSelectAction()
*/
public function getSelectAction($request)
{
/** @var ReviewGridDataProvider */
$gridDataProvider = $this->getDataProvider();
return $gridDataProvider->getSelectAction($request);
}
}
@@ -0,0 +1,142 @@
<?php
/**
* @file controllers/grid/files/review/ReviewGridDataProvider.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 ReviewGridDataProvider
*
* @ingroup controllers_grid_files_review
*
* @brief Provide access to review file data for grids.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\api\file\linkAction\AddFileLinkAction;
use PKP\controllers\grid\files\fileList\linkAction\SelectReviewFilesLinkAction;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\security\authorization\internal\ReviewRoundRequiredPolicy;
use PKP\submission\reviewRound\ReviewRound;
class ReviewGridDataProvider extends SubmissionFilesGridDataProvider
{
/** @var bool */
protected $_showAll;
/**
* Constructor
*
* @copydoc SubmissionFilesGridDataProvider::__construct()
*
* @param bool $showAll True iff all review round files should be included.
*/
public function __construct($fileStageId, $viewableOnly = false, $showAll = false)
{
$this->_showAll = $showAll;
parent::__construct($fileStageId, $viewableOnly);
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
// Get the parent authorization policy.
$policy = parent::getAuthorizationPolicy($request, $args, $roleAssignments);
// Add policy to ensure there is a review round id.
$policy->addPolicy(new ReviewRoundRequiredPolicy($request, $args));
return $policy;
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$reviewRound = $this->getReviewRound();
return array_merge(
parent::getRequestArgs(),
[
'reviewRoundId' => $reviewRound->getId()
]
);
}
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
// Get all review files assigned to this submission.
$collector = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$this->getSubmission()->getId()])
->filterByReviewRoundIds([$this->getReviewRound()->getId()]);
if (!$this->_showAll) {
$collector = $collector->filterByFileStages([(int) $this->getFileStage()]);
}
return $this->prepareSubmissionFileData($collector->getMany()->toArray(), $this->_viewableOnly, $filter);
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getSelectAction()
*/
public function getSelectAction($request)
{
$reviewRound = $this->getReviewRound();
$modalTitle = __('editor.submission.review.currentFiles', ['round' => $reviewRound->getRound()]);
return new SelectReviewFilesLinkAction(
$request,
$reviewRound,
__('editor.submission.uploadSelectFiles'),
$modalTitle
);
}
/**
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$submission = $this->getSubmission();
$reviewRound = $this->getReviewRound();
return new AddFileLinkAction(
$request,
$submission->getId(),
$this->getStageId(),
$this->getUploaderRoles(),
$this->getFileStage(),
null,
null,
$reviewRound->getId()
);
}
/**
* Get the review round object.
*
* @return ReviewRound
*/
public function getReviewRound()
{
$reviewRound = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ROUND);
return $reviewRound;
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @file controllers/grid/files/review/ReviewRevisionsGridDataProvider.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 ReviewRevisionsGridDataProvider
*
* @ingroup controllers_grid_files_review
*
* @brief Provide access to review revisions (new files added during a
* review round) for grids.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use APP\facades\Repo;
use PKP\controllers\api\file\linkAction\AddRevisionLinkAction;
use PKP\submissionFile\SubmissionFile;
class ReviewRevisionsGridDataProvider extends ReviewGridDataProvider
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION : SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION;
parent::__construct($fileStage);
}
//
// Implement template methods from GridDataProvider
//
/**
* @copydoc GridDataProvider::loadData()
*/
public function loadData($filter = [])
{
// Grab the files that are new (incoming) revisions
// of those currently assigned to the review round.
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterBySubmissionIds([$this->getSubmission()->getId()])
->filterByReviewRoundIds([$this->getReviewRound()->getId()])
->filterByFileStages([(int) $this->getFileStage()])
->getMany()
->toArray();
return $this->prepareSubmissionFileData($submissionFiles, false, $filter);
}
//
// Overridden public methods from FilesGridDataProvider
//
/**
* @copydoc FilesGridDataProvider::getAddFileAction()
*/
public function getAddFileAction($request)
{
$reviewRound = $this->getReviewRound();
return new AddRevisionLinkAction(
$request,
$reviewRound,
$this->getUploaderRoles()
);
}
}
@@ -0,0 +1,97 @@
<?php
/**
* @file controllers/grid/files/review/ReviewerReviewFilesGridDataProvider.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 ReviewerReviewFilesGridDataProvider
*
* @ingroup controllers_grid_files_review
*
* @brief Provide reviewer access to review file data for review file grids.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use PKP\db\DAORegistry;
use PKP\security\authorization\internal\ReviewAssignmentRequiredPolicy;
use PKP\security\authorization\internal\ReviewRoundRequiredPolicy;
use PKP\security\authorization\internal\WorkflowStageRequiredPolicy;
use PKP\security\authorization\SubmissionAccessPolicy;
use PKP\submission\ReviewFilesDAO;
use PKP\submissionFile\SubmissionFile;
class ReviewerReviewFilesGridDataProvider extends ReviewGridDataProvider
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE;
parent::__construct($fileStage);
}
//
// Implement template methods from GridDataProvider
//
/**
* @see GridDataProvider::getAuthorizationPolicy()
* Override the parent class, which defines a Workflow policy, to allow
* reviewer access to this grid.
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
$context = $request->getContext();
$policy = new SubmissionAccessPolicy($request, $args, $roleAssignments, 'submissionId', !$context->getData('restrictReviewerFileAccess'));
$stageId = $request->getUserVar('stageId');
$policy->addPolicy(new WorkflowStageRequiredPolicy($stageId));
// Add policy to ensure there is a review round id.
$policy->addPolicy(new ReviewRoundRequiredPolicy($request, $args));
// Add policy to ensure there is a review assignment for certain operations.
$policy->addPolicy(new ReviewAssignmentRequiredPolicy($request, $args, 'reviewAssignmentId'));
return $policy;
}
/**
* @see ReviewerReviewFilesGridDataProvider
* Extend the parent class to filter out review round files that aren't allowed
* for this reviewer according to ReviewFilesDAO.
*
* @param array $filter
*/
public function loadData($filter = [])
{
$submissionFileData = parent::loadData();
$reviewFilesDao = DAORegistry::getDAO('ReviewFilesDAO'); /** @var ReviewFilesDAO $reviewFilesDao */
$reviewAssignment = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
foreach ($submissionFileData as $submissionFileId => $fileData) {
if (!$reviewFilesDao->check($reviewAssignment->getId(), $submissionFileId)) {
// Not permitted; remove from list.
unset($submissionFileData[$submissionFileId]);
}
}
return $submissionFileData;
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$reviewAssignment = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_REVIEW_ASSIGNMENT);
return array_merge(parent::getRequestArgs(), [
'reviewAssignmentId' => $reviewAssignment->getId()
]);
}
}
@@ -0,0 +1,43 @@
<?php
/**
* @file controllers/grid/files/review/ReviewerReviewFilesGridHandler.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 ReviewerReviewFilesGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Handle the reviewer review file grid (for reviewers to download files to review)
*/
namespace PKP\controllers\grid\files\review;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\security\Role;
class ReviewerReviewFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
// Pass in null stageId to be set in initialize from request var.
parent::__construct(
new ReviewerReviewFilesGridDataProvider(),
null
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_REVIEWER],
['fetchGrid', 'fetchRow']
);
// Set the grid title.
$this->setTitle('reviewer.submission.reviewFiles');
}
}
@@ -0,0 +1,47 @@
<?php
/**
* @file controllers/grid/files/review/WorkflowReviewRevisionsGridHandler.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 WorkflowReviewRevisionsGridHandler
*
* @ingroup controllers_grid_files_review
*
* @brief Display in workflow pages the file revisions that authors have uploaded.
*/
namespace PKP\controllers\grid\files\review;
use APP\core\Application;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class WorkflowReviewRevisionsGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$stageId = (int) Application::get()->getRequest()->getUserVar('stageId');
$fileStage = $stageId === WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_REVISION : SubmissionFile::SUBMISSION_FILE_REVIEW_REVISION;
parent::__construct(
new ReviewGridDataProvider($fileStage),
null,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_EDIT | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_DELETE
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
['fetchGrid', 'fetchRow', 'addFile']
);
$this->setTitle('editor.submission.revisions');
}
}
@@ -0,0 +1,129 @@
<?php
/**
* @file controllers/grid/files/review/form/ManageReviewFilesForm.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 ManageReviewFilesForm
*
* @ingroup controllers_grid_files_review_form
*
* @brief Form for add or removing files from a review
*/
namespace PKP\controllers\grid\files\review\form;
use APP\facades\Repo;
use PKP\controllers\grid\files\form\ManageSubmissionFilesForm;
use PKP\db\DAORegistry;
use PKP\submission\reviewRound\ReviewRound;
use PKP\submission\reviewRound\ReviewRoundDAO;
use PKP\submissionFile\SubmissionFile;
class ManageReviewFilesForm extends ManageSubmissionFilesForm
{
/** @var int */
public $_stageId;
/** @var int */
public $_reviewRoundId;
/**
* Constructor.
*/
public function __construct($submissionId, $stageId, $reviewRoundId)
{
parent::__construct($submissionId, 'controllers/grid/files/review/manageReviewFiles.tpl');
$this->_stageId = (int)$stageId;
$this->_reviewRoundId = (int)$reviewRoundId;
}
//
// Getters / Setters
//
/**
* Get the review stage id
*
* @return int
*/
public function getStageId()
{
return $this->_stageId;
}
/**
* Get the round
*
* @return int
*/
public function getReviewRoundId()
{
return $this->_reviewRoundId;
}
/**
* @return ReviewRound
*/
public function getReviewRound()
{
$reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /** @var ReviewRoundDAO $reviewRoundDao */
return $reviewRoundDao->getById($this->getReviewRoundId());
}
//
// Overridden template methods
//
/**
* @copydoc ManageSubmissionFilesForm::initData
*/
public function initData()
{
$this->setData('stageId', $this->getStageId());
$this->setData('reviewRoundId', $this->getReviewRoundId());
$reviewRound = $this->getReviewRound();
$this->setData('round', $reviewRound->getRound());
parent::initData();
}
/**
* Save review round files
*
* @stageSubmissionFiles array The files that belongs to a file stage
* that is currently being used by a grid inside this form.
*
* @param int $fileStage SubmissionFile::SUBMISSION_FILE_...
* @param null|mixed $stageSubmissionFiles
*/
public function execute($stageSubmissionFiles = null, $fileStage = null, ...$functionArgs)
{
parent::execute(
$stageSubmissionFiles,
$this->getReviewRound()->getStageId() == WORKFLOW_STAGE_ID_INTERNAL_REVIEW ? SubmissionFile::SUBMISSION_FILE_INTERNAL_REVIEW_FILE : SubmissionFile::SUBMISSION_FILE_REVIEW_FILE
);
}
/**
* @copydoc ManageSubmissionFilesForm::importFile()
*/
protected function importFile($submissionFile, $fileStage)
{
$newSubmissionFile = parent::importFile($submissionFile, $fileStage);
Repo::submissionFile()
->dao
->assignRevisionToReviewRound(
$newSubmissionFile,
$this->getReviewRound()
);
return $newSubmissionFile;
}
}
@@ -0,0 +1,43 @@
<?php
/**
* @file controllers/grid/files/submission/AuthorSubmissionDetailsFilesGridHandler.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 AuthorSubmissionDetailsFilesGridHandler
*
* @ingroup controllers_grid_files_submission
*
* @brief Handle submission file grid requests on the author's submission details pages.
*/
namespace PKP\controllers\grid\files\submission;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class AuthorSubmissionDetailsFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$dataProvider = new SubmissionFilesGridDataProvider(SubmissionFile::SUBMISSION_FILE_SUBMISSION);
parent::__construct($dataProvider, WORKFLOW_STAGE_ID_SUBMISSION, FilesGridCapabilities::FILE_GRID_DOWNLOAD_ALL | FilesGridCapabilities::FILE_GRID_EDIT);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
// Grid title.
$this->setTitle('submission.submit.submissionFiles');
}
}
@@ -0,0 +1,47 @@
<?php
/**
* @file controllers/grid/files/submission/EditorSubmissionDetailsFilesGridHandler.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 EditorSubmissionDetailsFilesGridHandler
*
* @ingroup controllers_grid_files_submission
*
* @brief Handle submission file grid requests on the editor's submission details pages.
*/
namespace PKP\controllers\grid\files\submission;
use PKP\controllers\grid\files\fileList\FileListGridHandler;
use PKP\controllers\grid\files\FilesGridCapabilities;
use PKP\controllers\grid\files\SubmissionFilesGridDataProvider;
use PKP\security\Role;
use PKP\submissionFile\SubmissionFile;
class EditorSubmissionDetailsFilesGridHandler extends FileListGridHandler
{
/**
* Constructor
*/
public function __construct()
{
$dataProvider = new SubmissionFilesGridDataProvider(SubmissionFile::SUBMISSION_FILE_SUBMISSION);
parent::__construct(
$dataProvider,
WORKFLOW_STAGE_ID_SUBMISSION,
FilesGridCapabilities::FILE_GRID_ADD | FilesGridCapabilities::FILE_GRID_DELETE | FilesGridCapabilities::FILE_GRID_VIEW_NOTES | FilesGridCapabilities::FILE_GRID_DOWNLOAD_ALL | FilesGridCapabilities::FILE_GRID_EDIT
);
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
['fetchGrid', 'fetchRow']
);
// Grid title.
$this->setTitle('submission.submit.submissionFiles');
}
}
@@ -0,0 +1,74 @@
<?php
/**
* @file controllers/grid/files/submissionDocuments/SubmissionDocumentsFilesGridDataProvider.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 SubmissionDocumentsFilesGridDataProvider
*
* @ingroup controllers_grid_files_submissionDocuments
*
* @brief The base data provider for the submission documents library files grid.
*/
namespace PKP\controllers\grid\files\submissionDocuments;
use APP\core\Application;
use APP\submission\Submission;
use PKP\context\LibraryFileDAO;
use PKP\controllers\grid\CategoryGridDataProvider;
use PKP\db\DAORegistry;
use PKP\security\authorization\SubmissionAccessPolicy;
class SubmissionDocumentsFilesGridDataProvider extends CategoryGridDataProvider
{
/**
* @copydoc GridDataProvider::getAuthorizationPolicy()
*/
public function getAuthorizationPolicy($request, $args, $roleAssignments)
{
return new SubmissionAccessPolicy($request, $args, $roleAssignments, 'submissionId');
}
//
// Getters and Setters
//
/**
* Get the authorized submission.
*
* @return Submission
*/
public function getSubmission()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
}
/**
* @copydoc GridDataProvider::getRequestArgs()
*/
public function getRequestArgs()
{
$submission = $this->getSubmission();
return [
'submissionId' => $submission->getId(),
];
}
/**
* @copydoc CategoryGridHandler::loadCategoryData()
*
* @param null|mixed $filter
*/
public function loadCategoryData($request, $fileType, $filter = null)
{
// Retrieve all library files for the given submission document category.
$submission = $this->getSubmission();
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$libraryFiles = $libraryFileDao->getBySubmissionId($submission->getId(), $fileType);
return $libraryFiles->toAssociativeArray();
}
}
@@ -0,0 +1,174 @@
<?php
/**
* @file controllers/grid/files/submissionDocuments/SubmissionDocumentsFilesGridHandler.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 SubmissionDocumentsFilesGridHandler
*
* @ingroup controllers_grid_files_submissionDocuments
*
* @brief Handle submission documents file grid requests.
*/
namespace PKP\controllers\grid\files\submissionDocuments;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\context\Context;
use PKP\controllers\grid\files\LibraryFileGridHandler;
use PKP\controllers\grid\files\LibraryFileGridRow;
use PKP\controllers\grid\files\submissionDocuments\form\EditLibraryFileForm;
use PKP\controllers\grid\files\submissionDocuments\form\NewLibraryFileForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\security\Role;
class SubmissionDocumentsFilesGridHandler extends LibraryFileGridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(new SubmissionDocumentsFilesGridDataProvider());
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT, Role::ROLE_ID_AUTHOR],
[
'addFile', 'uploadFile', 'saveFile', // Adding new library files
'editFile', 'updateFile', // Editing existing library files
'deleteFile', 'viewLibrary'
]
);
}
//
// Overridden template methods
//
/**
* Configure the grid
*
* @see LibraryFileGridHandler::initialize
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
$this->setCanEdit(true); // this grid can always be edited.
parent::initialize($request, $args);
$this->setTitle(null);
$router = $request->getRouter();
// Add grid-level actions
if ($this->canEdit()) {
$this->addAction(
new LinkAction(
'addFile',
new AjaxModal(
$router->url($request, null, null, 'addFile', null, $this->getActionArgs()),
__('grid.action.addFile'),
'modal_add_file'
),
__('grid.action.addFile'),
'add'
)
);
}
$this->addAction(
new LinkAction(
'viewLibrary',
new AjaxModal(
$router->url($request, null, null, 'viewLibrary', null, $this->getActionArgs()),
__('grid.action.viewLibrary'),
'modal_information'
),
__('grid.action.viewLibrary'),
'more_info'
)
);
}
/**
* Retrieve the arguments for the 'add file' action.
*
* @return array
*/
public function getActionArgs()
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
$actionArgs = [
'submissionId' => $submission->getId(),
];
return $actionArgs;
}
/**
* Get the row handler - override the default row handler
*
* @return LibraryFileGridRow
*/
protected function getRowInstance()
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
return new LibraryFileGridRow($this->canEdit(), $submission);
}
//
// Public File Grid Actions
//
/**
* Load the (read only) context file library.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function viewLibrary($args, $request)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('isModal', true);
$userRoles = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_USER_ROLES);
$templateMgr->assign('canEdit', !empty(array_intersect([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN], $userRoles)));
return $templateMgr->fetchJson('controllers/modals/documentLibrary/publisherLibrary.tpl');
}
/**
* Returns a specific instance of the new form for this grid.
*
* @param Context $context
*
* @return NewLibraryFileForm
*/
public function _getNewFileForm($context)
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
return new NewLibraryFileForm($context->getId(), $submission->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)
{
$submission = $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
return new EditLibraryFileForm($context->getId(), $fileId, $submission->getId());
}
}
@@ -0,0 +1,86 @@
<?php
/**
* @file controllers/grid/files/submissionDocuments/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_files_submissionDocuments_form
*
* @brief Form for editing a library file
*/
namespace PKP\controllers\grid\files\submissionDocuments\form;
use PKP\context\LibraryFile;
use PKP\context\LibraryFileDAO;
use PKP\controllers\grid\files\form\LibraryFileForm;
use PKP\db\DAORegistry;
class EditLibraryFileForm extends LibraryFileForm
{
/** @var LibraryFile the file being edited, or null for new */
public $libraryFile;
/** @var int the id of the submission for this library file */
public $submissionId;
/**
* Constructor.
*
* @param int $contextId
* @param int $fileId optional
*/
public function __construct($contextId, $fileId, $submissionId)
{
parent::__construct('controllers/grid/files/submissionDocuments/form/editFileForm.tpl', $contextId);
$this->submissionId = $submissionId;
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$this->libraryFile = $libraryFileDao->getById($fileId);
if (!$this->libraryFile || $this->libraryFile->getContextId() != $this->contextId || $this->libraryFile->getSubmissionId() != $this->getSubmissionId()) {
fatalError('Invalid library file!');
}
}
/**
* Initialize form data from current settings.
*/
public function initData()
{
$this->_data = [
'submissionId' => $this->libraryFile->getSubmissionId(),
'libraryFileName' => $this->libraryFile->getName(null), // Localized
'libraryFile' => $this->libraryFile // For read-only info
];
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$this->libraryFile->setName($this->getData('libraryFileName'), null); // Localized
$this->libraryFile->setType($this->getData('fileType'));
$libraryFileDao = DAORegistry::getDAO('LibraryFileDAO'); /** @var LibraryFileDAO $libraryFileDao */
$libraryFileDao->updateObject($this->libraryFile);
parent::execute(...$functionArgs);
}
/**
* return the submission ID for this library file.
*
* @return int
*/
public function getSubmissionId()
{
return $this->submissionId;
}
}
@@ -0,0 +1,114 @@
<?php
/**
* @file controllers/grid/files/submissionDocuments/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_files_submissionDocuments_form
*
* @brief Form for adding/editing a file
* stores/retrieves from an associative array
*/
namespace PKP\controllers\grid\files\submissionDocuments\form;
use APP\core\Application;
use APP\file\LibraryFileManager;
use APP\template\TemplateManager;
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
{
/** @var int */
public $submissionId;
/**
* Constructor.
*
* @param int $contextId
*/
public function __construct($contextId, $submissionId)
{
parent::__construct('controllers/grid/files/submissionDocuments/form/newFileForm.tpl', $contextId);
$this->submissionId = $submissionId;
$this->addCheck(new \PKP\form\validation\FormValidator($this, 'temporaryFileId', 'required', 'settings.libraryFiles.fileRequired'));
}
/**
* Assign form data to user-submitted data.
*
* @copydoc Form::readInputData()
*/
public function readInputData()
{
$this->readUserVars(['temporaryFileId', 'submissionId']);
return parent::readInputData();
}
/**
* @copydoc LibraryFileForm::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign('submissionId', $this->getSubmissionId());
return parent::fetch($request, $template, $display);
}
/**
* @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->setSubmissionId($this->getData('submissionId'));
$fileId = $libraryFileDao->insertObject($libraryFile);
// Clean up the temporary file
$temporaryFileManager = new TemporaryFileManager();
$temporaryFileManager->deleteById($this->getData('temporaryFileId'), $userId);
parent::execute(...$functionArgs);
return $fileId;
}
/**
* return the submission ID for this library file.
*
* @return int
*/
public function getSubmissionId()
{
return $this->submissionId;
}
}
@@ -0,0 +1,146 @@
<?php
/**
* @file controllers/grid/languages/LanguageGridCellProvider.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 LanguageGridCellProvider
*
* @ingroup controllers_grid_languages
*
* @brief Subclass for a language grid column's cell provider
*/
namespace PKP\controllers\grid\languages;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridHandler;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class LanguageGridCellProvider extends GridCellProvider
{
/**
* @copydoc GridCellProvider::getTemplateVarsFromRowColumn()
*/
public function getTemplateVarsFromRowColumn($row, $column)
{
$element = $row->getData();
$columnId = $column->getId();
switch ($columnId) {
case 'enable':
return ['selected' => $element['supported'],
'disabled' => false];
case 'locale':
$label = $element['name'];
$returnArray = ['label' => $label];
if (isset($element['incomplete'])) {
$returnArray['incomplete'] = $element['incomplete'];
}
return $returnArray;
case 'code':
$label = $element['code'];
$returnArray = ['label' => $label];
return $returnArray;
case 'sitePrimary':
return ['selected' => $element['primary'],
'disabled' => !$element['supported']];
case 'contextPrimary':
return ['selected' => $element['primary'],
'disabled' => !$element['supported']];
case 'uiLocale':
return ['selected' => $element['supportedLocales'],
'disabled' => !$element['supported']];
case 'formLocale':
return ['selected' => $element['supportedFormLocales'],
'disabled' => !$element['supported']];
case 'submissionLocale':
return ['selected' => $element['supportedSubmissionLocales'],
'disabled' => !$element['supported']];
default:
assert(false);
break;
}
}
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
$element = $row->getData();
$router = $request->getRouter();
$actions = [];
$actionArgs = ['rowId' => $row->getId()];
$action = null;
$actionRequest = null;
switch ($column->getId()) {
case 'enable':
$enabled = $element['supported'];
if ($enabled) {
$action = 'disable-' . $row->getId();
$actionRequest = new RemoteActionConfirmationModal(
$request->getSession(),
__('admin.languages.confirmDisable'),
__('common.disable'),
$router->url($request, null, null, 'disableLocale', null, $actionArgs)
);
} else {
$action = 'enable-' . $row->getId();
$actionRequest = new AjaxAction($router->url($request, null, null, 'enableLocale', null, $actionArgs));
}
break;
case 'sitePrimary':
$primary = $element['primary'];
if (!$primary) {
$action = 'setPrimary-' . $row->getId();
$actionRequest = new RemoteActionConfirmationModal(
$request->getSession(),
__('admin.languages.confirmSitePrimaryLocaleChange'),
__('locale.primary'),
$router->url($request, null, null, 'setPrimaryLocale', null, $actionArgs)
);
}
break;
case 'contextPrimary':
$primary = $element['primary'];
if (!$primary) {
$action = 'setPrimary-' . $row->getId();
$actionRequest = new AjaxAction($router->url($request, null, null, 'setContextPrimaryLocale', null, $actionArgs));
}
break;
case 'uiLocale':
$action = 'setUiLocale-' . $row->getId();
$actionArgs['setting'] = 'supportedLocales';
$actionArgs['value'] = !$element['supportedLocales'];
$actionRequest = new AjaxAction($router->url($request, null, null, 'saveLanguageSetting', null, $actionArgs));
break;
case 'formLocale':
$action = 'setFormLocale-' . $row->getId();
$actionArgs['setting'] = 'supportedFormLocales';
$actionArgs['value'] = !$element['supportedFormLocales'];
$actionRequest = new AjaxAction($router->url($request, null, null, 'saveLanguageSetting', null, $actionArgs));
break;
case 'submissionLocale':
$action = 'setSubmissionLocale-' . $row->getId();
$actionArgs['setting'] = 'supportedSubmissionLocales';
$actionArgs['value'] = !$element['supportedSubmissionLocales'];
$actionRequest = new AjaxAction($router->url($request, null, null, 'saveLanguageSetting', null, $actionArgs));
break;
}
if ($action && $actionRequest) {
$linkAction = new LinkAction($action, $actionRequest, null, null);
$actions = [$linkAction];
}
return $actions;
}
}
@@ -0,0 +1,348 @@
<?php
/**
* @file controllers/grid/languages/LanguageGridHandler.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 LanguageGridHandler
*
* @ingroup classes_controllers_grid_languages
*
* @brief Handle language grid requests.
*/
namespace PKP\controllers\grid\languages;
use APP\core\Application;
use APP\core\Request;
use APP\core\Services;
use APP\notification\NotificationManager;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\facades\Locale;
use PKP\notification\PKPNotification;
use PKP\security\Role;
class LanguageGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN],
['saveLanguageSetting', 'setContextPrimaryLocale']
);
}
//
// 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('common.languages');
}
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new LanguageGridRow();
}
//
// Public handler methods.
//
/**
* Save language management settings.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON message
*/
public function saveLanguageSetting($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$locale = (string) $request->getUserVar('rowId');
$settingName = (string) $request->getUserVar('setting');
$settingValue = (bool) $request->getUserVar('value');
$availableLocales = $this->getGridDataElements($request);
$context = $request->getContext();
$contextService = Services::get('context');
$permittedSettings = ['supportedFormLocales', 'supportedSubmissionLocales', 'supportedLocales'];
if (in_array($settingName, $permittedSettings) && $locale) {
$currentSettingValue = (array) $context->getData($settingName);
if (Locale::isLocaleValid($locale) && array_key_exists($locale, $availableLocales)) {
if ($settingValue) {
array_push($currentSettingValue, $locale);
if ($settingName == 'supportedFormLocales') {
// reload localized default context settings
$contextService->restoreLocaleDefaults($context, $request, $locale);
} elseif ($settingName == 'supportedSubmissionLocales') {
// if a submission locale is enabled, and this locale is not in the form locales, add it
$supportedFormLocales = (array) $context->getData('supportedFormLocales');
if (!in_array($locale, $supportedFormLocales)) {
array_push($supportedFormLocales, $locale);
$context = $contextService->edit($context, ['supportedFormLocales' => $supportedFormLocales], $request);
// reload localized default context settings
$contextService->restoreLocaleDefaults($context, $request, $locale);
}
}
} else {
$key = array_search($locale, $currentSettingValue);
if ($key !== false) {
unset($currentSettingValue[$key]);
}
if ($currentSettingValue === []) {
return new JSONMessage(false, __('notification.localeSettingsCannotBeSaved'));
}
if ($settingName == 'supportedFormLocales') {
// if a form locale is disabled, disable it form submission locales as well
$supportedSubmissionLocales = (array) $context->getData('supportedSubmissionLocales');
$key = array_search($locale, $supportedSubmissionLocales);
if ($key !== false) {
unset($supportedSubmissionLocales[$key]);
}
$supportedSubmissionLocales = array_values($supportedSubmissionLocales);
if ($supportedSubmissionLocales == []) {
return new JSONMessage(false, __('notification.localeSettingsCannotBeSaved'));
}
$context = $contextService->edit($context, ['supportedSubmissionLocales' => $supportedSubmissionLocales], $request);
}
if ($settingName == 'supportedSubmissionLocales') {
// If someone tried to disable all submissions checkboxes, we should display an error message.
$supportedSubmissionLocales = (array) $context->getData('supportedSubmissionLocales');
$key = array_search($locale, $supportedSubmissionLocales);
if ($key !== false) {
unset($supportedSubmissionLocales[$key]);
}
$supportedSubmissionLocales = array_values($supportedSubmissionLocales);
if ($supportedSubmissionLocales == []) {
return new JSONMessage(false, __('notification.localeSettingsCannotBeSaved'));
}
}
}
}
}
$context = $contextService->edit($context, [$settingName => array_values(array_unique($currentSettingValue))], $request);
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeSettingsSaved')]
);
$locales = $context->getSupportedFormLocaleNames();
$locales = array_map(fn (string $locale, string $name) => ['key' => $locale, 'label' => $name], array_keys($locales), $locales);
$json = \PKP\db\DAO::getDataChangedEvent($locale);
$json->setGlobalEvent('set-form-languages', $locales);
return $json;
}
/**
* Set context primary locale.
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function setContextPrimaryLocale($args, $request)
{
if (!$request->checkCSRF()) {
return new JSONMessage(false);
}
$locale = (string) $request->getUserVar('rowId');
$context = $request->getContext();
$availableLocales = $this->getGridDataElements($request);
if (Locale::isLocaleValid($locale) && array_key_exists($locale, $availableLocales)) {
// Make sure at least the primary locale is chosen as available
foreach (['supportedLocales', 'supportedSubmissionLocales', 'supportedFormLocales'] as $name) {
$$name = $context->getData($name);
if (!in_array($locale, $$name)) {
array_push($$name, $locale);
$context->updateSetting($name, $$name);
}
}
$context->setPrimaryLocale($locale);
$contextDao = Application::getContextDAO();
$contextDao->updateObject($context);
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification(
$user->getId(),
PKPNotification::NOTIFICATION_TYPE_SUCCESS,
['contents' => __('notification.localeSettingsSaved')]
);
}
return \PKP\db\DAO::getDataChangedEvent();
}
//
// Protected methods.
//
/**
* Return an instance of the cell provider
* used by this grid.
*
* @return LanguageGridCellProvider
*/
public function getCellProvider()
{
return new LanguageGridCellProvider();
}
/**
* Add name column.
*/
public function addNameColumn()
{
$cellProvider = $this->getCellProvider();
// Locale name.
$this->addColumn(
new GridColumn(
'locale',
'grid.columns.locale',
null,
'controllers/grid/languages/localeNameCell.tpl',
$cellProvider
)
);
}
/**
* Add locale code column.
*/
public function addLocaleCodeColumn()
{
$cellProvider = $this->getCellProvider();
// Locale code.
$this->addColumn(
new GridColumn(
'code',
'grid.columns.locale.code',
null,
null,
$cellProvider
)
);
}
/**
* Add primary column.
*
* @param string $columnId The column id.
*/
public function addPrimaryColumn($columnId)
{
$cellProvider = $this->getCellProvider();
$this->addColumn(
new GridColumn(
$columnId,
'locale.primary',
null,
'controllers/grid/common/cell/radioButtonCell.tpl',
$cellProvider
)
);
}
/**
* Add columns related to management settings.
*/
public function addManagementColumns()
{
$cellProvider = $this->getCellProvider();
$this->addColumn(
new GridColumn(
'uiLocale',
'manager.language.ui',
null,
'controllers/grid/common/cell/selectStatusCell.tpl',
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'formLocale',
'manager.language.forms',
null,
'controllers/grid/common/cell/selectStatusCell.tpl',
$cellProvider
)
);
$this->addColumn(
new GridColumn(
'submissionLocale',
'manager.language.submissions',
null,
'controllers/grid/common/cell/selectStatusCell.tpl',
$cellProvider
)
);
}
/**
* Add data related to management settings.
*
* @param Request $request
* @param array $data Data already loaded.
*
* @return array Same passed array, but with
* the extra management data inserted.
*/
public function addManagementData($request, $data)
{
$context = $request->getContext();
if (is_array($data)) {
foreach ($data as $locale => $localeData) {
foreach (['supportedFormLocales', 'supportedSubmissionLocales', 'supportedLocales'] as $name) {
$data[$locale][$name] = in_array($locale, $context->getData($name));
// $data[$locale][$name] = in_array($locale, (array) $context->getData($name));
}
}
} else {
assert(false);
}
return $data;
}
}
@@ -0,0 +1,83 @@
<?php
/**
* @file controllers/grid/languages/LanguageGridRow.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 LanguageGridRow
*
* @ingroup controllers_grid_languages
*
* @brief Language grid row definition
*/
namespace PKP\controllers\grid\languages;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\RemoteActionConfirmationModal;
use PKP\security\Validation;
class LanguageGridRow 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?
$rowId = $this->getId();
$rowData = $this->getData();
if (!empty($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
$actionArgs = [
'gridId' => $this->getGridId(),
'rowId' => $rowId
];
if (Validation::isSiteAdmin()) {
if (!$request->getContext() && !$rowData['primary']) {
$this->addAction(
new LinkAction(
'uninstall',
new RemoteActionConfirmationModal(
$request->getSession(),
__('admin.languages.confirmUninstall'),
__('grid.action.remove'),
$router->url($request, null, null, 'uninstallLocale', null, $actionArgs)
),
__('grid.action.remove'),
'delete'
)
);
}
if ($request->getContext()) {
$this->addAction(
new LinkAction(
'reload',
new RemoteActionConfirmationModal(
$request->getSession(),
__('manager.language.confirmDefaultSettingsOverwrite'),
__('manager.language.reloadLocalizedDefaultSettings'),
$router->url($request, null, null, 'reloadLocale', null, $actionArgs)
),
__('manager.language.reloadLocalizedDefaultSettings')
)
);
}
}
}
}
}
@@ -0,0 +1,116 @@
<?php
/**
* @file controllers/grid/languages/form/InstallLanguageForm.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 InstallLanguageForm
*
* @ingroup controllers_grid_languages_form
*
* @brief Form for installing languages.
*/
namespace PKP\controllers\grid\languages\form;
use APP\core\Application;
use APP\template\TemplateManager;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\form\Form;
use PKP\i18n\LocaleMetadata;
use PKP\site\SiteDAO;
class InstallLanguageForm extends Form
{
/**
* Constructor.
*/
public function __construct()
{
parent::__construct('controllers/grid/languages/installLanguageForm.tpl');
}
//
// Overridden methods from Form.
//
/**
* @copydoc Form::initData()
*/
public function initData()
{
parent::initData();
$request = Application::get()->getRequest();
$site = $request->getSite();
$this->setData('installedLocales', $site->getInstalledLocales());
}
/**
* @copydoc Form::fetch()
*
* @param null|mixed $template
*/
public function fetch($request, $template = null, $display = false)
{
$allLocales = Locale::getFormattedDisplayNames(null, null, LocaleMetadata::LANGUAGE_LOCALE_WITH, false);
$installedLocales = $this->getData('installedLocales');
$notInstalledLocales = array_diff(array_keys($allLocales), $installedLocales);
$templateMgr = TemplateManager::getManager($request);
$templateMgr->assign([
'allLocales' => $allLocales,
'notInstalledLocales' => $notInstalledLocales,
]);
return parent::fetch($request, $template, $display);
}
/**
* @copydoc Form::readInputData()
*/
public function readInputData()
{
parent::readInputData();
$request = Application::get()->getRequest();
$localesToInstall = $request->getUserVar('localesToInstall');
$this->setData('localesToInstall', $localesToInstall);
}
/**
* @copydoc Form::execute()
*/
public function execute(...$functionArgs)
{
$request = Application::get()->getRequest();
$site = $request->getSite();
$localesToInstall = $this->getData('localesToInstall');
parent::execute(...$functionArgs);
if (isset($localesToInstall) && is_array($localesToInstall)) {
$installedLocales = $site->getInstalledLocales();
$supportedLocales = $site->getSupportedLocales();
foreach ($localesToInstall as $locale) {
if (Locale::isLocaleValid($locale) && !in_array($locale, $installedLocales)) {
array_push($installedLocales, $locale);
// Activate/support by default.
if (!in_array($locale, $supportedLocales)) {
array_push($supportedLocales, $locale);
}
Locale::installLocale($locale);
}
}
$site->setInstalledLocales($installedLocales);
$site->setSupportedLocales($supportedLocales);
$siteDao = DAORegistry::getDAO('SiteDAO'); /** @var SiteDAO $siteDao */
$siteDao->updateObject($site);
}
}
}
@@ -0,0 +1,63 @@
<?php
/**
* @file controllers/grid/navigationMenus/NavigationMenuItemsCellProvider.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 NavigationMenuItemsGridCellProvider
*
* @ingroup controllers_grid_navigationMenus
*
* @brief Cell provider for title column of a NavigationMenuItems grid.
*/
namespace PKP\controllers\grid\navigationMenus;
use APP\core\Application;
use APP\core\Services;
use APP\template\TemplateManager;
use PKP\controllers\grid\GridCellProvider;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
class NavigationMenuItemsGridCellProvider extends GridCellProvider
{
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
return parent::getCellActions($request, $row, $column, $position);
}
/**
* 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)
{
$navigationMenuItem = $row->getData();
$columnId = $column->getId();
assert($navigationMenuItem instanceof \PKP\navigationMenu\NavigationMenuItem && !empty($columnId));
switch ($columnId) {
case 'title':
$templateMgr = TemplateManager::getManager(Application::get()->getRequest());
Services::get('navigationMenu')->transformNavMenuItemTitle($templateMgr, $navigationMenuItem);
return ['label' => $navigationMenuItem->getLocalizedTitle()];
default:
break;
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
}
@@ -0,0 +1,274 @@
<?php
/**
* @file controllers/grid/navigationMenus/NavigationMenuItemsGridHandler.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 NavigationMenuItemsGridHandler
*
* @ingroup controllers_grid_navigationMenus
*
* @brief Handle NavigationMenuItems grid requests.
*/
namespace PKP\controllers\grid\navigationMenus;
use APP\controllers\grid\navigationMenus\form\NavigationMenuItemsForm;
use APP\core\Request;
use APP\notification\NotificationManager;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\navigationMenu\NavigationMenuItemDAO;
use PKP\notification\PKPNotification;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
class NavigationMenuItemsGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
Role::ROLE_ID_MANAGER,
$ops = [
'fetchGrid', 'fetchRow',
'addNavigationMenuItem', 'editNavigationMenuItem',
'updateNavigationMenuItem',
'deleteNavigationMenuItem', 'saveSequence',
]
);
$this->addRoleAssignment(Role::ROLE_ID_SITE_ADMIN, $ops);
}
//
// Overridden template methods
//
/**
* @copydoc GridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$context = $request->getContext();
$contextId = $context ? $context->getId() : \PKP\core\PKPApplication::CONTEXT_ID_NONE;
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);
$navigationMenuItemId = $request->getUserVar('navigationMenuItemId');
if ($navigationMenuItemId) {
$navigationMenuItemDao = DAORegistry::getDAO('NavigationMenuItemDAO'); /** @var NavigationMenuItemDAO $navigationMenuItemDao */
$navigationMenuItem = $navigationMenuItemDao->getById($navigationMenuItemId);
if (!$navigationMenuItem || $navigationMenuItem->getContextId() != $contextId) {
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);
// Basic grid configuration
$this->setTitle('manager.navigationMenuItems');
// Set the no items row text
$this->setEmptyRowText('grid.navigationMenus.navigationMenuItems.noneExist');
// Columns
$navigationMenuItemsCellProvider = new NavigationMenuItemsGridCellProvider();
$this->addColumn(
new GridColumn(
'title',
'common.title',
null,
null,
$navigationMenuItemsCellProvider
)
);
// Add grid action.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addNavigationMenuItem',
new AjaxModal(
$router->url($request, null, null, 'addNavigationMenuItem', null, null),
__('grid.action.addNavigationMenuItem'),
'modal_add_item',
true
),
__('grid.action.addNavigationMenuItem'),
'add_item'
)
);
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuItemDao = DAORegistry::getDAO('NavigationMenuItemDAO'); /** @var NavigationMenuItemDAO $navigationMenuItemDao */
return $navigationMenuItemDao->getByContextId($contextId);
}
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new NavigationMenuItemsGridRow();
}
//
// Public grid actions.
//
/**
* Update NavigationMenuItem
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function updateNavigationMenuItem($args, $request)
{
$navigationMenuItemId = (int)$request->getUserVar('navigationMenuItemId');
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuItemForm = new NavigationMenuItemsForm($contextId, $navigationMenuItemId);
$navigationMenuItemForm->readInputData();
if ($navigationMenuItemForm->validate()) {
$navigationMenuItemForm->execute();
if ($navigationMenuItemId) {
// Successful edit of an existing $navigationMenuItem.
$notificationLocaleKey = 'notification.editedNavigationMenuItem';
} else {
// Successful added a new $navigationMenuItemForm.
$notificationLocaleKey = 'notification.addedNavigationMenuItem';
}
// Record the notification to user.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __($notificationLocaleKey)]);
// Prepare the grid row data.
return \PKP\db\DAO::getDataChangedEvent($navigationMenuItemId);
} else {
return new JSONMessage(false);
}
}
/**
* Display form to edit a navigation menu item object.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editNavigationMenuItem($args, $request)
{
$navigationMenuItemId = (int) $request->getUserVar('navigationMenuItemId');
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuItemForm = new NavigationMenuItemsForm($contextId, $navigationMenuItemId);
$navigationMenuItemForm->initData();
return new JSONMessage(true, $navigationMenuItemForm->fetch($request));
}
/**
* Add NavigationMenuItem
*
* @param array $args
* @param Request $request
*
* @return JSONMessage JSON object
*/
public function addNavigationMenuItem($args, $request)
{
$navigationMenuItemId = (int)$request->getUserVar('navigationMenuItemId');
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuItemForm = new NavigationMenuItemsForm($contextId, $navigationMenuItemId);
$navigationMenuItemForm->initData();
return new JSONMessage(true, $navigationMenuItemForm->fetch($request));
}
/**
* Delete a navigation Menu item.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteNavigationMenuItem($args, $request)
{
if (!$request->checkCSRF()) return new JSONMessage(false);
$navigationMenuItemId = (int) $request->getUserVar('navigationMenuItemId');
$navigationMenuItemDao = DAORegistry::getDAO('NavigationMenuItemDAO'); /** @var NavigationMenuItemDAO $navigationMenuItemDao */
$navigationMenuItem = $navigationMenuItemDao->getById($navigationMenuItemId);
if ($navigationMenuItem) {
$navigationMenuItemDao->deleteObject($navigationMenuItem);
// Create notification.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.removedNavigationMenuItem')]);
return \PKP\db\DAO::getDataChangedEvent($navigationMenuItemId);
}
return new JSONMessage(false);
}
}
@@ -0,0 +1,81 @@
<?php
/**
* @file controllers/grid/navigationMenus/NavigationMenuItemsGridRow.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 NavigationMenuItemsGridRow
*
* @ingroup controllers_grid_navigationMenus
*
* @brief NavigationMenuItem grid row definition
*/
namespace PKP\controllers\grid\navigationMenus;
use PKP\controllers\grid\GridRow;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\linkAction\request\RemoteActionConfirmationModal;
class NavigationMenuItemsGridRow extends GridRow
{
//
// Overridden methods from GridRow
//
/**
* @copydoc GridRow::initialize()
*
* @param null|mixed $template
*/
public function initialize($request, $template = null)
{
parent::initialize($request, $template);
$element = $this->getData();
assert($element instanceof \PKP\navigationMenu\NavigationMenuItem);
$rowId = $this->getId();
// Is this a new row or an existing row?
if (!empty($rowId) && is_numeric($rowId)) {
// Only add row actions if this is an existing row
$router = $request->getRouter();
$actionArgs = [
'navigationMenuItemId' => $rowId
];
$this->addAction(
new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editNavigationMenuItem', null, $actionArgs),
__('grid.action.edit'),
'modal_edit',
true
),
__('grid.action.edit'),
'edit'
)
);
$this->addAction(
new LinkAction(
'remove',
new RemoteActionConfirmationModal(
$request->getSession(),
__('common.confirmDelete'),
__('common.remove'),
$router->url($request, null, null, 'deleteNavigationMenuItem', null, $actionArgs),
'modal_delete'
),
__('grid.action.remove'),
'delete'
)
);
}
}
}
@@ -0,0 +1,96 @@
<?php
/**
* @file controllers/grid/navigationMenus/NavigationMenusGridCellProvider.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 NavigationMenusGridCellProvider
*
* @ingroup controllers_grid_navigationMenus
*
* @brief Cell provider for title column of a NavigationMenu grid.
*/
namespace PKP\controllers\grid\navigationMenus;
use APP\core\Application;
use APP\core\Services;
use APP\template\TemplateManager;
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\AjaxModal;
use PKP\navigationMenu\NavigationMenuItemDAO;
class NavigationMenusGridCellProvider extends GridCellProvider
{
/**
* @copydoc GridCellProvider::getCellActions()
*/
public function getCellActions($request, $row, $column, $position = GridHandler::GRID_ACTION_POSITION_DEFAULT)
{
switch ($column->getId()) {
case 'title':
$navigationMenu = $row->getData();
$router = $request->getRouter();
$actionArgs = ['navigationMenuId' => $row->getId()];
return [new LinkAction(
'edit',
new AjaxModal(
$router->url($request, null, null, 'editNavigationMenu', null, $actionArgs),
__('grid.action.edit'),
null,
true
),
htmlspecialchars($navigationMenu->getTitle())
)];
}
return parent::getCellActions($request, $row, $column, $position);
}
/**
* 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)
{
$navigationMenu = $row->getData();
$columnId = $column->getId();
assert($navigationMenu instanceof \PKP\navigationMenu\NavigationMenu && !empty($columnId));
switch ($columnId) {
case 'title':
return ['label' => ''];
case 'nmis':
$navigationMenuItemDao = DAORegistry::getDAO('NavigationMenuItemDAO'); /** @var NavigationMenuItemDAO $navigationMenuItemDao */
$items = $navigationMenuItemDao->getByMenuId($navigationMenu->getId())->toArray();
$navigationMenusTitles = '';
$templateMgr = TemplateManager::getManager(Application::get()->getRequest());
foreach ($items as $item) {
Services::get('navigationMenu')->transformNavMenuItemTitle($templateMgr, $item);
$navigationMenusTitles = $navigationMenusTitles . $item->getLocalizedTitle() . ', ';
}
$navigationMenusTitles = trim($navigationMenusTitles, ', ');
return ['label' => $navigationMenusTitles];
default:
break;
}
return parent::getTemplateVarsFromRowColumn($row, $column);
}
}
@@ -0,0 +1,277 @@
<?php
/**
* @file controllers/grid/navigationMenus/NavigationMenusGridHandler.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 NavigationMenusGridHandler
*
* @ingroup controllers_grid_navigationMenus
*
* @brief Handle NavigationMenus grid requests.
*/
namespace PKP\controllers\grid\navigationMenus;
use APP\notification\NotificationManager;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\navigationMenus\form\NavigationMenuForm;
use PKP\core\JSONMessage;
use PKP\core\PKPRequest;
use PKP\db\DAORegistry;
use PKP\linkAction\LinkAction;
use PKP\linkAction\request\AjaxModal;
use PKP\navigationMenu\NavigationMenuDAO;
use PKP\notification\PKPNotification;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RoleBasedHandlerOperationPolicy;
use PKP\security\Role;
class NavigationMenusGridHandler extends GridHandler
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
Role::ROLE_ID_MANAGER,
$ops = [
'fetchGrid', 'fetchRow',
'addNavigationMenu', 'editNavigationMenu',
'updateNavigationMenu',
'deleteNavigationMenu'
]
);
$this->addRoleAssignment(Role::ROLE_ID_SITE_ADMIN, $ops);
}
//
// Overridden template methods
//
/**
* @copydoc GridHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$context = $request->getContext();
$contextId = $context ? $context->getId() : \PKP\core\PKPApplication::CONTEXT_ID_NONE;
$rolePolicy = new PolicySet(PolicySet::COMBINING_PERMIT_OVERRIDES);
foreach ($roleAssignments as $role => $operations) {
$rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
}
$this->addPolicy($rolePolicy);
$navigationMenuId = $request->getUserVar('navigationMenuId');
if ($navigationMenuId) {
// Ensure NavigationMenus is valid and for this context
$navigationMenuDao = DAORegistry::getDAO('NavigationMenuDAO'); /** @var NavigationMenuDAO $navigationMenuDao */
$navigationMenu = $navigationMenuDao->getById($navigationMenuId);
if (!$navigationMenu || $navigationMenu->getContextId() != $contextId) {
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);
// Basic grid configuration
$this->setTitle('manager.navigationMenus');
// Set the no items row text
$this->setEmptyRowText('grid.navigationMenus.navigationMenu.noneExist');
// Columns
$navigationMenuCellProvider = new NavigationMenusGridCellProvider();
$this->addColumn(
new GridColumn(
'title',
'common.title',
null,
null,
$navigationMenuCellProvider
)
);
$this->addColumn(
new GridColumn(
'nmis',
'manager.navigationMenuItems',
null,
null,
$navigationMenuCellProvider
)
);
// Add grid action.
$router = $request->getRouter();
$this->addAction(
new LinkAction(
'addNavigationMenu',
new AjaxModal(
$router->url($request, null, null, 'addNavigationMenu', null, null),
__('grid.action.addNavigationMenu'),
'modal_add_item',
true
),
__('grid.action.addNavigationMenu'),
'add_item'
)
);
}
/**
* @copydoc GridHandler::loadData()
*/
protected function loadData($request, $filter)
{
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuDao = DAORegistry::getDAO('NavigationMenuDAO'); /** @var NavigationMenuDAO $navigationMenuDao */
return $navigationMenuDao->getByContextId($contextId);
}
/**
* @copydoc GridHandler::getRowInstance()
*/
protected function getRowInstance()
{
return new NavigationMenusGridRow();
}
//
// Public grid actions.
//
/**
* Display form to add NavigationMenus.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage
*/
public function addNavigationMenu($args, $request)
{
return $this->editNavigationMenu($args, $request);
}
/**
* Display form to edit NavigationMenus.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function editNavigationMenu($args, $request)
{
$navigationMenuId = (int)$request->getUserVar('navigationMenuId');
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
$navigationMenuForm = new NavigationMenuForm($contextId, $navigationMenuId);
$navigationMenuForm->initData();
return new JSONMessage(true, $navigationMenuForm->fetch($request));
}
/**
* Save an edited/inserted NavigationMenus.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function updateNavigationMenu($args, $request)
{
// Identify the NavigationMenu id.
$navigationMenuId = $request->getUserVar('navigationMenuId');
$context = $request->getContext();
$contextId = \PKP\core\PKPApplication::CONTEXT_ID_NONE;
if ($context) {
$contextId = $context->getId();
}
// Form handling.
$navigationMenusForm = new NavigationMenuForm($contextId, $navigationMenuId);
$navigationMenusForm->readInputData();
if ($navigationMenusForm->validate()) {
$navigationMenusForm->execute();
if ($navigationMenuId) {
// Successful edit of an existing NavigationMenu.
$notificationLocaleKey = 'notification.editedNavigationMenu';
} else {
// Successful added a new NavigationMenu.
$notificationLocaleKey = 'notification.addedNavigationMenu';
}
// Record the notification to user.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __($notificationLocaleKey)]);
// Prepare the grid row data.
return \PKP\db\DAO::getDataChangedEvent($navigationMenuId);
} else {
return new JSONMessage(false);
}
}
/**
* Delete a NavigationMenu.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteNavigationMenu($args, $request)
{
$navigationMenuId = (int) $request->getUserVar('navigationMenuId');
$context = $request->getContext();
$navigationMenuDao = DAORegistry::getDAO('NavigationMenuDAO'); /** @var NavigationMenuDAO $navigationMenuDao */
$navigationMenu = $navigationMenuDao->getById($navigationMenuId, $context ? $context->getId() : \PKP\core\PKPApplication::CONTEXT_SITE);
if ($navigationMenu && $request->checkCSRF()) {
$navigationMenuDao->deleteObject($navigationMenu);
// Create notification.
$notificationManager = new NotificationManager();
$user = $request->getUser();
$notificationManager->createTrivialNotification($user->getId(), PKPNotification::NOTIFICATION_TYPE_SUCCESS, ['contents' => __('notification.removedNavigationMenu')]);
return \PKP\db\DAO::getDataChangedEvent($navigationMenuId);
}
return new JSONMessage(false);
}
}

Some files were not shown because too many files have changed in this diff Show More