Open Journal 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  $request = \Application::get()->getRequest();
319  $currentUser = $request->getUser();
320  $context = $request->getContext();
321  $dateFormatShort = $context->getLocalizedDateFormatShort();
322  $due = is_null($reviewAssignment->getDateDue()) ? null : strftime($dateFormatShort, strtotime($reviewAssignment->getDateDue()));
323  $responseDue = is_null($reviewAssignment->getDateResponseDue()) ? null : strftime($dateFormatShort, strtotime($reviewAssignment->getDateResponseDue()));
324 
325  $reviews[] = array(
326  'id' => (int) $reviewAssignment->getId(),
327  'isCurrentUserAssigned' => $currentUser->getId() == (int) $reviewAssignment->getReviewerId(),
328  'statusId' => (int) $reviewAssignment->getStatus(),
329  'status' => __($reviewAssignment->getStatusKey()),
330  'due' => $due,
331  'responseDue' => $responseDue,
332  'round' => (int) $reviewAssignment->getRound(),
333  'roundId' => (int) $reviewAssignment->getReviewRoundId(),
334  );
335  }
336 
337  return $reviews;
338  }
339 
347  public function getPropertyReviewRounds($submission) {
348 
349  $reviewRounds = $this->getReviewRounds($submission);
350 
351  $rounds = array();
352  foreach ($reviewRounds as $reviewRound) {
353  $rounds[] = array(
354  'id' => $reviewRound->getId(),
355  'round' => $reviewRound->getRound(),
356  'stageId' => $reviewRound->getStageId(),
357  'statusId' => $reviewRound->determineStatus(),
358  'status' => __($reviewRound->getStatusKey()),
359  );
360  }
361 
362  return $rounds;
363  }
364 
390  public function getPropertyStages($submission, $stageIds = null) {
391 
392  if (is_null($stageIds)) {
393  $stageIds = Application::get()->getApplicationStages();
394  } elseif (is_int($stageIds)) {
395  $stageIds = array($stageIds);
396  }
397 
398  $currentUser = \Application::get()->getRequest()->getUser();
399  $context = \Application::get()->getRequest()->getContext();
400  $contextId = $context ? $context->getId() : CONTEXT_ID_NONE;
401 
402  $stages = array();
403  foreach ($stageIds as $stageId) {
404 
405  import('lib.pkp.classes.workflow.WorkflowStageDAO');
406  $workflowStageDao = DAORegistry::getDAO('WorkflowStageDAO'); /* @var $workflowStageDao WorkflowStageDAO */
407  $stage = array(
408  'id' => (int) $stageId,
409  'label' => __($workflowStageDao->getTranslationKeyFromId($stageId)),
410  'isActiveStage' => $submission->getStageId() == $stageId,
411  );
412 
413  // Discussions in this stage
414  $stage['queries'] = array();
415  $request = Application::get()->getRequest();
416  import('lib.pkp.classes.query.QueryDAO');
417  $queryDao = DAORegistry::getDAO('QueryDAO'); /* @var $queryDao QueryDAO */
418  $queries = $queryDao->getByAssoc(
419  ASSOC_TYPE_SUBMISSION,
420  $submission->getId(),
421  $stageId,
422  $request->getUser()->getId() // Current user restriction should prevent unauthorized access
423  );
424 
425  while ($query = $queries->next()) {
426  $stage['queries'][] = array(
427  'id' => (int) $query->getId(),
428  'assocType' => (int) $query->getAssocType(),
429  'assocId' => (int) $query->getAssocId(),
430  'stageId' => $stageId,
431  'seq' => (int) $query->getSequence(),
432  'closed' => (bool) $query->getIsClosed(),
433  );
434  }
435 
436  $currentUserAssignedRoles = array();
437  if ($currentUser) {
438  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
439  $stageAssignmentsResult = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId($submission->getId(), $currentUser->getId(), $stageId);
440  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
441  while ($stageAssignment = $stageAssignmentsResult->next()) {
442  $userGroup = $userGroupDao->getById($stageAssignment->getUserGroupId(), $contextId);
443  $currentUserAssignedRoles[] = (int) $userGroup->getRoleId();
444  }
445  }
446  $stage['currentUserAssignedRoles'] = array_values(array_unique($currentUserAssignedRoles));
447 
448  // Stage-specific statuses
449  switch ($stageId) {
450 
451  case WORKFLOW_STAGE_ID_SUBMISSION:
452  import('lib.pkp.classes.stageAssignment.StageAssignmentDAO');
453  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
454  $assignedEditors = $stageAssignmentDao->editorAssignedToStage($submission->getId(), $stageId);
455  if (!$assignedEditors) {
456  $stage['statusId'] = STAGE_STATUS_SUBMISSION_UNASSIGNED;
457  $stage['status'] = __('submissions.queuedUnassigned');
458  }
459 
460  // Submission stage never has revisions
461  $stage['files'] = array(
462  'count' => 0,
463  );
464  break;
465 
466  case WORKFLOW_STAGE_ID_INTERNAL_REVIEW:
467  case WORKFLOW_STAGE_ID_EXTERNAL_REVIEW:
468  import('lib.pkp.classes.submission.reviewRound.ReviewRoundDAO');
469  $reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /* @var $reviewRoundDao ReviewRoundDAO */
470  $reviewRound = $reviewRoundDao->getLastReviewRoundBySubmissionId($submission->getId(), $stageId);
471  if ($reviewRound) {
472  $stage['statusId'] = $reviewRound->determineStatus();
473  $stage['status'] = __($reviewRound->getStatusKey());
474 
475  // Revision files in this round.
476  import('lib.pkp.classes.submission.SubmissionFile');
477  $submissionFileDao = DAORegistry::getDAO('SubmissionFileDAO'); /* @var $submissionFileDao SubmissionFileDAO */
478  $submissionFiles = $submissionFileDao->getRevisionsByReviewRound($reviewRound, SUBMISSION_FILE_REVIEW_REVISION);
479  $stage['files'] = array(
480  'count' => count($submissionFiles),
481  );
482 
483  // See if the curent user can only recommend:
484  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
485  $user = $request->getUser();
486  $editorsStageAssignments = $stageAssignmentDao->getEditorsAssignedToStage($submission->getId(), $stageId);
487  // if the user is assigned several times in the editorial role, and
488  // one of the assignments have recommendOnly option set, consider it here
489  $stage['currentUserCanRecommendOnly'] = false;
490  foreach ($editorsStageAssignments as $editorsStageAssignment) {
491  if ($editorsStageAssignment->getUserId() == $user->getId() && $editorsStageAssignment->getRecommendOnly()) {
492  $stage['currentUserCanRecommendOnly'] = true;
493  break;
494  }
495  }
496  } else {
497  // workaround for pkp/pkp-lib#4231, pending formal data model
498  $stage['files'] = array(
499  'count' => 0
500  );
501  }
502  break;
503 
504  // Get revision files for editing and production stages.
505  // Review rounds are handled separately in the review stage below.
506  case WORKFLOW_STAGE_ID_EDITING:
507  case WORKFLOW_STAGE_ID_PRODUCTION:
508  import('lib.pkp.classes.submission.SubmissionFile'); // Import constants
509  $submissionFileDao = DAORegistry::getDAO('SubmissionFileDAO'); /* @var $submissionFileDao SubmissionFileDAO */
510  $fileStageIId = $stageId === WORKFLOW_STAGE_ID_EDITING ? SUBMISSION_FILE_COPYEDIT : SUBMISSION_FILE_PROOF;
511  $submissionFiles = $submissionFileDao->getLatestRevisions($submission->getId(), $fileStageIId);
512  $stage['files'] = array(
513  'count' => count($submissionFiles),
514  );
515  break;
516  }
517 
518  $stages[] = $stage;
519  }
520 
521  return $stages;
522  }
523 
537  public function getWorkflowUrlByUserRoles($submission, $userId = null) {
538 
539  $request = Application::get()->getRequest();
540 
541  if (is_null($userId)) {
542  $user = $request->getUser();
543  } else {
544  $userDao = DAORegistry::getDAO('UserDAO'); /* @var $userDao UserDAO */
545  $user = $userDao->getById($userId);
546  }
547 
548  if (is_null($user)) {
549  return false;
550  }
551 
552  $submissionContext = $request->getContext();
553 
554  if (!$submissionContext || $submissionContext->getId() != $submission->getData('contextId')) {
555  $submissionContext = Services::get('context')->get($submission->getData('contextId'));
556  }
557 
558  $dispatcher = $request->getDispatcher();
559 
560  // Check if the user is an author of this submission
561  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
562  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
563  $authorUserGroupIds = $userGroupDao->getUserGroupIdsByRoleId(ROLE_ID_AUTHOR);
564  $stageAssignmentsFactory = $stageAssignmentDao->getBySubmissionAndStageId($submission->getId(), null, null, $user->getId());
565 
566  $authorDashboard = false;
567  while ($stageAssignment = $stageAssignmentsFactory->next()) {
568  if (in_array($stageAssignment->getUserGroupId(), $authorUserGroupIds)) {
569  $authorDashboard = true;
570  }
571  }
572 
573  // Send authors, journal managers and site admins to the submission
574  // wizard for incomplete submissions
575  if ($submission->getSubmissionProgress() > 0 &&
576  ($authorDashboard ||
577  $user->hasRole(array(ROLE_ID_MANAGER), $submissionContext->getId()) ||
578  $user->hasRole(array(ROLE_ID_SITE_ADMIN), CONTEXT_SITE))) {
579  return $dispatcher->url(
580  $request,
581  ROUTE_PAGE,
582  $submissionContext->getPath(),
583  'submission',
584  'wizard',
585  $submission->getSubmissionProgress(),
586  array('submissionId' => $submission->getId())
587  );
588  }
589 
590  // Send authors to author dashboard
591  if ($authorDashboard) {
592  return $dispatcher->url(
593  $request,
594  ROUTE_PAGE,
595  $submissionContext->getPath(),
596  'authorDashboard',
597  'submission',
598  $submission->getId()
599  );
600  }
601 
602  // Send reviewers to review wizard
603  $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /* @var $reviewAssignmentDao ReviewAssignmentDAO */
604  $reviewAssignment = $reviewAssignmentDao->getLastReviewRoundReviewAssignmentByReviewer($submission->getId(), $user->getId());
605  if ($reviewAssignment) {
606  return $dispatcher->url(
607  $request,
608  ROUTE_PAGE,
609  $submissionContext->getPath(),
610  'reviewer',
611  'submission',
612  $submission->getId()
613  );
614  }
615 
616  // Give any other users the editorial workflow URL. If they can't access
617  // it, they'll be blocked there.
618  return $dispatcher->url(
619  $request,
620  ROUTE_PAGE,
621  $submissionContext->getPath(),
622  'workflow',
623  'access',
624  $submission->getId()
625  );
626  }
627 
634  public function canCurrentUserDelete($submission) {
635 
636  if (!is_a($submission, 'Submission')) {
637  $submission = $this->get((int) $submission);
638  if (!$submission) {
639  return false;
640  }
641  }
642 
643  $request = Application::get()->getRequest();
644  $contextId = $submission->getContextId();
645 
646  $currentUser = $request->getUser();
647  if (!$currentUser) {
648  return false;
649  }
650 
651  $canDelete = false;
652 
653  // Only allow admins and journal managers to delete submissions, except
654  // for authors who can delete their own incomplete submissions
655  if ($currentUser->hasRole(array(ROLE_ID_MANAGER), $contextId) || $currentUser->hasRole(array(ROLE_ID_SITE_ADMIN), CONTEXT_SITE)) {
656  $canDelete = true;
657  } else {
658  if ($submission->getSubmissionProgress() != 0 ) {
659  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
660  $assignments = $stageAssignmentDao->getBySubmissionAndRoleId($submission->getId(), ROLE_ID_AUTHOR, WORKFLOW_STAGE_ID_SUBMISSION, $currentUser->getId());
661  $assignment = $assignments->next();
662  if ($assignment) {
663  $canDelete = true;
664  }
665  }
666  }
667 
668  return $canDelete;
669  }
670 
677  public function getReviewRounds($submission) {
678  $reviewRoundDao = DAORegistry::getDAO('ReviewRoundDAO'); /* @var $reviewRoundDao ReviewRoundDAO */
679  return $reviewRoundDao->getBySubmissionId($submission->getId())->toIterator();
680  }
681 
688  public function getReviewAssignments($submission) {
689  import('lib.pkp.classes.submission.reviewAssignment.ReviewAssignmentDAO');
690  $reviewAssignmentDao = DAORegistry::getDAO('ReviewAssignmentDAO'); /* @var $reviewAssignmentDao ReviewAssignmentDAO */
691  return $reviewAssignmentDao->getBySubmissionId($submission->getId());
692  }
693 
697  public function validate($action, $props, $allowedLocales, $primaryLocale) {
698  $schemaService = Services::get('schema');
699 
700  import('lib.pkp.classes.validation.ValidatorFactory');
701  $validator = \ValidatorFactory::make(
702  $props,
703  $schemaService->getValidationRules(SCHEMA_SUBMISSION, $allowedLocales)
704  );
705 
706  // Check required fields
708  $validator,
709  $action,
710  $schemaService->getRequiredProps(SCHEMA_SUBMISSION),
711  $schemaService->getMultilingualProps(SCHEMA_SUBMISSION),
712  $primaryLocale,
713  $allowedLocales
714  );
715 
716  // Check for input from disallowed locales
717  \ValidatorFactory::allowedLocales($validator, $schemaService->getMultilingualProps(SCHEMA_SUBMISSION), $allowedLocales);
718 
719  // The contextId must match an existing context
720  $validator->after(function($validator) use ($props) {
721  if (isset($props['contextid']) && !$validator->errors()->get('contextid')) {
722  $submissionContext = Services::get('context')->get($props['contextid']);
723  if (!$submissionContext) {
724  $validator->errors()->add('contextId', __('submission.submit.noContext'));
725  }
726  }
727  });
728 
729  if ($validator->fails()) {
730  $errors = $schemaService->formatValidationErrors($validator->errors(), $schemaService->get(SCHEMA_SUBMISSION), $allowedLocales);
731  }
732 
733  \HookRegistry::call('Submission::validate', [&$errors, $action, $props, $allowedLocales, $primaryLocale]);
734 
735  return $errors;
736  }
737 
741  public function add($submission, $request) {
742  $submission->stampLastActivity();
743  $submission->stampModified();
744  if (!$submission->getData('dateSubmitted') && !$submission->getData('submissionProgress')) {
745  $submission->setData('dateSubmitted', Core::getCurrentDate());
746  }
747  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
748  $submissionId = $submissionDao->insertObject($submission);
749  $submission = $this->get($submissionId);
750 
751  \HookRegistry::call('Submission::add', [$submission, $request]);
752 
753  return $submission;
754  }
755 
759  public function edit($submission, $params, $request) {
760  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
761 
762  $newSubmission = $submissionDao->newDataObject();
763  $newSubmission->_data = array_merge($submission->_data, $params);
764  $submission->stampLastActivity();
765  $submission->stampModified();
766 
767  \HookRegistry::call('Submission::edit', [$newSubmission, $submission, $params, $request]);
768 
769  $submissionDao->updateObject($newSubmission);
770  $newSubmission = $this->get($newSubmission->getId());
771 
772  return $newSubmission;
773  }
774 
778  public function delete($submission) {
779  \HookRegistry::call('Submission::delete::before', [$submission]);
780 
781  $submissionDao = DAORegistry::getDAO('SubmissionDAO'); /* @var $submissionDao SubmissionDAO */
782  $submissionDao->deleteObject($submission);
783 
784  \HookRegistry::call('Submission::delete', [$submission]);
785  }
786 
794  public function canEditPublication($submissionId, $userId) {
795  $stageAssignmentDao = DAORegistry::getDAO('StageAssignmentDAO'); /* @var $stageAssignmentDao StageAssignmentDAO */
796  $stageAssignments = $stageAssignmentDao->getBySubmissionAndUserIdAndStageId($submissionId, $userId, null);
797  // Check for permission from stage assignments
798  while ($stageAssignment = $stageAssignments->next()) {
799  if ($stageAssignment->getCanChangeMetadata()) {
800  return true;
801  }
802  }
803  // If user has no stage assigments, check if user can edit anyway ie. is manager
804  $context = Application::get()->getRequest()->getContext();
805  if ($stageAssignments->wasEmpty() && $this->_canUserAccessUnassignedSubmissions($context->getId(), $userId)){
806  return true;
807  }
808  // Else deny access
809  return false;
810  }
811 
818  private static function _canUserAccessUnassignedSubmissions($contextId, $userId) {
819  $roleDao = DAORegistry::getDAO('RoleDAO'); /* @var $roleDao RoleDAO */
820  $roles = $roleDao->getByUserId($userId, $contextId);
821  $userGroupDao = DAORegistry::getDAO('UserGroupDAO'); /* @var $userGroupDao UserGroupDAO */
822  $allowedRoles = $userGroupDao->getNotChangeMetadataEditPermissionRoles();
823  foreach ($roles as $role) {
824  if (in_array($role->getRoleId(), $allowedRoles))
825  return true;
826  }
827  return false;
828  }
829 
839  public function updateStatus($submission) {
840  $status = $newStatus = $submission->getData('status');
841  $currentPublicationId = $submission->getData('currentPublicationId');
842  $publications = $submission->getData('publications');
843 
844  // There should always be at least one publication for a submission. If
845  // not, an error has occurred in the code and will cause problems.
846  if (empty($publications)) {
847  throw new \Exception('Tried to update the status of submission ' . $submission->getId() . ' and no publications were found.');
848  }
849 
850  // Get the new current publication after status changes or deletions
851  // Use the latest published publication or, failing that, the latest publication
852  $newCurrentPublicationId = array_reduce($publications, function($a, $b) {
853  return $b->getData('status') === STATUS_PUBLISHED && $b->getId() > $a ? $b->getId() : $a;
854  }, 0);
855  if (!$newCurrentPublicationId) {
856  $newCurrentPublicationId = array_reduce($publications, function($a, $b) {
857  return $a > $b->getId() ? $a : $b->getId();
858  }, 0);
859  }
860 
861  // Declined submissions should remain declined even if their
862  // publications change
863  if ($status !== STATUS_DECLINED) {
864  $newStatus = STATUS_QUEUED;
865  foreach ($publications as $publication) {
866  if ($publication->getData('status') === STATUS_PUBLISHED) {
867  $newStatus = STATUS_PUBLISHED;
868  break;
869  }
870  if ($publication->getData('status') === STATUS_SCHEDULED) {
871  $newStatus = STATUS_SCHEDULED;
872  continue;
873  }
874  }
875  }
876 
877  \HookRegistry::call('Submission::updateStatus', [&$status, $submission]);
878 
879  $updateParams = [];
880  if ($status !== $newStatus) {
881  $updateParams['status'] = $newStatus;
882  }
883  if ($currentPublicationId !== $newCurrentPublicationId) {
884  $updateParams['currentPublicationId'] = $newCurrentPublicationId;
885  }
886  if (!empty($updateParams)) {
887  $submission = $this->edit($submission, $updateParams, Application::get()->getRequest());
888  }
889 
890  return $submission;
891  }
892 }
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:688
PKP\Services\PKPSubmissionService\validate
validate($action, $props, $allowedLocales, $primaryLocale)
Definition: PKPSubmissionService.inc.php:697
PKP\Services\PKPSubmissionService\getWorkflowUrlByUserRoles
getWorkflowUrlByUserRoles($submission, $userId=null)
Definition: PKPSubmissionService.inc.php:537
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:759
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
ValidatorFactory\make
static make($props, $rules, $messages=[])
Definition: ValidatorFactory.inc.php:38
PKP\Services\PKPSubmissionService\getReviewRounds
getReviewRounds($submission)
Definition: PKPSubmissionService.inc.php:677
PKP\Services\PKPSubmissionService\getSummaryProperties
getSummaryProperties($submission, $args=null)
Definition: PKPSubmissionService.inc.php:264
PKP\Services\PKPSubmissionService\getPropertyReviewRounds
getPropertyReviewRounds($submission)
Definition: PKPSubmissionService.inc.php:347
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:839
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:634
PKP\Services\PKPSubmissionService\canEditPublication
canEditPublication($submissionId, $userId)
Definition: PKPSubmissionService.inc.php:794
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:741
PKP\Services\PKPSubmissionService\getPropertyStages
getPropertyStages($submission, $stageIds=null)
Definition: PKPSubmissionService.inc.php:390
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