6a3e64cb59281de47944f85daffdd271fb658eed
[Packages/TYPO3.CMS.git] / typo3 / sysext / taskcenter / Classes / Controller / TaskModuleController.php
1 <?php
2 namespace TYPO3\CMS\Taskcenter\Controller;
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\BaseScriptClass;
20 use TYPO3\CMS\Backend\Template\ModuleTemplate;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
22 use TYPO3\CMS\Core\Messaging\FlashMessage;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Core\Utility\PathUtility;
25 use TYPO3\CMS\Fluid\View\StandaloneView;
26 use TYPO3\CMS\Taskcenter\TaskInterface;
27
28 /**
29 * This class provides a taskcenter for BE users
30 */
31 class TaskModuleController extends BaseScriptClass
32 {
33 /**
34 * @var array
35 */
36 protected $pageinfo;
37
38 /**
39 * ModuleTemplate Container
40 *
41 * @var ModuleTemplate
42 */
43 protected $moduleTemplate;
44
45 /**
46 * The name of the module
47 *
48 * @var string
49 */
50 protected $moduleName = 'user_task';
51
52 /**
53 * Initializes the Module
54 */
55 public function __construct()
56 {
57 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
58 $this->getLanguageService()->includeLLFile('EXT:taskcenter/Resources/Private/Language/locallang_task.xlf');
59 $this->MCONF = [
60 'name' => $this->moduleName
61 ];
62 parent::init();
63 }
64
65 /**
66 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
67 */
68 public function menuConfig()
69 {
70 $this->MOD_MENU = ['mode' => []];
71 $this->MOD_MENU['mode']['information'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang.xlf:task_overview');
72 $this->MOD_MENU['mode']['tasks'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang.xlf:task_tasks');
73 /* Copied from parent::menuConfig, because parent is hardcoded to menu.function,
74 * however menu.function is already used for the individual tasks.
75 * Therefore we use menu.mode here.
76 */
77 // Page/be_user TSconfig settings and blinding of menu-items
78 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
79 $this->MOD_MENU['mode'] = $this->mergeExternalItems($this->MCONF['name'], 'mode', $this->MOD_MENU['mode']);
80 $this->MOD_MENU['mode'] = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $this->MOD_MENU['mode'], 'menu.mode');
81 parent::menuConfig();
82 }
83
84 /**
85 * Generates the menu based on $this->MOD_MENU
86 *
87 * @throws \InvalidArgumentException
88 */
89 protected function generateMenu()
90 {
91 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
92 $menu->setIdentifier('WebFuncJumpMenu');
93 foreach ($this->MOD_MENU['mode'] as $controller => $title) {
94 $item = $menu
95 ->makeMenuItem()
96 ->setHref(
97 BackendUtility::getModuleUrl(
98 $this->moduleName,
99 [
100 'id' => $this->id,
101 'SET' => [
102 'mode' => $controller
103 ]
104 ]
105 )
106 )
107 ->setTitle($title);
108 if ($controller === $this->MOD_SETTINGS['mode']) {
109 $item->setActive(true);
110 }
111 $menu->addMenuItem($item);
112 }
113 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
114 }
115
116 /**
117 * Injects the request object for the current request or subrequest
118 * Simply calls main() and writes the content to the response
119 *
120 * @param ServerRequestInterface $request the current request
121 * @param ResponseInterface $response
122 * @return ResponseInterface the response with the content
123 */
124 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
125 {
126 $GLOBALS['SOBE'] = $this;
127 $this->main();
128
129 $this->moduleTemplate->setContent($this->content);
130
131 $response->getBody()->write($this->moduleTemplate->renderContent());
132 return $response;
133 }
134
135 /**
136 * Creates the module's content. In this case it rather acts as a kind of #
137 * dispatcher redirecting requests to specific tasks.
138 */
139 public function main()
140 {
141 $this->getButtons();
142 $this->generateMenu();
143 $this->moduleTemplate->addJavaScriptCode(
144 'TaskCenterInlineJavascript',
145 'if (top.fsMod) { top.fsMod.recentIds["web"] = 0; }'
146 );
147
148 // Render content depending on the mode
149 $mode = (string)$this->MOD_SETTINGS['mode'];
150 if ($mode === 'information') {
151 $this->renderInformationContent();
152 } else {
153 $this->renderModuleContent();
154 }
155 // Renders the module page
156 $this->moduleTemplate->setTitle($this->getLanguageService()->getLL('title'));
157 }
158
159 /**
160 * Generates the module content by calling the selected task
161 */
162 protected function renderModuleContent()
163 {
164 $chosenTask = (string)$this->MOD_SETTINGS['function'];
165 // Render the taskcenter task as default
166 if (empty($chosenTask) || $chosenTask === 'index') {
167 $chosenTask = 'taskcenter.tasks';
168 }
169 // Render the task
170 $actionContent = '';
171 $flashMessage = null;
172 list($extKey, $taskClass) = explode('.', $chosenTask, 2);
173 if (class_exists($taskClass)) {
174 $taskInstance = GeneralUtility::makeInstance($taskClass, $this);
175 if ($taskInstance instanceof TaskInterface) {
176 // Check if the task is restricted to admins only
177 if ($this->checkAccess($extKey, $taskClass)) {
178 $actionContent .= $taskInstance->getTask();
179 } else {
180 $flashMessage = GeneralUtility::makeInstance(
181 FlashMessage::class,
182 $this->getLanguageService()->getLL('error-access'),
183 $this->getLanguageService()->getLL('error_header'),
184 FlashMessage::ERROR
185 );
186 }
187 } else {
188 // Error if the task is not an instance of \TYPO3\CMS\Taskcenter\TaskInterface
189 $flashMessage = GeneralUtility::makeInstance(
190 FlashMessage::class,
191 sprintf($this->getLanguageService()->getLL('error_no-instance'), $taskClass, TaskInterface::class),
192 $this->getLanguageService()->getLL('error_header'),
193 FlashMessage::ERROR
194 );
195 }
196 } else {
197 $flashMessage = GeneralUtility::makeInstance(
198 FlashMessage::class,
199 $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tabdescr'),
200 $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'),
201 FlashMessage::INFO
202 );
203 }
204
205 if ($flashMessage) {
206 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
207 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
208 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
209 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
210 $defaultFlashMessageQueue->enqueue($flashMessage);
211 }
212
213 $assigns = [];
214 $assigns['reports'] = $this->indexAction();
215 $assigns['taskClass'] = strtolower(str_replace('\\', '-', htmlspecialchars(($extKey . '-' . $taskClass))));
216 $assigns['actionContent'] = $actionContent;
217
218 // Rendering of the output via fluid
219 $view = GeneralUtility::makeInstance(StandaloneView::class);
220 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
221 'EXT:taskcenter/Resources/Private/Templates/ModuleContent.html'
222 ));
223 $view->assignMultiple($assigns);
224 $this->content .= $view->render();
225 }
226
227 /**
228 * Generates the information content
229 */
230 protected function renderInformationContent()
231 {
232 $assigns = [];
233 $assigns['LLPrefix'] = 'LLL:EXT:taskcenter/Resources/Private/Language/locallang.xlf:';
234 $assigns['LLPrefixMod'] = 'LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:';
235 $assigns['LLPrefixTask'] = 'LLL:EXT:taskcenter/Resources/Private/Language/locallang_task.xlf:';
236 $assigns['admin'] = $this->getBackendUser()->isAdmin();
237
238 // Rendering of the output via fluid
239 $view = GeneralUtility::makeInstance(StandaloneView::class);
240 $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:taskcenter/Resources/Private/Templates')]);
241 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:taskcenter/Resources/Private/Partials')]);
242 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
243 'EXT:taskcenter/Resources/Private/Templates/InformationContent.html'
244 ));
245 $view->assignMultiple($assigns);
246 $this->content .= $view->render();
247 }
248
249 /**
250 * Render the headline of a task including a title and an optional description.
251 *
252 * @param string $title Title
253 * @param string $description Description
254 * @return string formatted title and description
255 */
256 public function description($title, $description = '')
257 {
258 $descriptionView = GeneralUtility::makeInstance(StandaloneView::class);
259 $descriptionView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
260 'EXT:taskcenter/Resources/Private/Partials/Description.html'
261 ));
262 $descriptionView->assign('title', $title);
263 $descriptionView->assign('description', $description);
264 return $descriptionView->render();
265 }
266
267 /**
268 * Render a list of items as a nicely formatted definition list including a
269 * link, icon, title and description.
270 * The keys of a single item are:
271 * - title: Title of the item
272 * - link: Link to the task
273 * - icon: Path to the icon or Icon as HTML if it begins with <img
274 * - description: Description of the task, using htmlspecialchars()
275 * - descriptionHtml: Description allowing HTML tags which will override the
276 * description
277 *
278 * @param array $items List of items to be displayed in the definition list.
279 * @param bool $mainMenu Set it to TRUE to render the main menu
280 * @return string Formatted definition list
281 */
282 public function renderListMenu($items, $mainMenu = false)
283 {
284 $assigns = [];
285 $assigns['mainMenu'] = $mainMenu;
286
287 // Change the sorting of items to the user's one
288 if ($mainMenu) {
289 $userSorting = unserialize($this->getBackendUser()->uc['taskcenter']['sorting']);
290 if (is_array($userSorting)) {
291 $newSorting = [];
292 foreach ($userSorting as $item) {
293 if (isset($items[$item])) {
294 $newSorting[] = $items[$item];
295 unset($items[$item]);
296 }
297 }
298 $items = $newSorting + $items;
299 }
300 }
301 if (is_array($items) && !empty($items)) {
302 foreach ($items as $itemKey => &$item) {
303 // Check for custom icon
304 if (!empty($item['icon'])) {
305 if (strpos($item['icon'], '<img ') === false) {
306 $iconFile = GeneralUtility::getFileAbsFileName($item['icon']);
307 if (@is_file($iconFile)) {
308 $item['iconFile'] = PathUtility::getAbsoluteWebPath($iconFile);
309 }
310 }
311 }
312 $id = $this->getUniqueKey($item['uid']);
313 $contentId = strtolower(str_replace('\\', '-', $id));
314 $item['uniqueKey'] = $id;
315 $item['contentId'] = $contentId;
316 // Collapsed & expanded menu items
317 if (isset($this->getBackendUser()->uc['taskcenter']['states'][$id]) && $this->getBackendUser()->uc['taskcenter']['states'][$id]) {
318 $item['ariaExpanded'] = 'true';
319 $item['collapseIcon'] = 'actions-view-list-expand';
320 $item['collapsed'] = '';
321 } else {
322 $item['ariaExpanded'] = 'false';
323 $item['collapseIcon'] = 'actions-view-list-collapse';
324 $item['collapsed'] = 'in';
325 }
326 // Active menu item
327 $panelState = (string)$this->MOD_SETTINGS['function'] == $item['uid'] ? 'panel-active' : 'panel-default';
328 $item['panelState'] = $panelState;
329 }
330 }
331 $assigns['items'] = $items;
332
333 // Rendering of the output via fluid
334 $view = GeneralUtility::makeInstance(StandaloneView::class);
335 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
336 'EXT:taskcenter/Resources/Private/Templates/ListMenu.html'
337 ));
338 $view->assignMultiple($assigns);
339 return $view->render();
340 }
341
342 /**
343 * Shows an overview list of available reports.
344 *
345 * @return string List of available reports
346 */
347 protected function indexAction()
348 {
349 $content = '';
350 $tasks = [];
351 $defaultIcon = 'EXT:taskcenter/Resources/Public/Icons/module-taskcenter.svg';
352 // Render the tasks only if there are any available
353 if (count($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'] ?? [])) {
354 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'] as $extKey => $extensionReports) {
355 foreach ($extensionReports as $taskClass => $task) {
356 if (!$this->checkAccess($extKey, $taskClass)) {
357 continue;
358 }
359 $link = BackendUtility::getModuleUrl('user_task') . '&SET[function]=' . $extKey . '.' . $taskClass;
360 $taskTitle = $this->getLanguageService()->sL($task['title']);
361 $taskDescriptionHtml = '';
362
363 if (class_exists($taskClass)) {
364 $taskInstance = GeneralUtility::makeInstance($taskClass, $this);
365 if ($taskInstance instanceof TaskInterface) {
366 $taskDescriptionHtml = $taskInstance->getOverview();
367 }
368 }
369 // Generate an array of all tasks
370 $uniqueKey = $this->getUniqueKey($extKey . '.' . $taskClass);
371 $tasks[$uniqueKey] = [
372 'title' => $taskTitle,
373 'descriptionHtml' => $taskDescriptionHtml,
374 'description' => $this->getLanguageService()->sL($task['description']),
375 'icon' => !empty($task['icon']) ? $task['icon'] : $defaultIcon,
376 'link' => $link,
377 'uid' => $extKey . '.' . $taskClass
378 ];
379 }
380 }
381 $content .= $this->renderListMenu($tasks, true);
382 } else {
383 $flashMessage = GeneralUtility::makeInstance(
384 FlashMessage::class,
385 $this->getLanguageService()->getLL('no-tasks'),
386 '',
387 FlashMessage::INFO
388 );
389 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
390 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
391 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
392 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
393 $defaultFlashMessageQueue->enqueue($flashMessage);
394 }
395 return $content;
396 }
397
398 /**
399 * Create the panel of buttons for submitting the form or otherwise
400 * perform operations.
401 */
402 protected function getButtons()
403 {
404 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
405
406 // Shortcut
407 $shortcutButton = $buttonBar->makeShortcutButton()
408 ->setModuleName($this->moduleName)
409 ->setSetVariables(['function']);
410 $buttonBar->addButton($shortcutButton);
411 }
412
413 /**
414 * Check the access to a task. Considered are:
415 * - Admins are always allowed
416 * - Tasks can be restriced to admins only
417 * - Tasks can be blinded for Users with TsConfig taskcenter.<extensionkey>.<taskName> = 0
418 *
419 * @param string $extKey Extension key
420 * @param string $taskClass Name of the task
421 * @return bool Access to the task allowed or not
422 */
423 protected function checkAccess($extKey, $taskClass)
424 {
425 // Check if task is blinded with TsConfig (taskcenter.<extkey>.<taskName>
426 $tsConfig = $this->getBackendUser()->getTSConfig('taskcenter.' . $extKey . '.' . $taskClass);
427 if (isset($tsConfig['value']) && (int)$tsConfig['value'] === 0) {
428 return false;
429 }
430 // Admins are always allowed
431 if ($this->getBackendUser()->isAdmin()) {
432 return true;
433 }
434 // Check if task is restricted to admins
435 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'][$extKey][$taskClass]['admin'] === 1) {
436 return false;
437 }
438 return true;
439 }
440
441 /**
442 * Returns HTML code to dislay an url in an iframe at the right side of the taskcenter
443 *
444 * @param string $url Url to display
445 * @return string Code that inserts the iframe (HTML)
446 */
447 public function urlInIframe($url)
448 {
449 $urlView = GeneralUtility::makeInstance(StandaloneView::class);
450 $urlView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName(
451 'EXT:taskcenter/Resources/Private/Partials/UrlInIframe.html'
452 ));
453 $urlView->assign('url', $url);
454 return $urlView->render();
455 }
456
457 /**
458 * Create a unique key from a string which can be used in JS for sorting
459 * Therefore '_' are replaced
460 *
461 * @param string $string string which is used to generate the identifier
462 * @return string Modified string
463 */
464 protected function getUniqueKey($string)
465 {
466 $search = ['.', '_'];
467 $replace = ['-', ''];
468 return str_replace($search, $replace, $string);
469 }
470
471 /**
472 * Returns the current BE user.
473 *
474 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
475 */
476 protected function getBackendUser()
477 {
478 return $GLOBALS['BE_USER'];
479 }
480
481 /**
482 * Returns LanguageService
483 *
484 * @return \TYPO3\CMS\Core\Localization\LanguageService
485 */
486 protected function getLanguageService()
487 {
488 return $GLOBALS['LANG'];
489 }
490
491 /**
492 * @return ModuleTemplate
493 */
494 public function getModuleTemplate()
495 {
496 return $this->moduleTemplate;
497 }
498 }