[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
05122024
/
htdocs
/
jurnal-kesmas
/
v1
/
lib
/
pkp
/
controllers
/
grid
/
queries
/
[
Home
]
File: QueriesGridHandler.php
<?php /** * @file controllers/grid/queries/QueriesGridHandler.php * * Copyright (c) 2016-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 QueriesGridHandler * * @ingroup controllers_grid_query * * @brief base PKP class to handle query grid requests. */ namespace PKP\controllers\grid\queries; use APP\core\Application; use APP\facades\Repo; use APP\notification\Notification; use APP\notification\NotificationManager; use APP\submission\Submission; use APP\template\TemplateManager; use Illuminate\Support\Facades\Mail; use PKP\controllers\grid\feature\OrderGridItemsFeature; use PKP\controllers\grid\GridColumn; use PKP\controllers\grid\GridHandler; use PKP\controllers\grid\queries\form\QueryForm; use PKP\controllers\grid\queries\traits\StageMailable; use PKP\core\JSONMessage; use PKP\core\PKPApplication; use PKP\core\PKPRequest; use PKP\db\DAORegistry; use PKP\linkAction\LinkAction; use PKP\linkAction\request\AjaxModal; use PKP\linkAction\request\RemoteActionConfirmationModal; use PKP\log\SubmissionEmailLogDAO; use PKP\log\SubmissionEmailLogEntry; use PKP\notification\NotificationDAO; use PKP\notification\NotificationSubscriptionSettingsDAO; use PKP\notification\PKPNotification; use PKP\query\Query; use PKP\query\QueryDAO; use PKP\security\authorization\QueryAccessPolicy; use PKP\security\authorization\QueryWorkflowStageAccessPolicy; use PKP\security\Role; use PKP\submissionFile\SubmissionFile; class QueriesGridHandler extends GridHandler { use StageMailable; /** @var int WORKFLOW_STAGE_ID_... */ public $_stageId; /** @var PKPRequest */ public $_request; /** * 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], ['fetchGrid', 'fetchRow', 'readQuery', 'participants', 'addQuery', 'editQuery', 'updateQuery', 'deleteQuery'] ); $this->addRoleAssignment( [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT], ['openQuery', 'closeQuery', 'saveSequence', 'fetchTemplateBody'] ); $this->addRoleAssignment( [Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN], ['leaveQuery'] ); } // // Getters/Setters // /** * Get the authorized submission. * * @return Submission */ public function getSubmission() { return $this->getAuthorizedContextObject(PKPApplication::ASSOC_TYPE_SUBMISSION); } /** * Get the authorized query. * * @return Query */ public function getQuery() { return $this->getAuthorizedContextObject(PKPApplication::ASSOC_TYPE_QUERY); } /** * Get the stage id. * * @return int */ public function getStageId() { return $this->_stageId; } /** * Get the query assoc type. * * @return int Application::ASSOC_TYPE_... */ public function getAssocType() { return PKPApplication::ASSOC_TYPE_SUBMISSION; } /** * Get the query assoc ID. * * @return int */ public function getAssocId() { return $this->getSubmission()->getId(); } /** * Create and return a data provider for this grid. * * @return QueriesGridCellProvider */ public function getCellProvider() { return new QueriesGridCellProvider( $this->getSubmission(), $this->getStageId(), $this->getAccessHelper() ); } // // Overridden methods from PKPHandler. // Note: this is subclassed in application-specific grids. // /** * @copydoc PKPHandler::authorize() */ public function authorize($request, &$args, $roleAssignments) { $this->_stageId = (int) $request->getUserVar('stageId'); // This is being validated in WorkflowStageAccessPolicy $this->_request = $request; if ($request->getUserVar('queryId')) { $this->addPolicy(new QueryAccessPolicy($request, $args, $roleAssignments, $this->_stageId)); } else { $this->addPolicy(new QueryWorkflowStageAccessPolicy($request, $args, $roleAssignments, 'submissionId', $this->_stageId)); } return parent::authorize($request, $args, $roleAssignments); } /** * @copydoc GridHandler::initialize() * * @param null|mixed $args */ public function initialize($request, $args = null) { parent::initialize($request, $args); switch ($this->getStageId()) { case WORKFLOW_STAGE_ID_SUBMISSION: $this->setTitle('submission.queries.submission'); break; case WORKFLOW_STAGE_ID_EDITING: $this->setTitle('submission.queries.editorial'); break; case WORKFLOW_STAGE_ID_PRODUCTION: $this->setTitle('submission.queries.production'); break; case WORKFLOW_STAGE_ID_INTERNAL_REVIEW: case WORKFLOW_STAGE_ID_EXTERNAL_REVIEW: $this->setTitle('submission.queries.review'); break; default: assert(false); } // Columns $cellProvider = $this->getCellProvider(); $this->addColumn(new QueryTitleGridColumn($this->getRequestArgs())); $this->addColumn(new GridColumn( 'from', 'submission.query.from', null, null, $cellProvider, ['html' => true, 'width' => 20] )); $this->addColumn(new GridColumn( 'lastReply', 'submission.query.lastReply', null, null, $cellProvider, ['html' => true, 'width' => 20] )); $this->addColumn(new GridColumn( 'replies', 'submission.query.replies', null, null, $cellProvider, ['width' => 10, 'alignment' => GridColumn::COLUMN_ALIGNMENT_CENTER] )); $this->addColumn( new GridColumn( 'closed', 'submission.query.closed', null, 'controllers/grid/common/cell/selectStatusCell.tpl', $cellProvider, ['width' => 10, 'alignment' => GridColumn::COLUMN_ALIGNMENT_CENTER] ) ); $router = $request->getRouter(); if ($this->getAccessHelper()->getCanCreate($this->getStageId())) { $this->addAction(new LinkAction( 'addQuery', new AjaxModal( $router->url($request, null, null, 'addQuery', null, $this->getRequestArgs()), __('grid.action.addQuery'), 'modal_add_item' ), __('grid.action.addQuery'), 'add_item' )); } } // // Overridden methods from GridHandler // /** * @copydoc GridHandler::initFeatures() */ public function initFeatures($request, $args) { $features = parent::initFeatures($request, $args); if ($this->getAccessHelper()->getCanOrder($this->getStageId())) { $features[] = new OrderGridItemsFeature(); } return $features; } /** * @copydoc GridHandler::getDataElementSequence() */ public function getDataElementSequence($row) { return $row->getSequence(); } /** * @copydoc GridHandler::setDataElementSequence() */ public function setDataElementSequence($request, $rowId, $gridDataElement, $newSequence) { $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $query = $queryDao->getById($rowId, $this->getAssocType(), $this->getAssocId()); $query->setSequence($newSequence); $queryDao->updateObject($query); } /** * @copydoc GridHandler::getRowInstance() * * @return QueriesGridRow */ public function getRowInstance() { return new QueriesGridRow( $this->getSubmission(), $this->getStageId(), $this->getAccessHelper() ); } /** * Get an instance of the queries grid access helper * * @return QueriesAccessHelper */ public function getAccessHelper() { return new QueriesAccessHelper($this->getAuthorizedContext(), $this->_request->getUser()); } /** * Get the arguments that will identify the data in the grid. * Overridden by child grids. * * @return array */ public function getRequestArgs() { return [ 'submissionId' => $this->getSubmission()->getId(), 'stageId' => $this->getStageId(), ]; } /** * @copydoc GridHandler::loadData() * * @param null|mixed $filter */ public function loadData($request, $filter = null) { $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ return $queryDao->getByAssoc( $this->getAssocType(), $this->getAssocId(), $this->getStageId(), $this->getAccessHelper()->getCanListAll($this->getStageId()) ? null : $request->getUser()->getId() ); } // // Public Query Grid Actions // /** * Add a query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function addQuery($args, $request) { if (!$this->getAccessHelper()->getCanCreate($this->getStageId())) { return new JSONMessage(false); } $queryForm = new QueryForm( $request, $this->getAssocType(), $this->getAssocId(), $this->getStageId() ); $queryForm->initData(); return new JSONMessage(true, $queryForm->fetch($request, null, false, $this->getRequestArgs())); } /** * Delete a query. * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function deleteQuery($args, $request) { $query = $this->getQuery(); if (!$request->checkCSRF() || !$query || !$this->getAccessHelper()->getCanDelete($query->getId())) { return new JSONMessage(false); } $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $queryDao->deleteObject($query); $notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */ $notificationDao->deleteByAssoc(PKPApplication::ASSOC_TYPE_QUERY, $query->getId()); if ($this->getStageId() == WORKFLOW_STAGE_ID_EDITING || $this->getStageId() == WORKFLOW_STAGE_ID_PRODUCTION) { // Update submission notifications $notificationMgr = new NotificationManager(); $notificationMgr->updateNotification( $request, [ PKPNotification::NOTIFICATION_TYPE_ASSIGN_COPYEDITOR, PKPNotification::NOTIFICATION_TYPE_AWAITING_COPYEDITS, PKPNotification::NOTIFICATION_TYPE_ASSIGN_PRODUCTIONUSER, PKPNotification::NOTIFICATION_TYPE_AWAITING_REPRESENTATIONS, ], null, PKPApplication::ASSOC_TYPE_SUBMISSION, $this->getAssocId() ); } return \PKP\db\DAO::getDataChangedEvent($query->getId()); } /** * Open a closed query. * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function openQuery($args, $request) { $query = $this->getQuery(); if (!$query || !$this->getAccessHelper()->getCanOpenClose($query)) { return new JSONMessage(false); } $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $query->setIsClosed(false); $queryDao->updateObject($query); return \PKP\db\DAO::getDataChangedEvent($query->getId()); } /** * Close an open query. * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function closeQuery($args, $request) { $query = $this->getQuery(); if (!$query || !$this->getAccessHelper()->getCanOpenClose($query)) { return new JSONMessage(false); } $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $query->setIsClosed(true); $queryDao->updateObject($query); return \PKP\db\DAO::getDataChangedEvent($query->getId()); } /** * Get the name of the query notes grid handler. * * @return string */ public function getQueryNotesGridHandlerName() { return 'grid.queries.QueryNotesGridHandler'; } /** * Read a query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function readQuery($args, $request) { $query = $this->getQuery(); $router = $request->getRouter(); $user = $request->getUser(); $context = $request->getContext(); $actionArgs = array_merge($this->getRequestArgs(), ['queryId' => $query->getId()]); // If appropriate, create an Edit action for the participants list if ($this->getAccessHelper()->getCanEdit($query->getId())) { $editAction = new LinkAction( 'editQuery', new AjaxModal( $router->url($request, null, null, 'editQuery', null, $actionArgs), __('grid.action.updateQuery'), 'modal_edit' ), __('grid.action.edit'), 'edit' ); } else { $editAction = null; } $leaveQueryLinkAction = new LinkAction( 'leaveQuery', new RemoteActionConfirmationModal( $request->getSession(), __('submission.query.leaveQuery.confirm'), __('submission.query.leaveQuery'), $router->url($request, null, null, 'leaveQuery', null, $actionArgs), 'modal_delete' ), __('submission.query.leaveQuery'), 'leaveQuery' ); // Show leave query button for journal managers included in the query if ($user && $this->_getCurrentUserCanLeave($query->getId())) { $showLeaveQueryButton = true; } else { $showLeaveQueryButton = false; } $templateMgr = TemplateManager::getManager($request); $templateMgr->assign([ 'queryNotesGridHandlerName' => $this->getQueryNotesGridHandlerName(), 'requestArgs' => $this->getRequestArgs(), 'query' => $query, 'editAction' => $editAction, 'leaveQueryLinkAction' => $leaveQueryLinkAction, 'showLeaveQueryButton' => $showLeaveQueryButton, ]); return new JSONMessage(true, $templateMgr->fetch('controllers/grid/queries/readQuery.tpl')); } /** * Fetch the list of participants for a query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function participants($args, $request) { $query = $this->getQuery(); $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $context = $request->getContext(); $user = $request->getUser(); $participants = []; foreach ($queryDao->getParticipantIds($query->getId()) as $userId) { $user = Repo::user()->get($userId); if ($user) { $participants[] = $user; } } $templateMgr = TemplateManager::getManager($request); $templateMgr->assign('participants', $participants); if ($user && $this->_getCurrentUserCanLeave($query->getId())) { $showLeaveQueryButton = true; } else { $showLeaveQueryButton = false; } $json = new JSONMessage(); $json->setStatus(true); $json->setContent($templateMgr->fetch('controllers/grid/queries/participants.tpl')); $json->setAdditionalAttributes(['showLeaveQueryButton' => $showLeaveQueryButton]); return $json; } /** * Edit a query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function editQuery($args, $request) { $query = $this->getQuery(); if (!$this->getAccessHelper()->getCanEdit($query->getId())) { return new JSONMessage(false); } // Form handling $queryForm = new QueryForm( $request, $this->getAssocType(), $this->getAssocId(), $this->getStageId(), $query->getId() ); $queryForm->initData(); return new JSONMessage(true, $queryForm->fetch($request, null, false, $this->getRequestArgs())); } /** * Save a query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function updateQuery($args, $request) { $query = $this->getQuery(); if (!$this->getAccessHelper()->getCanEdit($query->getId())) { return new JSONMessage(false); } /** @var QueryDAO */ $queryDao = DAORegistry::getDAO('QueryDAO'); $oldParticipantIds = $queryDao->getParticipantIds($query->getId()); $queryForm = new QueryForm( $request, $this->getAssocType(), $this->getAssocId(), $this->getStageId(), $query->getId() ); $queryForm->readInputData(); if ($queryForm->validate()) { $queryForm->execute(); $notificationMgr = new NotificationManager(); if ($this->getStageId() == WORKFLOW_STAGE_ID_EDITING || $this->getStageId() == WORKFLOW_STAGE_ID_PRODUCTION) { // Update submission notifications $notificationMgr->updateNotification( $request, [ PKPNotification::NOTIFICATION_TYPE_ASSIGN_COPYEDITOR, PKPNotification::NOTIFICATION_TYPE_AWAITING_COPYEDITS, PKPNotification::NOTIFICATION_TYPE_ASSIGN_PRODUCTIONUSER, PKPNotification::NOTIFICATION_TYPE_AWAITING_REPRESENTATIONS, ], null, PKPApplication::ASSOC_TYPE_SUBMISSION, $this->getAssocId() ); } // Send notifications $currentUser = $request->getUser(); $newParticipantIds = $queryForm->getData('users'); $added = array_diff($newParticipantIds, $oldParticipantIds); // Don't notify the current user if ($key = array_search($currentUser->getId(), $added)) { unset($added[$key]); } /** @var NotificationSubscriptionSettingsDAO */ $notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO'); $note = $query->getHeadNote(); $submission = $this->getSubmission(); // Find attachments if any $submissionFiles = Repo::submissionFile() ->getCollector() ->filterByAssoc( PKPApplication::ASSOC_TYPE_NOTE, [$note->getId()] )->filterBySubmissionIds([$submission->getId()]) ->getMany(); foreach ($added as $userId) { $user = Repo::user()->get((int) $userId); $notification = $notificationMgr->createNotification( $request, $userId, PKPNotification::NOTIFICATION_TYPE_NEW_QUERY, $request->getContext()->getId(), PKPApplication::ASSOC_TYPE_QUERY, $query->getId(), Notification::NOTIFICATION_LEVEL_TASK ); // Check if the user is unsubscribed $notificationSubscriptionSettings = $notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings( NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY, $user->getId(), $request->getContext()->getId() ); if (in_array(PKPNotification::NOTIFICATION_TYPE_NEW_QUERY, $notificationSubscriptionSettings)) { continue; } $mailable = $this->getStageMailable($request->getContext(), $submission) ->sender($currentUser) ->recipients([$user]) ->subject($note->getData('title')) ->body($note->getData('contents')) ->allowUnsubscribe($notification); $submissionFiles->each(fn(SubmissionFile $item) => $mailable->attachSubmissionFile( $item->getId(), $item->getLocalizedData('name') )); Mail::send($mailable); $logDao = DAORegistry::getDAO('SubmissionEmailLogDAO'); /** @var SubmissionEmailLogDAO $logDao */ $logDao->logMailable(SubmissionEmailLogEntry::SUBMISSION_EMAIL_DISCUSSION_NOTIFY, $mailable, $submission); } return \PKP\db\DAO::getDataChangedEvent($query->getId()); } // If this was new (placeholder) query that didn't validate, remember whether or not // we need to delete it on cancellation. if ($request->getUserVar('wasNew')) { $queryForm->setIsNew(true); } return new JSONMessage( true, $queryForm->fetch( $request, null, false, array_merge( $this->getRequestArgs(), ['queryId' => $query->getId()] ) ) ); } /** * Leave query * * @param array $args * @param PKPRequest $request * * @return JSONMessage JSON object */ public function leaveQuery($args, $request) { $queryId = $args['queryId']; $user = $request->getUser(); if ($user && $this->_getCurrentUserCanLeave($queryId)) { $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $queryDao->removeParticipant($queryId, $user->getId()); $json = new JSONMessage(); $json->setEvent('user-left-discussion'); } else { $json = new JSONMessage(false); } return $json; } /** * Check if the current user can leave a query. Only allow if query has more than two participants. * * @param int $queryId * * @return bool */ public function _getCurrentUserCanLeave($queryId) { $userRoles = $this->getAuthorizedContextObject(PKPApplication::ASSOC_TYPE_USER_ROLES); if (!count(array_intersect([Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, ], $userRoles))) { return false; } $queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */ $participantIds = $queryDao->getParticipantIds($queryId); if (count($participantIds) < 3) { return false; } $user = Application::get()->getRequest()->getUser(); return in_array($user->getId(), $participantIds); } /** * Fetches an email template's message body. * * @return JSONMessage JSON object */ public function fetchTemplateBody(array $args, PKPRequest $request): JSONMessage { $templateId = $request->getUserVar('template'); $context = $request->getContext(); $template = Repo::emailTemplate()->getByKey($context->getId(), $templateId); if ($template) { $mailable = $this->getStageMailable($context, $this->getSubmission()); $mailable->sender($request->getUser()); $data = $mailable->getData(); return new JSONMessage( true, [ 'body' => Mail::compileParams($template->getLocalizedData('body'), $data), 'subject' => Mail::compileParams($template->getLocalizedData('subject'), $data), ] ); } } }