first commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user