308 lines
11 KiB
PHP
308 lines
11 KiB
PHP
<?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;
|
|
}
|
|
}
|