Open Preprint Systems  3.3.0
PKPSubmissionService.inc.php
1 <?php
2 
16 namespace PKP\Services;
17 
18 use \Core;
19 use \DBResultRange;
20 use \Application;
21 use \DAOResultFactory;
22 use \DAORegistry;
23 use \Illuminate\Database\Capsule\Manager as Capsule;
24 use \Services;
25 use \PKP\Services\interfaces\EntityPropertyInterface;
26 use \PKP\Services\interfaces\EntityReadInterface;
27 use \PKP\Services\interfaces\EntityWriteInterface;
28 use \APP\Services\QueryBuilders\SubmissionQueryBuilder;
29 
30 define('STAGE_STATUS_SUBMISSION_UNASSIGNED', 1);
31 
32 abstract class PKPSubmissionService implements EntityPropertyInterface, EntityReadInterface, EntityWriteInterface {
33 
37  public function get($submissionId) {
38  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
39  return $submissionDao->getById($submissionId);
40  }
41 
49  public function getByUrlPath($urlPath, $contextId) {
50  $qb = new \PKP\Services\QueryBuilders\PKPPublicationQueryBuilder();
51  $firstResult = $qb->getQueryByUrlPath($urlPath, $contextId)->first();
52 
53  if (!$firstResult) {
54  return null;
55  }
56 
57  return $this->get($firstResult->submission_id);
58  }
59 
63  public function getCount($args = []) {
64  return $this->getQueryBuilder($args)->getCount();
65  }
66 
70  public function getIds($args = []) {
71  return $this->getQueryBuilder($args)->getIds();
72  }
73 
91  public function getMany($args = []) {
92  $range = null;
93  if (isset($args['count'])) {
94  import('lib.pkp.classes.db.DBResultRange');
95  $range = new \DBResultRange($args['count'], null, isset($args['offset']) ? $args['offset'] : 0);
96  }
97  // Pagination is handled by the DAO, so don't pass count and offset
98  // arguments to the QueryBuilder.
99  if (isset($args['count'])) unset($args['count']);
100  if (isset($args['offset'])) unset($args['offset']);
101  $submissionListQO = $this->getQueryBuilder($args)->getQuery();
102  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
103  $result = $submissionDao->retrieveRange($submissionListQO->toSql(), $submissionListQO->getBindings(), $range);
104  $queryResults = new DAOResultFactory($result, $submissionDao, '_fromRow');
105 
106  return $queryResults->toIterator();
107  }
108 
112  public function getMax($args = []) {
113  // Don't accept args to limit the results
114  if (isset($args['count'])) unset($args['count']);
115  if (isset($args['offset'])) unset($args['offset']);
116  return $this->getQueryBuilder($args)->getCount();
117  }
118 
123  public function getQueryBuilder($args = []) {
124 
125  $defaultArgs = array(
126  'contextId' => CONTEXT_ID_NONE,
127  'orderBy' => 'dateSubmitted',
128  'orderDirection' => 'DESC',
129  'assignedTo' => [],
130  'status' => null,
131  'stageIds' => null,
132  'searchPhrase' => null,
133  'isIncomplete' => false,
134  'isOverdue' => false,
135  'daysInactive' => null,
136  );
137 
138  $args = array_merge($defaultArgs, $args);
139 
140  $submissionListQB = new SubmissionQueryBuilder();
141  $submissionListQB
142  ->filterByContext($args['contextId'])
143  ->orderBy($args['orderBy'], $args['orderDirection'])
144  ->assignedTo($args['assignedTo'])
145  ->filterByStatus($args['status'])
146  ->filterByStageIds($args['stageIds'])
147  ->filterByIncomplete($args['isIncomplete'])
148  ->filterByOverdue($args['isOverdue'])
149  ->filterByDaysInactive($args['daysInactive'])
150  ->filterByCategories(isset($args['categoryIds'])?$args['categoryIds']:null)
151  ->searchPhrase($args['searchPhrase']);
152 
153  if (isset($args['count'])) {
154  $submissionListQB->limitTo($args['count']);
155  }
156 
157  if (isset($args['offset'])) {
158  $submissionListQB->offsetBy($args['count']);
159  }
160 
161  \HookRegistry::call('Submission::getMany::queryBuilder', array($submissionListQB, $args));
162 
163  return $submissionListQB;
164  }
165 
169  public function getProperties($submission, $props, $args = null) {
170  \AppLocale::requireComponents(LOCALE_COMPONENT_APP_SUBMISSION, LOCALE_COMPONENT_PKP_SUBMISSION);
171  $values = array();
172  $request = $args['request'];
173  $dispatcher = $request->getDispatcher();
174 
175  // Retrieve the submission's context for properties that require it
176  if (array_intersect(['_href', 'urlAuthorWorkflow', 'urlEditorialWorkflow'], $props)) {
177  $submissionContext = $request->getContext();
178  if (!$submissionContext || $submissionContext->getId() != $submission->getData('contextId')) {
179  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
180  }
181  }
182 
183  foreach ($props as $prop) {
184  switch ($prop) {
185  case '_href':
186  $values[$prop] = $dispatcher->url(
187  $request,
188  ROUTE_API,
189  $submissionContext->getData('urlPath'),
190  'submissions/' . $submission->getId()
191  );
192  break;
193  case 'publications':
194  $values[$prop] = array_map(
195  function($publication) use ($args, $submission, $submissionContext) {
196  return Services::get('publication')->getSummaryProperties(
197  $publication,
198  $args + [
199  'submission' => $submission,
200  'context' => $submissionContext,
201  'currentUserReviewAssignment' => DAORegistry::getDAO('ReviewAssignmentDAO')
202  ->getLastReviewRoundReviewAssignmentByReviewer(
203  $submission->getId(),
204  $args['request']->getUser()->getId()
205  ),
206  ]);
207  },
208  $submission->getData('publications')
209  );
210  break;
211  case 'reviewAssignments':
212  $values[$prop] = $this->getPropertyReviewAssignments($submission);
213  break;
214  case 'reviewRounds':
215  $values[$prop] = $this->getPropertyReviewRounds($submission);
216  break;
217  case 'stages':
218  $values[$prop] = $this->getPropertyStages($submission);
219  break;
220  case 'statusLabel':
221  $values[$prop] = __($submission->getStatusKey());
222  break;
223  case 'urlAuthorWorkflow':
224  $values[$prop] = $dispatcher->url(
225  $request,
226  ROUTE_PAGE,
227  $submissionContext->getData('urlPath'),
228  'authorDashboard',
229  'submission',
230  $submission->getId()
231  );
232  break;
233  case 'urlEditorialWorkflow':
234  $values[$prop] = $dispatcher->url(
235  $request,
236  ROUTE_PAGE,
237  $submissionContext->getData('urlPath'),
238  'workflow',
239  'access',
240  $submission->getId()
241  );
242  break;
243  case 'urlWorkflow':
244  $values[$prop] = $this->getWorkflowUrlByUserRoles($submission);
245  break;
246  default:
247  $values[$prop] = $submission->getData($prop);
248  break;
249  }
250  }
251 
252  $values = Services::get('schema')->addMissingMultilingualValues(SCHEMA_SUBMISSION, $values, $request->getContext()->getSupportedSubmissionLocales());
253 
254  \HookRegistry::call('Submission::getProperties::values', array(&$values, $submission, $props, $args));
255 
256  ksort($values);
257 
258  return $values;
259  }
260 
264  public function getSummaryProperties($submission, $args = null) {
265  $props = Services::get('schema')->getSummaryProps(SCHEMA_SUBMISSION);
266 
267  return $this->getProperties($submission, $props, $args);
268  }
269 
273  public function getFullProperties($submission, $args = null) {
274  $props = Services::get('schema')->getFullProps(SCHEMA_SUBMISSION);
275 
276  return $this->getProperties($submission, $props, $args);
277  }
278 
286  public function getBackendListProperties($submission, $args = null) {
287  \PluginRegistry::loadCategory('pubIds', true);
288 
289  $props = array (
290  '_href', 'contextId', 'currentPublicationId','dateLastActivity','dateSubmitted','id',
291  'lastModified','publications','reviewAssignments','reviewRounds','stageId','stages','status',
292  'statusLabel','submissionProgress','urlAuthorWorkflow','urlEditorialWorkflow','urlWorkflow','urlPublished',
293  );
294 
295  \HookRegistry::call('Submission::getBackendListProperties::properties', array(&$props, $submission, $args));
296 
297  return $this->getProperties($submission, $props, $args);
298  }
299 
306  public function getPropertyReviewAssignments($submission) {
307 
308  $reviewAssignments = $this->getReviewAssignments($submission);
309 
310  $reviews = array();
311  foreach($reviewAssignments as $reviewAssignment) {
312  // @todo for now, only show reviews that haven't been
313  // declined or cancelled
314  if ($reviewAssignment->getDeclined()) {
315  continue;
316  }
317 
318  $currentUser = \Application::get()->getRequest()->getUser();
319  $dateFormatShort = \Config::getVar('general', 'date_format_short');
320  $due = is_null($reviewAssignment->getDateDue()) ? null : strftime($dateFormatShort, strtotime($reviewAssignment->getDateDue()));
321  $responseDue = is_null($reviewAssignment->getDateResponseDue()) ? null : strftime($dateFormatShort, strtotime($reviewAssignment->getDateResponseDue()));
322 
323  $reviews[] = array(
324  'id' => (int) $reviewAssignment->getId(),
325  'isCurrentUserAssigned' => $currentUser->getId() == (int) $reviewAssignment->getReviewerId(),
326  'statusId' => (int) $reviewAssignment->getStatus(),
327  'status' => __($reviewAssignment->getStatusKey()),
328  'due' => $due,
329  'responseDue' => $responseDue,
330  'round' => (int) $reviewAssignment->getRound(),
331  'roundId' => (int) $reviewAssignment->getReviewRoundId(),
332  );
333  }
334 
335  return $reviews;
336  }
337 
345  public function getPropertyReviewRounds($submission) {
346 
347  $reviewRounds = $this->getReviewRounds($submission);
348 
349  $rounds = array();
350  foreach ($reviewRounds as $reviewRound) {
351  $rounds[] = array(
352  'id' => $reviewRound->getId(),
353  'round' => $reviewRound->getRound(),
354  'stageId' => $reviewRound->getStageId(),
355  'statusId' => $reviewRound->determineStatus(),
356  'status' => __($reviewRound->getStatusKey()),
357  );
358  }
359 
360  return $rounds;
361  }
362 
388  public function getPropertyStages($submission, $stageIds = null) {
389 
390  if (is_null($stageIds)) {
391  $stageIds = Application::get()->getApplicationStages();
392  } elseif (is_int($stageIds)) {
393  $stageIds = array($stageIds);
394  }
395 
396  $currentUser = \Application::get()->getRequest()->getUser();
397  $context = \Application::get()->getRequest()->getContext();
398  $contextId = $context ? $context->getId() : CONTEXT_ID_NONE;
399 
400  $stages = array();
401  foreach ($stageIds as $stageId) {
402 
403  import('lib.pkp.classes.workflow.WorkflowStageDAO');
404  $workflowStageDao = DAORegistry::getDAO('WorkflowStageDAO'); /* @var $workflowStageDao WorkflowStageDAO */
405  $stage = array(
406  'id' => (int) $stageId,
407  'label' => __($workflowStageDao->getTranslationKeyFromId($stageId)),
408  'isActiveStage' => $submission->getStageId() == $stageId,
409  );
410 
411  // Discussions in this stage
412  $stage['queries'] = array();
413  $request = Application::get()->getRequest();
414  import('lib.pkp.classes.query.QueryDAO');
415  $queryDao = DAORegistry::getDAO('QueryDAO'); /* @var $queryDao QueryDAO */
416  $queries = $queryDao->getByAssoc(
417  ASSOC_TYPE_SUBMISSION,
418  $submission->getId(),
419  $stageId,
420  $request->getUser()->getId() // Current user restriction should prevent unauthorized access
421  );
422 
423  while ($query = $queries->next()) {
424  $stage['queries'][] = array(
425  'id' => (int) $query->getId(),
426  'assocType' => (int) $query->getAssocType(),
427  'assocId' => (int) $query->getAssocId(),
428  'stageId' => $stageId,
429  'seq' => (int) $query->getSequence(),
430  'closed' => (bool) $query->getIsClosed(),
431  );
432  }
433 
434  $currentUserAssignedRoles = array();
435  if ($currentUser) {
436  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
437  $stageAssignmentsResult = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId($submission->getId(), $currentUser->getId(), $stageId);
438  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
439  while ($stageAssignment = $stageAssignmentsResult->next()) {
440  $userGroup = $userGroupDao->getById($stageAssignment->getUserGroupId(), $contextId);
441  $currentUserAssignedRoles[] = (int) $userGroup->getRoleId();
442  }
443  }
444  $stage['currentUserAssignedRoles'] = array_values(array_unique($currentUserAssignedRoles));
445 
446  // Stage-specific statuses
447  switch ($stageId) {
448 
449  case WORKFLOW_STAGE_ID_SUBMISSION:
450  import('lib.pkp.classes.stageAssignment.StageAssignmentDAO');
451  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
452  $assignedEditors = $stageAssignmentDao->editorAssignedToStage($submission->getId(), $stageId);
453  if (!$assignedEditors) {
454  $stage['statusId'] = STAGE_STATUS_SUBMISSION_UNASSIGNED;
455  $stage['status'] = __('submissions.queuedUnassigned');
456  }
457 
458  // Submission stage never has revisions
459  $stage['files'] = array(
460  'count' => 0,
461  );
462  break;
463 
464  case WORKFLOW_STAGE_ID_INTERNAL_REVIEW:
465  case WORKFLOW_STAGE_ID_EXTERNAL_REVIEW:
466  import('lib.pkp.classes.submission.reviewRound.ReviewRoundDAO');
467  $reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /* @var $reviewRoundDao ReviewRoundDAO */
468  $reviewRound = $reviewRoundDao->getLastReviewRoundBySubmissionId($submission->getId(), $stageId);
469  if ($reviewRound) {
470  $stage['statusId'] = $reviewRound->determineStatus();
471  $stage['status'] = __($reviewRound->getStatusKey());
472 
473  // Revision files in this round.
474  import('lib.pkp.classes.submission.SubmissionFile');
475  $submissionFileDao = DAORegistry::getDAO('SubmissionFileDAO'); /* @var $submissionFileDao SubmissionFileDAO */
476  $submissionFiles = $submissionFileDao->getRevisionsByReviewRound($reviewRound, SUBMISSION_FILE_REVIEW_REVISION);
477  $stage['files'] = array(
478  'count' => count($submissionFiles),
479  );
480 
481  // See if the curent user can only recommend:
482  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
483  $user = $request->getUser();
484  $editorsStageAssignments = $stageAssignmentDao->getEditorsAssignedToStage($submission->getId(), $stageId);
485  // if the user is assigned several times in the editorial role, and
486  // one of the assignments have recommendOnly option set, consider it here
487  $stage['currentUserCanRecommendOnly'] = false;
488  foreach ($editorsStageAssignments as $editorsStageAssignment) {
489  if ($editorsStageAssignment->getUserId() == $user->getId() && $editorsStageAssignment->getRecommendOnly()) {
490  $stage['currentUserCanRecommendOnly'] = true;
491  break;
492  }
493  }
494  } else {
495  // workaround for pkp/pkp-lib#4231, pending formal data model
496  $stage['files'] = array(
497  'count' => 0
498  );
499  }
500  break;
501 
502  // Get revision files for editing and production stages.
503  // Review rounds are handled separately in the review stage below.
504  case WORKFLOW_STAGE_ID_EDITING:
505  case WORKFLOW_STAGE_ID_PRODUCTION:
506  import('lib.pkp.classes.submission.SubmissionFile'); // Import constants
507  $submissionFileDao = DAORegistry::getDAO('SubmissionFileDAO'); /* @var $submissionFileDao SubmissionFileDAO */
508  $fileStageIId = $stageId === WORKFLOW_STAGE_ID_EDITING ? SUBMISSION_FILE_COPYEDIT : SUBMISSION_FILE_PROOF;
509  $submissionFiles = $submissionFileDao->getLatestRevisions($submission->getId(), $fileStageIId);
510  $stage['files'] = array(
511  'count' => count($submissionFiles),
512  );
513  break;
514  }
515 
516  $stages[] = $stage;
517  }
518 
519  return $stages;
520  }
521 
535  public function getWorkflowUrlByUserRoles($submission, $userId = null) {
536 
537  $request = Application::get()->getRequest();
538 
539  if (is_null($userId)) {
540  $user = $request->getUser();
541  } else {
542  $userDao = DAORegistry::getDAO('UserDAO'); /* @var $userDao UserDAO */
543  $user = $userDao->getById($userId);
544  }
545 
546  if (is_null($user)) {
547  return false;
548  }
549 
550  $submissionContext = $request->getContext();
551 
552  if (!$submissionContext || $submissionContext->getId() != $submission->getData('contextId')) {
553  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
554  }
555 
556  $dispatcher = $request->getDispatcher();
557 
558  // Check if the user is an author of this submission
559  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
560  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
561  $authorUserGroupIds = $userGroupDao->getUserGroupIdsByRoleId(ROLE_ID_AUTHOR);
562  $stageAssignmentsFactory = $stageAssignmentDao->getBySubmissionAndStageId($submission->getId(), null, null, $user->getId());
563 
564  $authorDashboard = false;
565  while ($stageAssignment = $stageAssignmentsFactory->next()) {
566  if (in_array($stageAssignment->getUserGroupId(), $authorUserGroupIds)) {
567  $authorDashboard = true;
568  }
569  }
570 
571  // Send authors, journal managers and site admins to the submission
572  // wizard for incomplete submissions
573  if ($submission->getSubmissionProgress() > 0 &&
574  ($authorDashboard ||
575  $user->hasRole(array(ROLE_ID_MANAGER), $submissionContext->getId()) ||
576  $user->hasRole(array(ROLE_ID_SITE_ADMIN), CONTEXT_SITE))) {
577  return $dispatcher->url(
578  $request,
579  ROUTE_PAGE,
580  $submissionContext->getPath(),
581  'submission',
582  'wizard',
583  $submission->getSubmissionProgress(),
584  array('submissionId' => $submission->getId())
585  );
586  }
587 
588  // Send authors to author dashboard
589  if ($authorDashboard) {
590  return $dispatcher->url(
591  $request,
592  ROUTE_PAGE,
593  $submissionContext->getPath(),
594  'authorDashboard',
595  'submission',
596  $submission->getId()
597  );
598  }
599 
600  // Send reviewers to review wizard
601  $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /* @var $reviewAssignmentDao ReviewAssignmentDAO */
602  $reviewAssignment = $reviewAssignmentDao->getLastReviewRoundReviewAssignmentByReviewer($submission->getId(), $user->getId());
603  if ($reviewAssignment) {
604  return $dispatcher->url(
605  $request,
606  ROUTE_PAGE,
607  $submissionContext->getPath(),
608  'reviewer',
609  'submission',
610  $submission->getId()
611  );
612  }
613 
614  // Give any other users the editorial workflow URL. If they can't access
615  // it, they'll be blocked there.
616  return $dispatcher->url(
617  $request,
618  ROUTE_PAGE,
619  $submissionContext->getPath(),
620  'workflow',
621  'access',
622  $submission->getId()
623  );
624  }
625 
632  public function canCurrentUserDelete($submission) {
633 
634  if (!is_a($submission, 'Submission')) {
635  $submission = $this->get((int) $submission);
636  if (!$submission) {
637  return false;
638  }
639  }
640 
641  $request = Application::get()->getRequest();
642  $contextId = $submission->getContextId();
643 
644  $currentUser = $request->getUser();
645  if (!$currentUser) {
646  return false;
647  }
648 
649  $canDelete = false;
650 
651  // Only allow admins and journal managers to delete submissions, except
652  // for authors who can delete their own incomplete submissions
653  if ($currentUser->hasRole(array(ROLE_ID_MANAGER), $contextId) || $currentUser->hasRole(array(ROLE_ID_SITE_ADMIN), CONTEXT_SITE)) {
654  $canDelete = true;
655  } else {
656  if ($submission->getSubmissionProgress() != 0 ) {
657  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
658  $assignments = $stageAssignmentDao->getBySubmissionAndRoleId($submission->getId(), ROLE_ID_AUTHOR, WORKFLOW_STAGE_ID_SUBMISSION, $currentUser->getId());
659  $assignment = $assignments->next();
660  if ($assignment) {
661  $canDelete = true;
662  }
663  }
664  }
665 
666  return $canDelete;
667  }
668 
675  public function getReviewRounds($submission) {
676  $reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /* @var $reviewRoundDao ReviewRoundDAO */
677  return $reviewRoundDao->getBySubmissionId($submission->getId())->toIterator();
678  }
679 
686  public function getReviewAssignments($submission) {
687  import('lib.pkp.classes.submission.reviewAssignment.ReviewAssignmentDAO');
688  $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /* @var $reviewAssignmentDao ReviewAssignmentDAO */
689  return $reviewAssignmentDao->getBySubmissionId($submission->getId());
690  }
691 
695  public function validate($action, $props, $allowedLocales, $primaryLocale) {
696  $schemaService = Services::get('schema');
697 
698  import('lib.pkp.classes.validation.ValidatorFactory');
699  $validator = \ValidatorFactory::make(
700  $props,
701  $schemaService->getValidationRules(SCHEMA_SUBMISSION, $allowedLocales)
702  );
703 
704  // Check required fields
706  $validator,
707  $action,
708  $schemaService->getRequiredProps(SCHEMA_SUBMISSION),
709  $schemaService->getMultilingualProps(SCHEMA_SUBMISSION),
710  $primaryLocale,
711  $allowedLocales
712  );
713 
714  // Check for input from disallowed locales
715  \ValidatorFactory::allowedLocales($validator, $schemaService->getMultilingualProps(SCHEMA_SUBMISSION), $allowedLocales);
716 
717  // The contextId must match an existing context
718  $validator->after(function($validator) use ($props) {
719  if (isset($props['contextid']) && !$validator->errors()->get('contextid')) {
720  $submissionContext = Services::get('context')->get($props['contextid']);
721  if (!$submissionContext) {
722  $validator->errors()->add('contextId', __('submission.submit.noContext'));
723  }
724  }
725  });
726 
727  if ($validator->fails()) {
728  $errors = $schemaService->formatValidationErrors($validator->errors(), $schemaService->get(SCHEMA_SUBMISSION), $allowedLocales);
729  }
730 
731  \HookRegistry::call('Submission::validate', [&$errors, $action, $props, $allowedLocales, $primaryLocale]);
732 
733  return $errors;
734  }
735 
739  public function add($submission, $request) {
740  $submission->stampLastActivity();
741  $submission->stampModified();
742  if (!$submission->getData('dateSubmitted') && !$submission->getData('submissionProgress')) {
743  $submission->setData('dateSubmitted', Core::getCurrentDate());
744  }
745  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
746  $submissionId = $submissionDao->insertObject($submission);
747  $submission = $this->get($submissionId);
748 
749  \HookRegistry::call('Submission::add', [$submission, $request]);
750 
751  return $submission;
752  }
753 
757  public function edit($submission, $params, $request) {
758  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
759 
760  $newSubmission = $submissionDao->newDataObject();
761  $newSubmission->_data = array_merge($submission->_data, $params);
762  $submission->stampLastActivity();
763  $submission->stampModified();
764 
765  \HookRegistry::call('Submission::edit', [$newSubmission, $submission, $params, $request]);
766 
767  $submissionDao->updateObject($newSubmission);
768  $newSubmission = $this->get($newSubmission->getId());
769 
770  return $newSubmission;
771  }
772 
776  public function delete($submission) {
777  \HookRegistry::call('Submission::delete::before', [$submission]);
778 
779  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
780  $submissionDao->deleteObject($submission);
781 
782  \HookRegistry::call('Submission::delete', [$submission]);
783  }
784 
792  public function canEditPublication($submissionId, $userId) {
793  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
794  $stageAssignments = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId($submissionId, $userId, null);
795  // Check for permission from stage assignments
796  while ($stageAssignment = $stageAssignments->next()) {
797  if ($stageAssignment->getCanChangeMetadata()) {
798  return true;
799  }
800  }
801  // If user has no stage assigments, check if user can edit anyway ie. is manager
802  $context = Application::get()->getRequest()->getContext();
803  if ($stageAssignments->wasEmpty() && $this->_canUserAccessUnassignedSubmissions($context->getId(), $userId)){
804  return true;
805  }
806  // Else deny access
807  return false;
808  }
809 
816  private static function _canUserAccessUnassignedSubmissions($contextId, $userId) {
817  $roleDao = DAORegistry::getDAO('RoleDAO'); /* @var $roleDao RoleDAO */
818  $roles = $roleDao->getByUserId($userId, $contextId);
819  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
820  $allowedRoles = $userGroupDao->getNotChangeMetadataEditPermissionRoles();
821  foreach ($roles as $role) {
822  if (in_array($role->getRoleId(), $allowedRoles))
823  return true;
824  }
825  return false;
826  }
827 
837  public function updateStatus($submission) {
838  $status = $newStatus = $submission->getData('status');
839  $currentPublicationId = $submission->getData('currentPublicationId');
840  $publications = $submission->getData('publications');
841 
842  // There should always be at least one publication for a submission. If
843  // not, an error has occurred in the code and will cause problems.
844  if (empty($publications)) {
845  throw new \Exception('Tried to update the status of submission ' . $submission->getId() . ' and no publications were found.');
846  }
847 
848  // Get the new current publication after status changes or deletions
849  // Use the latest published publication or, failing that, the latest publication
850  $newCurrentPublicationId = array_reduce($publications, function($a, $b) {
851  return $b->getData('status') === STATUS_PUBLISHED && $b->getId() > $a ? $b->getId() : $a;
852  }, 0);
853  if (!$newCurrentPublicationId) {
854  $newCurrentPublicationId = array_reduce($publications, function($a, $b) {
855  return $a > $b->getId() ? $a : $b->getId();
856  }, 0);
857  }
858 
859  // Declined submissions should remain declined even if their
860  // publications change
861  if ($status !== STATUS_DECLINED) {
862  $newStatus = STATUS_QUEUED;
863  foreach ($publications as $publication) {
864  if ($publication->getData('status') === STATUS_PUBLISHED) {
865  $newStatus = STATUS_PUBLISHED;
866  break;
867  }
868  if ($publication->getData('status') === STATUS_SCHEDULED) {
869  $newStatus = STATUS_SCHEDULED;
870  continue;
871  }
872  }
873  }
874 
875  \HookRegistry::call('Submission::updateStatus', [&$status, $submission]);
876 
877  $updateParams = [];
878  if ($status !== $newStatus) {
879  $updateParams['status'] = $newStatus;
880  }
881  if ($currentPublicationId !== $newCurrentPublicationId) {
882  $updateParams['currentPublicationId'] = $newCurrentPublicationId;
883  }
884  if (!empty($updateParams)) {
885  $submission = $this->edit($submission, $updateParams, Application::get()->getRequest());
886  }
887 
888  return $submission;
889  }
890 }
PKP\Services
AppLocale\requireComponents
static requireComponents()
Definition: env1/MockAppLocale.inc.php:56
DAOResultFactory
Wrapper around ADORecordSet providing "factory" features for generating objects from DAOs.
Definition: DAOResultFactory.inc.php:21
PKP\Services\SCHEMA_SUBMISSION
const SCHEMA_SUBMISSION
Definition: PKPSchemaService.inc.php:28
DAORegistry\getDAO
static & getDAO($name, $dbconn=null)
Definition: DAORegistry.inc.php:57
PKP\Services\PKPSubmissionService\getReviewAssignments
getReviewAssignments($submission)
Definition: PKPSubmissionService.inc.php:686
PKP\Services\PKPSubmissionService\validate
validate($action, $props, $allowedLocales, $primaryLocale)
Definition: PKPSubmissionService.inc.php:695
PKP\Services\PKPSubmissionService\getWorkflowUrlByUserRoles
getWorkflowUrlByUserRoles($submission, $userId=null)
Definition: PKPSubmissionService.inc.php:535
PKP\Services\PKPSubmissionService\getBackendListProperties
getBackendListProperties($submission, $args=null)
Definition: PKPSubmissionService.inc.php:286
PKP\Services\PKPSubmissionService\getByUrlPath
getByUrlPath($urlPath, $contextId)
Definition: PKPSubmissionService.inc.php:49
ValidatorFactory\allowedLocales
static allowedLocales($validator, $multilingualProps, $allowedLocales)
Definition: ValidatorFactory.inc.php:320
PKP\Services\PKPSubmissionService\getMax
getMax($args=[])
Definition: PKPSubmissionService.inc.php:112
PKP\Services\PKPSubmissionService\edit
edit($submission, $params, $request)
Definition: PKPSubmissionService.inc.php:757
PKP\Services\PKPSubmissionService\getPropertyReviewAssignments
getPropertyReviewAssignments($submission)
Definition: PKPSubmissionService.inc.php:306
ValidatorFactory\required
static required($validator, $action, $requiredProps, $multilingualProps, $allowedLocales, $primaryLocale)
Definition: ValidatorFactory.inc.php:261
PluginRegistry\loadCategory
static loadCategory($category, $enabledOnly=false, $mainContextId=null)
Definition: PluginRegistry.inc.php:103
PKP\Services\PKPSubmissionService\getProperties
getProperties($submission, $props, $args=null)
Definition: PKPSubmissionService.inc.php:169
PKP\Services\PKPSubmissionService
Definition: PKPSubmissionService.inc.php:32
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
ValidatorFactory\make
static make($props, $rules, $messages=[])
Definition: ValidatorFactory.inc.php:38
PKP\Services\PKPSubmissionService\getReviewRounds
getReviewRounds($submission)
Definition: PKPSubmissionService.inc.php:675
PKP\Services\PKPSubmissionService\getSummaryProperties
getSummaryProperties($submission, $args=null)
Definition: PKPSubmissionService.inc.php:264
PKP\Services\PKPSubmissionService\getPropertyReviewRounds
getPropertyReviewRounds($submission)
Definition: PKPSubmissionService.inc.php:345
PKP\Services\PKPSubmissionService\getMany
getMany($args=[])
Definition: PKPSubmissionService.inc.php:91
PKP\Services\PKPSubmissionService\getCount
getCount($args=[])
Definition: PKPSubmissionService.inc.php:63
PKP\Services\STAGE_STATUS_SUBMISSION_UNASSIGNED
const STAGE_STATUS_SUBMISSION_UNASSIGNED
Definition: PKPSubmissionService.inc.php:30
PKP\Services\PKPSubmissionService\getQueryBuilder
getQueryBuilder($args=[])
Definition: PKPSubmissionService.inc.php:123
PKP\Services\PKPSubmissionService\updateStatus
updateStatus($submission)
Definition: PKPSubmissionService.inc.php:837
Core\getCurrentDate
static getCurrentDate($ts=null)
Definition: Core.inc.php:63
PKP\Services\PKPSubmissionService\getFullProperties
getFullProperties($submission, $args=null)
Definition: PKPSubmissionService.inc.php:273
PKP\Services\PKPSubmissionService\canCurrentUserDelete
canCurrentUserDelete($submission)
Definition: PKPSubmissionService.inc.php:632
PKP\Services\PKPSubmissionService\canEditPublication
canEditPublication($submissionId, $userId)
Definition: PKPSubmissionService.inc.php:792
PKPApplication\get
static get()
Definition: PKPApplication.inc.php:235
HookRegistry\call
static call($hookName, $args=null)
Definition: HookRegistry.inc.php:86
PKP\Services\PKPSubmissionService\add
add($submission, $request)
Definition: PKPSubmissionService.inc.php:739
PKP\Services\PKPSubmissionService\getPropertyStages
getPropertyStages($submission, $stageIds=null)
Definition: PKPSubmissionService.inc.php:388
PKP\Services\PKPSubmissionService\getIds
getIds($args=[])
Definition: PKPSubmissionService.inc.php:70
PKPServices\get
static get($service)
Definition: PKPServices.inc.php:49
APP\Services\QueryBuilders\SubmissionQueryBuilder
Definition: SubmissionQueryBuilder.inc.php:20