<?php
/**
* @file controllers/grid/queries/QueryNotesGridHandler.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 QueryNotesGridHandler
*
* @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 Illuminate\Support\Facades\Mail;
use PKP\controllers\grid\GridColumn;
use PKP\controllers\grid\GridHandler;
use PKP\controllers\grid\queries\form\QueryNoteForm;
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\note\Note;
use PKP\note\NoteDAO;
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\Role;
use PKP\submissionFile\SubmissionFile;
use PKP\user\User;
class QueryNotesGridHandler extends GridHandler
{
use StageMailable;
/** @var User */
public $_user;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->addRoleAssignment(
[Role::ROLE_ID_MANAGER, Role::ROLE_ID_SITE_ADMIN, Role::ROLE_ID_REVIEWER, Role::ROLE_ID_AUTHOR, Role::ROLE_ID_SUB_EDITOR, Role::ROLE_ID_ASSISTANT],
['fetchGrid', 'fetchRow', 'addNote', 'insertNote', 'deleteNote']
);
}
//
// Getters/Setters
//
/**
* Get the authorized submission.
*/
public function getSubmission(): Submission
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_SUBMISSION);
}
/**
* Get the query.
*
* @return Query
*/
public function getQuery(): ?Query
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_QUERY);
}
/**
* Get the stage id.
*
* @return int
*/
public function getStageId()
{
return $this->getAuthorizedContextObject(Application::ASSOC_TYPE_WORKFLOW_STAGE);
}
//
// Overridden methods from PKPHandler.
// Note: this is subclassed in application-specific grids.
//
/**
* @copydoc PKPHandler::authorize()
*/
public function authorize($request, &$args, $roleAssignments)
{
$stageId = $request->getUserVar('stageId'); // This is being validated in WorkflowStageAccessPolicy
// Get the access policy
$this->addPolicy(new QueryAccessPolicy($request, $args, $roleAssignments, $stageId));
return parent::authorize($request, $args, $roleAssignments);
}
/**
* @copydoc GridHandler::initialize()
*
* @param null|mixed $args
*/
public function initialize($request, $args = null)
{
parent::initialize($request, $args);
$this->setTitle('submission.query.messages');
$cellProvider = new QueryNotesGridCellProvider($this->getSubmission());
// Columns
$this->addColumn(
new GridColumn(
'contents',
'common.note',
null,
null,
$cellProvider,
['width' => 80, 'html' => true]
)
);
$this->addColumn(
new GridColumn(
'from',
'submission.query.from',
null,
null,
$cellProvider,
['html' => true]
)
);
$this->_user = $request->getUser();
}
//
// Overridden methods from GridHandler
//
/**
* @copydoc GridHandler::getRowInstance()
*
* @return QueryNotesGridRow
*/
public function getRowInstance()
{
return new QueryNotesGridRow($this->getRequestArgs(), $this->getQuery(), $this);
}
/**
* 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(),
'queryId' => $this->getQuery()->getId(),
];
}
/**
* @copydoc GridHandler::loadData()
*
* Incomplete notes are hidden from everyone except
* the user who created them. These are considered
* in-progress and not yet saved.
*
* @see https://github.com/pkp/pkp-lib/issues/1155
*
* @param null|mixed $filter
*/
public function loadData($request, $filter = null)
{
return $this->getQuery()
->getReplies(null, NoteDAO::NOTE_ORDER_DATE_CREATED, \PKP\db\DAO::SORT_DIRECTION_ASC)
->filter(function (Note $note) use ($request) {
return (bool) $note->getContents() || (
$note->getUserId() === $request->getUser()->getId()
);
});
}
//
// Public Query Notes Grid Actions
//
/**
* Present the form to add a new note.
*
* @param array $args
* @param PKPRequest $request
*/
public function addNote($args, $request)
{
$queryNoteForm = new QueryNoteForm($this->getRequestArgs(), $this->getQuery(), $request->getUser());
$queryNoteForm->initData();
return new JSONMessage(true, $queryNoteForm->fetch($request));
}
/**
* Insert a new note.
*
* @param array $args
* @param PKPRequest $request
*/
public function insertNote($args, $request)
{
$queryNoteForm = new QueryNoteForm($this->getRequestArgs(), $this->getQuery(), $request->getUser(), $request->getUserVar('noteId'));
$queryNoteForm->readInputData();
if ($queryNoteForm->validate()) {
$note = $queryNoteForm->execute();
$this->insertedNoteNotify($note);
return \PKP\db\DAO::getDataChangedEvent($this->getQuery()->getId());
} else {
return new JSONMessage(true, $queryNoteForm->fetch($request));
}
}
/**
* Determine whether the current user can manage (delete) a note.
*
* @param Note $note optional
*
* @return bool
*/
public function getCanManage($note)
{
$isAdmin = (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]
)));
if ($note === null) {
return $isAdmin;
} else {
return ($note->getUserId() == $this->_user->getId() || $isAdmin);
}
}
/**
* Delete a query note.
*
* @param array $args
* @param PKPRequest $request
*
* @return JSONMessage JSON object
*/
public function deleteNote($args, $request)
{
$query = $this->getQuery();
$noteDao = DAORegistry::getDAO('NoteDAO'); /** @var NoteDAO $noteDao */
$note = $noteDao->getById($request->getUserVar('noteId'));
$user = $request->getUser();
if (!$request->checkCSRF() || !$note || $note->getAssocType() != Application::ASSOC_TYPE_QUERY || $note->getAssocId() != $query->getId()) {
// The note didn't exist or has the wrong assoc info.
return new JSONMessage(false);
}
if (!$this->getCanManage($note)) {
// The user doesn't own the note and isn't privileged enough to delete it.
return new JSONMessage(false);
}
$noteDao->deleteObject($note);
return \PKP\db\DAO::getDataChangedEvent($note->getId());
}
/**
* Sends notification and email to the query participants
*/
protected function insertedNoteNotify(Note $note): void
{
$notificationManager = new NotificationManager();
$notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */
$queryDao = DAORegistry::getDAO('QueryDAO'); /** @var QueryDAO $queryDao */
$query = $queryDao->getById($note->getData('assocId'));
$sender = Repo::user()->get($note->getData('userId'));
$request = Application::get()->getRequest();
$context = $request->getContext();
$submission = $this->getSubmission();
$title = $query->getHeadNote()->getData('title');
/** @var NotificationSubscriptionSettingsDAO $notificationSubscriptionSettingsDao */
$notificationSubscriptionSettingsDao = DAORegistry::getDAO('NotificationSubscriptionSettingsDAO');
// Find attachments if any
$submissionFiles = Repo::submissionFile()
->getCollector()
->filterByAssoc(
PKPApplication::ASSOC_TYPE_NOTE,
[$note->getId()]
)->filterBySubmissionIds([$submission->getId()])
->getMany();
foreach ($queryDao->getParticipantIds($query->getId()) as $userId) {
// Delete any prior notifications of the same type (e.g. prior "new" comments)
$notificationDao->deleteByAssoc(
PKPApplication::ASSOC_TYPE_QUERY,
$query->getId(),
$userId,
PKPNotification::NOTIFICATION_TYPE_QUERY_ACTIVITY,
$context->getId()
);
// No need to additionally notify the posting user.
if ($userId == $sender->getId()) {
continue;
}
// Notify the user of a new query.
$notification = $notificationManager->createNotification(
$request,
$userId,
PKPNotification::NOTIFICATION_TYPE_QUERY_ACTIVITY,
$request->getContext()->getId(),
PKPApplication::ASSOC_TYPE_QUERY,
$query->getId(),
Notification::NOTIFICATION_LEVEL_TASK
);
// Check if user is subscribed to this type of notification emails
if (!$notification || in_array(
PKPNotification::NOTIFICATION_TYPE_QUERY_ACTIVITY,
$notificationSubscriptionSettingsDao->getNotificationSubscriptionSettings(
NotificationSubscriptionSettingsDAO::BLOCKED_EMAIL_NOTIFICATION_KEY,
$userId,
(int) $context->getId()
)
)
) {
continue;
}
$recipient = Repo::user()->get($userId);
$mailable = $this->getStageMailable($context, $submission)
->sender($sender)
->recipients([$recipient])
->subject(__('common.re') . ' ' . $title)
->body($note->getContents())
->allowUnsubscribe($notification);
$submissionFiles->each(fn(SubmissionFile $item) => $mailable->attachSubmissionFile(
$item->getId(),
$item->getLocalizedData('name')
));
Mail::send($mailable);
}
}
}
|