[TASK] The Number of The Workspace
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / ExtDirect / ActionHandler.php
1 <?php
2 namespace TYPO3\CMS\Workspaces\ExtDirect;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Fluid\View\StandaloneView;
21 use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
22 use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
23 use TYPO3\CMS\Workspaces\Service\StagesService;
24 use TYPO3\CMS\Workspaces\Service\WorkspaceService;
25
26 /**
27 * ExtDirect action handler
28 */
29 class ActionHandler extends AbstractHandler
30 {
31 /**
32 * @var StagesService
33 */
34 protected $stageService;
35
36 /**
37 * Creates this object.
38 */
39 public function __construct()
40 {
41 $this->stageService = GeneralUtility::makeInstance(StagesService::class);
42 }
43
44 /**
45 * Generates a workspace preview link.
46 *
47 * @param int $uid The ID of the record to be linked
48 * @return string the full domain including the protocol http:// or https://, but without the trailing '/'
49 */
50 public function generateWorkspacePreviewLink($uid)
51 {
52 return $this->getWorkspaceService()->generateWorkspacePreviewLink($uid);
53 }
54
55 /**
56 * Generates workspace preview links for all available languages of a page.
57 *
58 * @param int $uid
59 * @return array
60 */
61 public function generateWorkspacePreviewLinksForAllLanguages($uid)
62 {
63 return $this->getWorkspaceService()->generateWorkspacePreviewLinksForAllLanguages($uid);
64 }
65
66 /**
67 * Swaps a single record.
68 *
69 * @param string $table
70 * @param int $t3ver_oid
71 * @param int $orig_uid
72 * @return void
73 * @todo What about reporting errors back to the ExtJS interface? /olly/
74 */
75 public function swapSingleRecord($table, $t3ver_oid, $orig_uid)
76 {
77 $versionRecord = BackendUtility::getRecord($table, $orig_uid);
78 $currentWorkspace = $this->setTemporaryWorkspace($versionRecord['t3ver_wsid']);
79
80 $cmd[$table][$t3ver_oid]['version'] = array(
81 'action' => 'swap',
82 'swapWith' => $orig_uid,
83 'swapIntoWS' => 1
84 );
85 $this->processTcaCmd($cmd);
86
87 $this->setTemporaryWorkspace($currentWorkspace);
88 }
89
90 /**
91 * Deletes a single record.
92 *
93 * @param string $table
94 * @param int $uid
95 * @return void
96 * @todo What about reporting errors back to the ExtJS interface? /olly/
97 */
98 public function deleteSingleRecord($table, $uid)
99 {
100 $versionRecord = BackendUtility::getRecord($table, $uid);
101 $currentWorkspace = $this->setTemporaryWorkspace($versionRecord['t3ver_wsid']);
102
103 $cmd[$table][$uid]['version'] = array(
104 'action' => 'clearWSID'
105 );
106 $this->processTcaCmd($cmd);
107
108 $this->setTemporaryWorkspace($currentWorkspace);
109 }
110
111 /**
112 * Generates a view link for a page.
113 *
114 * @param string $table
115 * @param string $uid
116 * @return string
117 */
118 public function viewSingleRecord($table, $uid)
119 {
120 return WorkspaceService::viewSingleRecord($table, $uid);
121 }
122
123 /**
124 * Executes an action (publish, discard, swap) to a selection set.
125 *
126 * @param \stdClass $parameter
127 * @return array
128 */
129 public function executeSelectionAction($parameter)
130 {
131 $result = array();
132
133 if (empty($parameter->action) || empty($parameter->selection)) {
134 $result['error'] = 'No action or record selection given';
135 return $result;
136 }
137
138 $commands = array();
139 $swapIntoWorkspace = ($parameter->action === 'swap');
140 if ($parameter->action === 'publish' || $swapIntoWorkspace) {
141 $commands = $this->getPublishSwapCommands($parameter->selection, $swapIntoWorkspace);
142 } elseif ($parameter->action === 'discard') {
143 $commands = $this->getFlushCommands($parameter->selection);
144 }
145
146 $result = $this->processTcaCmd($commands);
147 $result['total'] = count($commands);
148 return $result;
149 }
150
151 /**
152 * Get publish swap commands
153 *
154 * @param array|\stdClass[] $selection
155 * @param bool $swapIntoWorkspace
156 * @return array
157 */
158 protected function getPublishSwapCommands(array $selection, $swapIntoWorkspace)
159 {
160 $commands = array();
161 foreach ($selection as $record) {
162 $commands[$record->table][$record->liveId]['version'] = array(
163 'action' => 'swap',
164 'swapWith' => $record->versionId,
165 'swapIntoWS' => (bool)$swapIntoWorkspace,
166 );
167 }
168 return $commands;
169 }
170
171 /**
172 * Get flush commands
173 *
174 * @param array|\stdClass[] $selection
175 * @return array
176 */
177 protected function getFlushCommands(array $selection)
178 {
179 $commands = array();
180 foreach ($selection as $record) {
181 $commands[$record->table][$record->versionId]['version'] = array(
182 'action' => 'clearWSID',
183 );
184 }
185 return $commands;
186 }
187
188 /**
189 * Saves the selected columns to be shown to the preferences of the current backend user.
190 *
191 * @param \stdClass $model
192 * @return void
193 */
194 public function saveColumnModel($model)
195 {
196 $data = array();
197 foreach ($model as $column) {
198 $data[$column->column] = array(
199 'position' => $column->position,
200 'hidden' => $column->hidden
201 );
202 }
203 $GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'] = $data;
204 $GLOBALS['BE_USER']->writeUC();
205 }
206
207 public function loadColumnModel()
208 {
209 if (is_array($GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'])) {
210 return $GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['columns'];
211 } else {
212 return array();
213 }
214 }
215
216 /**
217 * Saves the selected language.
218 *
219 * @param int|string $language
220 * @return void
221 */
222 public function saveLanguageSelection($language)
223 {
224 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($language) === false && $language !== 'all') {
225 $language = 'all';
226 }
227 $GLOBALS['BE_USER']->uc['moduleData']['Workspaces'][$GLOBALS['BE_USER']->workspace]['language'] = $language;
228 $GLOBALS['BE_USER']->writeUC();
229 }
230
231 /**
232 * Gets the dialog window to be displayed before a record can be sent to the next stage.
233 *
234 * @param int $uid
235 * @param string $table
236 * @param int $t3ver_oid
237 * @return array
238 */
239 public function sendToNextStageWindow($uid, $table, $t3ver_oid)
240 {
241 $elementRecord = BackendUtility::getRecord($table, $uid);
242 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
243
244 if (is_array($elementRecord)) {
245 $workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
246 $nextStageRecord = $workspaceRecord->getNextStage($elementRecord['t3ver_stage']);
247 if ($nextStageRecord !== null) {
248 $this->stageService->getRecordService()->add($table, $uid);
249 $result = $this->getSentToStageWindow($nextStageRecord);
250 $result['affects'] = array(
251 'table' => $table,
252 'nextStage' => $nextStageRecord->getUid(),
253 't3ver_oid' => $t3ver_oid,
254 'uid' => $uid
255 );
256 } else {
257 $result = $this->getErrorResponse('error.stageId.invalid', 1291111644);
258 }
259 } else {
260 $result = $this->getErrorResponse('error.sendToNextStage.noRecordFound', 1287264776);
261 }
262
263 $this->setTemporaryWorkspace($currentWorkspace);
264 return $result;
265 }
266
267 /**
268 * Gets the dialog window to be displayed before a record can be sent to the previous stage.
269 *
270 * @param int $uid
271 * @param string $table
272 * @return array
273 */
274 public function sendToPrevStageWindow($uid, $table)
275 {
276 $elementRecord = BackendUtility::getRecord($table, $uid);
277 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
278
279 if (is_array($elementRecord)) {
280 $workspaceRecord = WorkspaceRecord::get($elementRecord['t3ver_wsid']);
281 $stageRecord = $workspaceRecord->getStage($elementRecord['t3ver_stage']);
282
283 if ($stageRecord !== null) {
284 if (!$stageRecord->isEditStage()) {
285 $this->stageService->getRecordService()->add($table, $uid);
286 $previousStageRecord = $stageRecord->getPrevious();
287 $result = $this->getSentToStageWindow($previousStageRecord);
288 $result['affects'] = array(
289 'table' => $table,
290 'uid' => $uid,
291 'nextStage' => $previousStageRecord->getUid()
292 );
293 } else {
294 // element is already in edit stage, there is no prev stage - return an error message
295 $result = $this->getErrorResponse('error.sendToPrevStage.noPreviousStage', 1287264746);
296 }
297 } else {
298 $result = $this->getErrorResponse('error.stageId.invalid', 1291111644);
299 }
300 } else {
301 $result = $this->getErrorResponse('error.sendToNextStage.noRecordFound', 1287264765);
302 }
303
304 $this->setTemporaryWorkspace($currentWorkspace);
305 return $result;
306 }
307
308 /**
309 * Gets the dialog window to be displayed before a record can be sent to a specific stage.
310 *
311 * @param int $nextStageId
312 * @param array|\stdClass[] $elements
313 * @return array
314 */
315 public function sendToSpecificStageWindow($nextStageId, array $elements)
316 {
317 foreach ($elements as $element) {
318 $this->stageService->getRecordService()->add(
319 $element->table,
320 $element->uid
321 );
322 }
323
324 $result = $this->getSentToStageWindow($nextStageId);
325 $result['affects'] = array(
326 'nextStage' => $nextStageId
327 );
328 return $result;
329 }
330
331 /**
332 * Gets a merged variant of recipient defined by uid and custom ones.
333 *
334 * @param array $uidOfRecipients list of recipients
335 * @param string $additionalRecipients given user string of additional recipients
336 * @param int $stageId stage id
337 * @return array
338 * @throws \InvalidArgumentException
339 */
340 public function getRecipientList(array $uidOfRecipients, $additionalRecipients, $stageId)
341 {
342 $stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageId);
343
344 if ($stageRecord === null) {
345 throw new \InvalidArgumentException($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:error.stageId.integer'));
346 }
347
348 $recipients = array();
349 $finalRecipients = array();
350 $backendUserIds = $stageRecord->getAllRecipients();
351 foreach ($uidOfRecipients as $userUid) {
352 // Ensure that only configured backend users are considered
353 if (!in_array($userUid, $backendUserIds)) {
354 continue;
355 }
356 $beUserRecord = BackendUtility::getRecord('be_users', (int)$userUid);
357 if (is_array($beUserRecord) && $beUserRecord['email'] !== '') {
358 $uc = $beUserRecord['uc'] ? unserialize($beUserRecord['uc']) : array();
359 $recipients[$beUserRecord['email']] = array(
360 'email' => $beUserRecord['email'],
361 'lang' => isset($uc['lang']) ? $uc['lang'] : $beUserRecord['lang']
362 );
363 }
364 }
365
366 if ($stageRecord->hasPreselection() && !$stageRecord->isPreselectionChangeable()) {
367 $preselectedBackendUsers = $this->getStageService()->getBackendUsers(
368 implode(',', $this->stageService->getPreselectedRecipients($stageRecord))
369 );
370
371 foreach ($preselectedBackendUsers as $preselectedBackendUser) {
372 if (empty($preselectedBackendUser['email']) || !GeneralUtility::validEmail($preselectedBackendUser['email'])) {
373 continue;
374 }
375 if (!isset($recipients[$preselectedBackendUser['email']])) {
376 $uc = (!empty($preselectedBackendUser['uc']) ? unserialize($preselectedBackendUser['uc']) : array());
377 $recipients[$preselectedBackendUser['email']] = array(
378 'email' => $preselectedBackendUser['email'],
379 'lang' => (isset($uc['lang']) ? $uc['lang'] : $preselectedBackendUser['lang'])
380 );
381 }
382 }
383 }
384
385 if ($additionalRecipients !== '') {
386 $emails = GeneralUtility::trimExplode(LF, $additionalRecipients, true);
387 $additionalRecipients = array();
388 foreach ($emails as $email) {
389 $additionalRecipients[$email] = array('email' => $email);
390 }
391 } else {
392 $additionalRecipients = array();
393 }
394 // We merge $recipients on top of $additionalRecipients because $recipients
395 // possibly is more complete with a user language. Furthermore, the list of
396 // recipients is automatically unique since we indexed $additionalRecipients
397 // and $recipients with the email address
398 $allRecipients = array_merge($additionalRecipients, $recipients);
399 foreach ($allRecipients as $email => $recipientInformation) {
400 if (GeneralUtility::validEmail($email)) {
401 $finalRecipients[] = $recipientInformation;
402 }
403 }
404 return $finalRecipients;
405 }
406
407 /**
408 * Discard all items from given page id.
409 *
410 * @param int $pageId
411 * @return array
412 */
413 public function discardStagesFromPage($pageId)
414 {
415 $cmdMapArray = array();
416 /** @var $workspaceService WorkspaceService */
417 $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
418 /** @var $stageService StagesService */
419 $stageService = GeneralUtility::makeInstance(StagesService::class);
420 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $pageId, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
421 foreach ($workspaceItemsArray as $tableName => $items) {
422 foreach ($items as $item) {
423 $cmdMapArray[$tableName][$item['uid']]['version']['action'] = 'clearWSID';
424 }
425 }
426 $this->processTcaCmd($cmdMapArray);
427 return array(
428 'success' => true
429 );
430 }
431
432 /**
433 * Push the given element collection to the next workspace stage.
434 *
435 * <code>
436 * $parameters->additional = your@mail.com
437 * $parameters->affects->__TABLENAME__
438 * $parameters->comments
439 * $parameters->receipients
440 * $parameters->stageId
441 * </code>
442 *
443 * @param \stdClass $parameters
444 * @return array
445 */
446 public function sentCollectionToStage(\stdClass $parameters)
447 {
448 $cmdMapArray = array();
449 $comment = $parameters->comments;
450 $stageId = $parameters->stageId;
451 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($stageId) === false) {
452 throw new \InvalidArgumentException('Missing "stageId" in $parameters array.', 1319488194);
453 }
454 if (!is_object($parameters->affects) || empty($parameters->affects)) {
455 throw new \InvalidArgumentException('Missing "affected items" in $parameters array.', 1319488195);
456 }
457 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $stageId);
458 foreach ($parameters->affects as $tableName => $items) {
459 foreach ($items as $item) {
460 // Publishing uses live id in command map
461 if ($stageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
462 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['action'] = 'swap';
463 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['swapWith'] = $item->uid;
464 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['comment'] = $comment;
465 $cmdMapArray[$tableName][$item->t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
466 // Setting stage uses version id in command map
467 } else {
468 $cmdMapArray[$tableName][$item->uid]['version']['action'] = 'setStage';
469 $cmdMapArray[$tableName][$item->uid]['version']['stageId'] = $stageId;
470 $cmdMapArray[$tableName][$item->uid]['version']['comment'] = $comment;
471 $cmdMapArray[$tableName][$item->uid]['version']['notificationAlternativeRecipients'] = $recipients;
472 }
473 }
474 }
475 $this->processTcaCmd($cmdMapArray);
476 return array(
477 'success' => true,
478 // force refresh after publishing changes
479 'refreshLivePanel' => $parameters->stageId == -20
480 );
481 }
482
483 /**
484 * Process TCA command map array.
485 *
486 * @param array $cmdMapArray
487 * @return array
488 */
489 protected function processTcaCmd(array $cmdMapArray)
490 {
491 $result = array();
492
493 if (empty($cmdMapArray)) {
494 $result['error'] = 'No commands given to be processed';
495 return $result;
496 }
497
498 /** @var \TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler */
499 $dataHandler = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
500 $dataHandler->start(array(), $cmdMapArray);
501 $dataHandler->process_cmdmap();
502
503 if ($dataHandler->errorLog) {
504 $result['error'] = implode('<br/>', $dataHandler->errorLog);
505 }
506
507 return $result;
508 }
509
510 /**
511 * Gets an object with this structure:
512 *
513 * affects: object
514 * table
515 * t3ver_oid
516 * nextStage
517 * uid
518 * receipients: array with uids
519 * additional: string
520 * comments: string
521 *
522 * @param \stdClass $parameters
523 * @return array
524 */
525 public function sendToNextStageExecute(\stdClass $parameters)
526 {
527 $cmdArray = array();
528 $setStageId = $parameters->affects->nextStage;
529 $comments = $parameters->comments;
530 $table = $parameters->affects->table;
531 $uid = $parameters->affects->uid;
532 $t3ver_oid = $parameters->affects->t3ver_oid;
533
534 $elementRecord = BackendUtility::getRecord($table, $uid);
535 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
536
537 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
538 if ($setStageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
539 $cmdArray[$table][$t3ver_oid]['version']['action'] = 'swap';
540 $cmdArray[$table][$t3ver_oid]['version']['swapWith'] = $uid;
541 $cmdArray[$table][$t3ver_oid]['version']['comment'] = $comments;
542 $cmdArray[$table][$t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
543 } else {
544 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
545 $cmdArray[$table][$uid]['version']['stageId'] = $setStageId;
546 $cmdArray[$table][$uid]['version']['comment'] = $comments;
547 $cmdArray[$table][$uid]['version']['notificationAlternativeRecipients'] = $recipients;
548 }
549 $this->processTcaCmd($cmdArray);
550 $result = array(
551 'success' => true
552 );
553
554 $this->setTemporaryWorkspace($currentWorkspace);
555 return $result;
556 }
557
558 /**
559 * Gets an object with this structure:
560 *
561 * affects: object
562 * table
563 * t3ver_oid
564 * nextStage
565 * receipients: array with uids
566 * additional: string
567 * comments: string
568 *
569 * @param \stdClass $parameters
570 * @return array
571 */
572 public function sendToPrevStageExecute(\stdClass $parameters)
573 {
574 $cmdArray = array();
575 $setStageId = $parameters->affects->nextStage;
576 $comments = $parameters->comments;
577 $table = $parameters->affects->table;
578 $uid = $parameters->affects->uid;
579
580 $elementRecord = BackendUtility::getRecord($table, $uid);
581 $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
582
583 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
584 $cmdArray[$table][$uid]['version']['action'] = 'setStage';
585 $cmdArray[$table][$uid]['version']['stageId'] = $setStageId;
586 $cmdArray[$table][$uid]['version']['comment'] = $comments;
587 $cmdArray[$table][$uid]['version']['notificationAlternativeRecipients'] = $recipients;
588 $this->processTcaCmd($cmdArray);
589 $result = array(
590 'success' => true
591 );
592
593 $this->setTemporaryWorkspace($currentWorkspace);
594 return $result;
595 }
596
597 /**
598 * Gets an object with this structure:
599 *
600 * affects: object
601 * elements: array
602 * 0: object
603 * table
604 * t3ver_oid
605 * uid
606 * 1: object
607 * table
608 * t3ver_oid
609 * uid
610 * nextStage
611 * recipients: array with uids
612 * additional: string
613 * comments: string
614 *
615 * @param \stdClass $parameters
616 * @return array
617 */
618 public function sendToSpecificStageExecute(\stdClass $parameters)
619 {
620 $cmdArray = array();
621 $setStageId = $parameters->affects->nextStage;
622 $comments = $parameters->comments;
623 $elements = $parameters->affects->elements;
624 $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
625 foreach ($elements as $element) {
626 // Avoid any action on records that have already been published to live
627 $elementRecord = BackendUtility::getRecord($element->table, $element->uid);
628 if ((int)$elementRecord['t3ver_wsid'] === 0) {
629 continue;
630 }
631
632 if ($setStageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
633 $cmdArray[$element->table][$element->t3ver_oid]['version']['action'] = 'swap';
634 $cmdArray[$element->table][$element->t3ver_oid]['version']['swapWith'] = $element->uid;
635 $cmdArray[$element->table][$element->t3ver_oid]['version']['comment'] = $comments;
636 $cmdArray[$element->table][$element->t3ver_oid]['version']['notificationAlternativeRecipients'] = $recipients;
637 } else {
638 $cmdArray[$element->table][$element->uid]['version']['action'] = 'setStage';
639 $cmdArray[$element->table][$element->uid]['version']['stageId'] = $setStageId;
640 $cmdArray[$element->table][$element->uid]['version']['comment'] = $comments;
641 $cmdArray[$element->table][$element->uid]['version']['notificationAlternativeRecipients'] = $recipients;
642 }
643 }
644 $this->processTcaCmd($cmdArray);
645 $result = array(
646 'success' => true
647 );
648 return $result;
649 }
650
651 /**
652 * Gets the dialog window to be displayed before a record can be sent to a stage.
653 *
654 * @param StageRecord|int $nextStage
655 * @return array
656 */
657 protected function getSentToStageWindow($nextStage)
658 {
659 if (!$nextStage instanceof StageRecord) {
660 $nextStage = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($nextStage);
661 }
662
663 $result = [];
664 if ($nextStage->isDialogEnabled()) {
665 $result['sendMailTo'] = $this->getRecipientsOfStage($nextStage->getUid());
666 $result['additional'] = [
667 'type' => 'textarea',
668 'value' => ''
669 ];
670 }
671 $result['comments'] = [
672 'type' => 'textarea',
673 'value' => ($nextStage->isInternal() ? '' : $nextStage->getDefaultComment())
674 ];
675
676 return $result;
677 }
678
679 /**
680 * Gets all assigned recipients of a particular stage.
681 *
682 * @param StageRecord|int $stageRecord
683 * @return array
684 */
685 protected function getRecipientsOfStage($stageRecord)
686 {
687 if (!$stageRecord instanceof StageRecord) {
688 $stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageRecord);
689 }
690
691 $result = array();
692 $allRecipients = $this->getStageService()->getResponsibleBeUser($stageRecord);
693 $preselectedRecipients = $this->stageService->getPreselectedRecipients($stageRecord);
694 $isPreselectionChangeable = $stageRecord->isPreselectionChangeable();
695
696 foreach ($allRecipients as $backendUserId => $backendUser) {
697 if (empty($backendUser['email']) || !GeneralUtility::validEmail($backendUser['email'])) {
698 continue;
699 }
700
701 $name = (!empty($backendUser['realName']) ? $backendUser['realName'] : $backendUser['username']);
702 $checked = in_array($backendUserId, $preselectedRecipients);
703 $disabled = ($checked && !$isPreselectionChangeable);
704
705 $result[] = array(
706 'label' => sprintf('%s (%s)', $name, $backendUser['email']),
707 'value' => $backendUserId,
708 'name' => 'recipients-' . $backendUserId,
709 'checked' => $checked,
710 'disabled' => $disabled
711 );
712 }
713
714 return $result;
715 }
716
717 /**
718 * Gets the default comment of a particular stage.
719 *
720 * @param int $stage
721 * @return string
722 */
723 protected function getDefaultCommentOfStage($stage)
724 {
725 $result = $this->getStageService()->getPropertyOfCurrentWorkspaceStage($stage, 'default_mailcomment');
726 return $result;
727 }
728
729 /**
730 * Gets an instance of the Stage service.
731 *
732 * @return StagesService
733 */
734 protected function getStageService()
735 {
736 if (!isset($this->stageService)) {
737 $this->stageService = GeneralUtility::makeInstance(StagesService::class);
738 }
739 return $this->stageService;
740 }
741
742 /**
743 * Send all available workspace records to the previous stage.
744 *
745 * @param int $id Current page id to process items to previous stage.
746 * @return array
747 */
748 public function sendPageToPreviousStage($id)
749 {
750 $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
751 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
752 list($currentStage, $previousStage) = $this->getStageService()->getPreviousStageForElementCollection($workspaceItemsArray);
753 // get only the relevant items for processing
754 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), $currentStage['uid'], $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
755 $stageFormFields = $this->getSentToStageWindow($previousStage['uid']);
756 $result = array_merge($stageFormFields, [
757 'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $previousStage['title'],
758 'items' => $this->getSentToStageWindow($previousStage['uid']),
759 'affects' => $workspaceItemsArray,
760 'stageId' => $previousStage['uid']
761 ]);
762 return $result;
763 }
764
765 /**
766 * @param int $id Current Page id to select Workspace items from.
767 * @return array
768 */
769 public function sendPageToNextStage($id)
770 {
771 $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
772 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
773 list($currentStage, $nextStage) = $this->getStageService()->getNextStageForElementCollection($workspaceItemsArray);
774 // get only the relevant items for processing
775 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), $currentStage['uid'], $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
776 $stageFormFields = $this->getSentToStageWindow($nextStage['uid']);
777 $result = array_merge($stageFormFields, [
778 'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $nextStage['title'],
779 'affects' => $workspaceItemsArray,
780 'stageId' => $nextStage['uid']
781 ]);
782 return $result;
783 }
784
785 /**
786 * Fetch the current label and visible state of the buttons.
787 *
788 * @param int $id
789 * @return string The pre-rendered HTML for the stage buttons
790 */
791 public function updateStageChangeButtons($id)
792 {
793 /** @var StagesService $stageService */
794 $stageService = GeneralUtility::makeInstance(StagesService::class);
795 /** @var WorkspaceService $workspaceService */
796 $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
797 // fetch the next and previous stage
798 $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
799 list(, $nextStage) = $stageService->getNextStageForElementCollection($workspaceItemsArray);
800 list(, $previousStage) = $stageService->getPreviousStageForElementCollection($workspaceItemsArray);
801
802 /** @var StandaloneView $view */
803 $view = GeneralUtility::makeInstance(StandaloneView::class);
804 $extensionPath = ExtensionManagementUtility::extPath('workspaces');
805 $view->setPartialRootPaths(['default' => $extensionPath . 'Resources/Private/Partials']);
806 $view->setTemplatePathAndFilename($extensionPath . 'Resources/Private/Templates/Preview/Ajax/StageButtons.html');
807 $request = $view->getRequest();
808 $request->setControllerExtensionName('workspaces');
809 $view->assignMultiple([
810 'enablePreviousStageButton' => is_array($previousStage) && !empty($previousStage),
811 'enableNextStageButton' => is_array($nextStage) && !empty($nextStage),
812 'enableDiscardStageButton' => is_array($nextStage) && !empty($nextStage) || is_array($previousStage) && !empty($previousStage),
813 'nextStage' => $nextStage['title'],
814 'nextStageId' => $nextStage['uid'],
815 'prevStage' => $previousStage['title'],
816 'prevStageId' => $previousStage['uid'],
817 ]);
818 $renderedView = $view->render();
819 return $renderedView;
820 }
821
822 /**
823 * @param int $workspaceId
824 * @return int Id of the original workspace
825 * @throws \TYPO3\CMS\Core\Exception
826 */
827 protected function setTemporaryWorkspace($workspaceId)
828 {
829 $workspaceId = (int)$workspaceId;
830 $currentWorkspace = (int)$this->getBackendUser()->workspace;
831
832 if ($currentWorkspace !== $workspaceId) {
833 if (!$this->getBackendUser()->setTemporaryWorkspace($workspaceId)) {
834 throw new \TYPO3\CMS\Core\Exception(
835 'Cannot set temporary workspace to "' . $workspaceId . '"',
836 1371484524
837 );
838 }
839 }
840
841 return $currentWorkspace;
842 }
843
844 /**
845 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
846 */
847 protected function getBackendUser()
848 {
849 return $GLOBALS['BE_USER'];
850 }
851 }