• Main Page
  • Modules
  • Classes
  • Files
  • File List

controllers/wizard/fileUpload/FileUploadWizardHandler.inc.php

00001 <?php
00019 // Import the base handler.
00020 import('classes.file.FileManagementHandler');
00021 
00022 // Import JSON class for use with all AJAX requests.
00023 import('lib.pkp.classes.core.JSONMessage');
00024 
00025 // The percentage of characters that the name of a file
00026 // has to share with an existing file for it to be
00027 // considered as a revision of that file.
00028 define('SUBMISSION_MIN_SIMILARITY_OF_REVISION', 70);
00029 
00030 class FileUploadWizardHandler extends FileManagementHandler {
00032    var $_fileStage;
00033 
00035    var $_uploaderRoles;
00036 
00038    var $_revisionOnly;
00039 
00041    var $_reviewRound;
00042 
00044    var $_revisedFileId;
00045 
00047    var $_assocType;
00048 
00050    var $_assocId;
00051 
00052 
00056    function FileUploadWizardHandler() {
00057       parent::Handler();
00058       $this->addRoleAssignment(
00059          array(ROLE_ID_PRESS_MANAGER, ROLE_ID_SERIES_EDITOR, ROLE_ID_AUTHOR, ROLE_ID_REVIEWER, ROLE_ID_PRESS_ASSISTANT),
00060          array(
00061             'startWizard', 'displayFileUploadForm',
00062             'uploadFile', 'confirmRevision',
00063             'editMetadata', 'saveMetadata',
00064             'finishFileSubmission'
00065          )
00066       );
00067    }
00068 
00069 
00070    //
00071    // Implement template methods from PKPHandler
00072    //
00076    function initialize(&$request, $args) {
00077       parent::initialize($request, $args);
00078       // Configure the wizard with the authorized monograph and file stage.
00079       // Validated in authorize.
00080       $this->_fileStage = (int)$request->getUserVar('fileStage');
00081 
00082       // Set the uploader roles (if given).
00083       $uploaderRoles = $request->getUserVar('uploaderRoles');
00084       if (!is_null($uploaderRoles)) {
00085          $this->_uploaderRoles = array();
00086          $uploaderRoles = explode('-', $uploaderRoles);
00087          foreach($uploaderRoles as $uploaderRole) {
00088             if (!is_numeric($uploaderRole)) fatalError('Invalid uploader role!');
00089             $this->_uploaderRoles[] = (int)$uploaderRole;
00090          }
00091       }
00092 
00093       // Do we allow revisions only?
00094       $this->_revisionOnly = (boolean)$request->getUserVar('revisionOnly');
00095       $reviewRound =& $this->getReviewRound();
00096       $this->_assocType = $request->getUserVar('assocType') ? (int)$request->getUserVar('assocType') : null;
00097       $this->_assocId = $request->getUserVar('assocId') ? (int)$request->getUserVar('assocId') : null;
00098 
00099       // The revised file will be non-null if we revise a single existing file.
00100       if ($this->getRevisionOnly() && $request->getUserVar('revisedFileId')) {
00101          // Validated in authorize.
00102          $this->_revisedFileId = (int)$request->getUserVar('revisedFileId');
00103       }
00104 
00105       // Load translations.
00106       AppLocale::requireComponents(
00107          LOCALE_COMPONENT_OMP_SUBMISSION,
00108          LOCALE_COMPONENT_PKP_SUBMISSION,
00109          LOCALE_COMPONENT_PKP_COMMON,
00110          LOCALE_COMPONENT_APPLICATION_COMMON
00111       );
00112    }
00113 
00114    function authorize($request, $args, $roleAssignments) {
00115       // This is validated in parent's authorization policy.
00116       $stageId = (int)$request->getUserVar('stageId');
00117 
00118       // Authorize review round id when this handler is used in review stages.
00119       if ($stageId == WORKFLOW_STAGE_ID_INTERNAL_REVIEW || $stageId == WORKFLOW_STAGE_ID_EXTERNAL_REVIEW) {
00120          import('classes.security.authorization.internal.ReviewRoundRequiredPolicy');
00121          $this->addPolicy(new ReviewRoundRequiredPolicy($request, $args));
00122       }
00123 
00124       // We validate file stage outside a policy because
00125       // we don't need to validate in another places.
00126       $fileStage = $request->getUserVar('fileStage');
00127       if ($fileStage) {
00128          $submissionFileDao =& DAORegistry::getDAO('SubmissionFileDAO');
00129          $fileStages = $submissionFileDao->getAllFileStages();
00130          if (!in_array($fileStage, $fileStages)) {
00131             return false;
00132          }
00133       }
00134 
00135       // Validate file ids. We have two cases where we might have a file id.
00136       // CASE 1: user is uploading a revision to a file, the revised file id
00137       // will need validation.
00138       $revisedFileId = (int)$request->getUserVar('revisedFileId');
00139       // CASE 2: user already have uploaded a file (and it's editing the metadata),
00140       // we will need to validate the uploaded file id.
00141       $fileId = (int)$request->getUserVar('fileId');
00142       // Get the right one to validate.
00143       $fileIdToValidate = null;
00144       if ($revisedFileId && !$fileId) {
00145          $fileIdToValidate = $revisedFileId;
00146       } else if ($fileId && !$revisedFileId) {
00147          $fileIdToValidate = $fileId;
00148       } else if ($revisedFileId && $fileId) {
00149          // Those two cases will not happen at the same time.
00150          return false;
00151       }
00152       if ($fileIdToValidate) {
00153          import('classes.security.authorization.OmpMonographFileAccessPolicy');
00154          $this->addPolicy(new OmpMonographFileAccessPolicy($request, $args, $roleAssignments, MONOGRAPH_FILE_ACCESS_READ, $fileIdToValidate));
00155       }
00156 
00157       return parent::authorize($request, $args, $roleAssignments);
00158    }
00159 
00160 
00161    //
00162    // Getters and Setters
00163    //
00170    function getFileStage() {
00171       return $this->_fileStage;
00172    }
00173 
00178    function getUploaderRoles() {
00179       return $this->_uploaderRoles;
00180    }
00181 
00186    function getRevisionOnly() {
00187       return $this->_revisionOnly;
00188    }
00189 
00194    function &getReviewRound() {
00195       return $this->getAuthorizedContextObject(ASSOC_TYPE_REVIEW_ROUND);
00196    }
00197 
00202    function getRevisedFileId() {
00203       return $this->_revisedFileId;
00204    }
00205 
00210    function getAssocType() {
00211       return $this->_assocType;
00212    }
00213 
00218    function getAssocId() {
00219       return $this->_assocId;
00220    }
00221 
00222    //
00223    // Public handler methods
00224    //
00231    function startWizard($args, &$request) {
00232       $templateMgr =& TemplateManager::getManager();
00233 
00234       // Assign the monograph.
00235       $monograph =& $this->getMonograph();
00236       $templateMgr->assign('monographId', $monograph->getId());
00237 
00238       // Assign the workflow stage.
00239       $templateMgr->assign('stageId', $this->getStageId());
00240 
00241       // Assign the roles allowed to upload in the given context.
00242       $templateMgr->assign('uploaderRoles', implode('-', $this->getUploaderRoles()));
00243 
00244       // Assign the file stage.
00245       $templateMgr->assign('fileStage', $this->getFileStage());
00246 
00247       // Preserve the isReviewer flag
00248       $templateMgr->assign('isReviewer', $request->getUserVar('isReviewer'));
00249 
00250       // Configure the "revision only" feature.
00251       $templateMgr->assign('revisionOnly', $this->getRevisionOnly());
00252       $reviewRound =& $this->getReviewRound();
00253       if (is_a($reviewRound, 'ReviewRound')) {
00254          $templateMgr->assign('reviewRoundId', $reviewRound->getId());
00255       }
00256       $templateMgr->assign('revisedFileId', $this->getRevisedFileId());
00257       $templateMgr->assign('assocType', $this->getAssocType());
00258       $templateMgr->assign('assocId', $this->getAssocId());
00259 
00260       // Render the file upload wizard.
00261       return $templateMgr->fetchJson('controllers/wizard/fileUpload/fileUploadWizard.tpl');
00262    }
00263 
00270    function displayFileUploadForm($args, &$request) {
00271       // Instantiate, configure and initialize the form.
00272       import('controllers.wizard.fileUpload.form.SubmissionFilesUploadForm');
00273       $monograph =& $this->getMonograph();
00274       $fileForm = new SubmissionFilesUploadForm(
00275          $request, $monograph->getId(), $this->getStageId(), $this->getUploaderRoles(), $this->getFileStage(),
00276          $this->getRevisionOnly(), $this->getReviewRound(), $this->getRevisedFileId(),
00277          $this->getAssocType(), $this->getAssocId()
00278       );
00279       $fileForm->initData($args, $request);
00280 
00281       // Render the form.
00282       $json = new JSONMessage(true, $fileForm->fetch($request));
00283       return $json->getString();
00284    }
00285 
00292    function uploadFile($args, &$request, $fileModifyCallback = null) {
00293       // Instantiate the file upload form.
00294       $monograph =& $this->getMonograph();
00295       import('controllers.wizard.fileUpload.form.SubmissionFilesUploadForm');
00296       $uploadForm = new SubmissionFilesUploadForm(
00297          $request, $monograph->getId(), $this->getStageId(), null, $this->getFileStage(),
00298          $this->getRevisionOnly(), $this->getReviewRound(), null, $this->getAssocType(), $this->getAssocId()
00299       );
00300       $uploadForm->readInputData();
00301 
00302       // Validate the form and upload the file.
00303       if ($uploadForm->validate($request)) {
00304          if (is_a($uploadedFile =& $uploadForm->execute($request), 'MonographFile')) { /* @var $uploadedFile MonographFile */
00305             // Retrieve file info to be used in a JSON response.
00306             $uploadedFileInfo = $this->_getUploadedFileInfo($uploadedFile);
00307             $reviewRound =& $this->getReviewRound();
00308 
00309             // If no revised file id was given then try out whether
00310             // the user maybe accidentally didn't identify this file as a revision.
00311             if (!$uploadForm->getRevisedFileId()) {
00312                $revisedFileId = $this->_checkForRevision($uploadedFile, $uploadForm->getMonographFiles());
00313                if ($revisedFileId) {
00314                   // Instantiate the revision confirmation form.
00315                   import('controllers.wizard.fileUpload.form.SubmissionFilesUploadConfirmationForm');
00316                   $confirmationForm = new SubmissionFilesUploadConfirmationForm($request, $monograph->getId(), $this->getStageId(), $this->getFileStage(), $reviewRound, $revisedFileId, $this->getAssocType(), $this->getAssocId(), $uploadedFile);
00317                   $confirmationForm->initData($args, $request);
00318 
00319                   // Render the revision confirmation form.
00320                   $json = new JSONMessage(true, $confirmationForm->fetch($request), '0', $uploadedFileInfo);
00321                   return $json->getString();
00322                }
00323             }
00324 
00325             // Remove pending revisions task notification, if any.
00326             if ($uploadedFile->getFileStage() == MONOGRAPH_FILE_REVIEW_REVISION) {
00327                $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE);
00328                $notificationMgr = new NotificationManager(); /* @var $notificationMgr NotificationManager */
00329                $user =& $request->getUser();
00330                $notificationMgr->deletePendingRevisionsNotification($request, $monograph, $stageId, $user->getId());
00331                $notificationMgr->insertAllRevisionsInNotification($request, $reviewRound);
00332             }
00333 
00334             // Advance to the next step (i.e. meta-data editing).
00335             $json = new JSONMessage(true, '', '0', $uploadedFileInfo);
00336          } else {
00337             $json = new JSONMessage(false, __('common.uploadFailed'));
00338          }
00339       } else {
00340          $json = new JSONMessage(false, array_pop($uploadForm->getErrorsArray()));
00341       }
00342       return $json->getString();
00343    }
00344 
00352    function confirmRevision($args, &$request) {
00353       // Instantiate the revision confirmation form.
00354       $monograph =& $this->getMonograph();
00355       import('controllers.wizard.fileUpload.form.SubmissionFilesUploadConfirmationForm');
00356       // FIXME?: need assocType and assocId? Not sure if they would be used, so not adding now.
00357       $reviewRound =& $this->getReviewRound();
00358       $confirmationForm = new SubmissionFilesUploadConfirmationForm(
00359          $request, $monograph->getId(), $this->getStageId(), $this->getFileStage(), $reviewRound
00360       );
00361       $confirmationForm->readInputData();
00362 
00363       // Validate the form and revise the file.
00364       if ($confirmationForm->validate($request)) {
00365          if (is_a($uploadedFile =& $confirmationForm->execute($request), 'MonographFile')) {
00366             // Go to the meta-data editing step.
00367             $json = new JSONMessage(true, '', '0', $this->_getUploadedFileInfo($uploadedFile));
00368          } else {
00369             $json = new JSONMessage(false, __('common.uploadFailed'));
00370          }
00371       } else {
00372          $json = new JSONMessage(false, array_pop($confirmationForm->getErrorsArray()));
00373       }
00374       return $json->getString();
00375    }
00376 
00384    function editMetadata($args, &$request) {
00385       $metadataForm =& $this->_getMetadataForm($request);
00386       $metadataForm->initData($args, $request);
00387       $json = new JSONMessage(true, $metadataForm->fetch($request));
00388       return $json->getString();
00389    }
00390 
00398    function saveMetadata($args, &$request) {
00399       $metadataForm =& $this->_getMetadataForm($request);
00400       $metadataForm->readInputData();
00401       if ($metadataForm->validate()) {
00402          $metadataForm->execute($args, $request);
00403          $submissionFile =& $metadataForm->getSubmissionFile();
00404          return DAO::getDataChangedEvent();
00405       } else {
00406          $json = new JSONMessage(false, $metadataForm->fetch($request));
00407       }
00408       return $json->getString();
00409    }
00410 
00417    function finishFileSubmission($args, &$request) {
00418       $monograph =& $this->getMonograph();
00419 
00420       // Validation not req'd -- just generating a JSON update message.
00421       $fileId = (int)$request->getUserVar('fileId');
00422 
00423       $templateMgr =& TemplateManager::getManager();
00424       $templateMgr->assign('monographId', $monograph->getId());
00425       $templateMgr->assign('fileId', $fileId);
00426 
00427       return $templateMgr->fetchJson('controllers/wizard/fileUpload/form/fileSubmissionComplete.tpl');
00428    }
00429 
00430 
00431    //
00432    // Private helper methods
00433    //
00439    function &_getMetadataForm(&$request) {
00440       // Retrieve the authorized monograph.
00441       $monograph =& $this->getMonograph();
00442 
00443       // Retrieve the monograph file.
00444       $submissionFile =& $this->getAuthorizedContextObject(ASSOC_TYPE_MONOGRAPH_FILE);
00445 
00446       // Import the meta-data form based on the file implementation.
00447       if (is_a($submissionFile, 'ArtworkFile')) {
00448          import('controllers.wizard.fileUpload.form.SubmissionFilesArtworkMetadataForm');
00449          $metadataForm = new SubmissionFilesArtworkMetadataForm($submissionFile, $this->getStageId(), $this->getReviewRound());
00450       } else {
00451          import('controllers.wizard.fileUpload.form.SubmissionFilesMetadataForm');
00452          $metadataForm = new SubmissionFilesMetadataForm($submissionFile, $this->getStageId(), $this->getReviewRound());
00453       }
00454 
00455       return $metadataForm;
00456    }
00457 
00467    function &_checkForRevision(&$uploadedFile, &$monographFiles) {
00468       // Get the file name.
00469       $uploadedFileName = $uploadedFile->getOriginalFileName();
00470 
00471       // Start with the minimal required similarity.
00472       $minPercentage = SUBMISSION_MIN_SIMILARITY_OF_REVISION;
00473 
00474       // Find out whether one of the files belonging to the current
00475       // file stage matches the given file name.
00476       $possibleRevisedFileId = null;
00477       $matchedPercentage = 0;
00478       foreach ($monographFiles as $monographFile) { /* @var $monographFile MonographFile */
00479          // Do not consider the uploaded file itself.
00480          if ($uploadedFile->getFileId() == $monographFile->getFileId()) continue;
00481 
00482          // Do not consider files from different publication formats.
00483          if (($uploadedFile->getAssocType() == ASSOC_TYPE_PUBLICATION_FORMAT &&
00484             $monographFile->getAssocType() == ASSOC_TYPE_PUBLICATION_FORMAT) &&
00485             $uploadedFile->getAssocId() != $monographFile->getAssocId()) continue;
00486 
00487          // Test whether the current monograph file is similar
00488          // to the uploaded file. (Transliterate to ASCII -- the
00489          // similar_text function can't handle UTF-8.)
00490 
00491          import('lib.pkp.classes.core.Transcoder');
00492          $transcoder = new Transcoder('UTF-8', 'ASCII', true);
00493 
00494          similar_text(
00495             $a = $transcoder->trans($uploadedFileName),
00496             $b = $transcoder->trans($monographFile->getOriginalFileName()),
00497             $matchedPercentage
00498          );
00499          if($matchedPercentage > $minPercentage && !$this->_onlyNumbersDiffer($a, $b)) {
00500             // We found a file that might be a possible revision.
00501             $possibleRevisedFileId = $monographFile->getFileId();
00502 
00503             // Reset the min percentage to this comparison's precentage
00504             // so that only better matches will be considered from now on.
00505             $minPercentage = $matchedPercentage;
00506          }
00507       }
00508 
00509       // Return the id of the file that we found similar.
00510       return $possibleRevisedFileId;
00511    }
00512 
00521    function _onlyNumbersDiffer($a, $b) {
00522       if ($a == $b) return false;
00523 
00524       $pattern = '/([^0-9]*)([0-9]*)([^0-9]*)/';
00525       $aMatchCount = preg_match_all($pattern, $a, $aMatches, PREG_SET_ORDER);
00526       $bMatchCount = preg_match_all($pattern, $b, $bMatches, PREG_SET_ORDER);
00527       if ($aMatchCount != $bMatchCount || $aMatchCount == 0) return false;
00528 
00529       // Check each match. If the 1st and 3rd (text) parts all match
00530       // then only numbers differ in the two supplied strings.
00531       for ($i=0; $i<count($aMatches); $i++) {
00532          if ($aMatches[$i][1] != $bMatches[$i][1]) return false;
00533          if ($aMatches[$i][3] != $bMatches[$i][3]) return false;
00534       }
00535 
00536       // No counterexamples were found. Only numbers differ.
00537       return true;
00538    }
00539 
00546    function &_getUploadedFileInfo(&$uploadedFile) {
00547       $uploadedFileInfo = array(
00548          'uploadedFile' => array(
00549             'fileId' => $uploadedFile->getFileId(),
00550             'revision' => $uploadedFile->getRevision()
00551          )
00552       );
00553       return $uploadedFileInfo;
00554    }
00555 }
00556 
00557 ?>

Generated on Mon Sep 17 2012 13:58:56 for Open Monograph Press by  doxygen 1.7.1