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