[TASK] Fix CGL errors
[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\Components\ButtonBar;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Utility\BackendUtility;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Messaging\FlashMessage;
25 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Core\Utility\PathUtility;
28 use TYPO3\CMS\Taskcenter\TaskInterface;
29
30 /**
31 * This class provides a taskcenter for BE users
32 */
33 class TaskModuleController extends BaseScriptClass
34 {
35 /**
36 * @var array
37 */
38 protected $pageinfo;
39
40 /**
41 * ModuleTemplate Container
42 *
43 * @var ModuleTemplate
44 */
45 protected $moduleTemplate;
46
47 /**
48 * The name of the module
49 *
50 * @var string
51 */
52 protected $moduleName = 'user_task';
53
54 /**
55 * Initializes the Module
56 */
57 public function __construct()
58 {
59 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
60 $this->moduleTemplate->getPageRenderer()->addCssFile(ExtensionManagementUtility::extRelPath('taskcenter') . 'Resources/Public/Css/styles.css');
61 $this->getLanguageService()->includeLLFile('EXT:taskcenter/Resources/Private/Language/locallang_task.xlf');
62 $this->MCONF = array(
63 'name' => $this->moduleName
64 );
65 parent::init();
66 }
67
68 /**
69 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
70 *
71 * @return void
72 */
73 public function menuConfig()
74 {
75 $this->MOD_MENU = array('mode' => array());
76 $this->MOD_MENU['mode']['information'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang.xlf:task_overview');
77 $this->MOD_MENU['mode']['tasks'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang.xlf:task_tasks');
78 /* Copied from parent::menuConfig, because parent is hardcoded to menu.function,
79 * however menu.function is already used for the individual tasks.
80 * Therefore we use menu.mode here.
81 */
82 // Page/be_user TSconfig settings and blinding of menu-items
83 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
84 $this->MOD_MENU['mode'] = $this->mergeExternalItems($this->MCONF['name'], 'mode', $this->MOD_MENU['mode']);
85 $this->MOD_MENU['mode'] = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $this->MOD_MENU['mode'], 'menu.mode');
86 parent::menuConfig();
87 }
88
89 /**
90 * Generates the menu based on $this->MOD_MENU
91 *
92 * @throws \InvalidArgumentException
93 */
94 protected function generateMenu()
95 {
96 $menu = $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
97 $menu->setIdentifier('WebFuncJumpMenu');
98 foreach ($this->MOD_MENU['mode'] as $controller => $title) {
99 $item = $menu
100 ->makeMenuItem()
101 ->setHref(
102 BackendUtility::getModuleUrl(
103 $this->moduleName,
104 [
105 'id' => $this->id,
106 'SET' => [
107 'mode' => $controller
108 ]
109 ]
110 )
111 )
112 ->setTitle($title);
113 if ($controller === $this->MOD_SETTINGS['mode']) {
114 $item->setActive(true);
115 }
116 $menu->addMenuItem($item);
117 }
118 $this->moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
119 }
120
121 /**
122 * Injects the request object for the current request or subrequest
123 * Simply calls main() and writes the content to the response
124 *
125 * @param ServerRequestInterface $request the current request
126 * @param ResponseInterface $response
127 * @return ResponseInterface the response with the content
128 */
129 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
130 {
131 $GLOBALS['SOBE'] = $this;
132 $this->main();
133
134 $this->moduleTemplate->setContent($this->content);
135
136 $response->getBody()->write($this->moduleTemplate->renderContent());
137 return $response;
138 }
139
140 /**
141 * Creates the module's content. In this case it rather acts as a kind of #
142 * dispatcher redirecting requests to specific tasks.
143 *
144 * @return void
145 */
146 public function main()
147 {
148 $this->getButtons();
149 $this->generateMenu();
150 $this->moduleTemplate->addJavaScriptCode(
151 'TaskCenterInlineJavascript',
152 'if (top.fsMod) { top.fsMod.recentIds["web"] = 0; }'
153 );
154
155 // Render content depending on the mode
156 $mode = (string)$this->MOD_SETTINGS['mode'];
157 if ($mode === 'information') {
158 $this->renderInformationContent();
159 } else {
160 $this->renderModuleContent();
161 }
162 // Renders the module page
163 $this->moduleTemplate->setTitle($this->getLanguageService()->getLL('title'));
164 }
165
166 /**
167 * Prints out the module's HTML
168 *
169 * @return void
170 */
171 public function printContent()
172 {
173 echo $this->content;
174 }
175
176 /**
177 * Generates the module content by calling the selected task
178 *
179 * @return void
180 */
181 protected function renderModuleContent()
182 {
183 $chosenTask = (string)$this->MOD_SETTINGS['function'];
184 // Render the taskcenter task as default
185 if (empty($chosenTask) || $chosenTask == 'index') {
186 $chosenTask = 'taskcenter.tasks';
187 }
188 // Render the task
189 $actionContent = '';
190 list($extKey, $taskClass) = explode('.', $chosenTask, 2);
191 if (class_exists($taskClass)) {
192 $taskInstance = GeneralUtility::makeInstance($taskClass, $this);
193 if ($taskInstance instanceof TaskInterface) {
194 // Check if the task is restricted to admins only
195 if ($this->checkAccess($extKey, $taskClass)) {
196 $actionContent .= $taskInstance->getTask();
197 } else {
198 $flashMessage = GeneralUtility::makeInstance(
199 FlashMessage::class,
200 $this->getLanguageService()->getLL('error-access', true),
201 $this->getLanguageService()->getLL('error_header'),
202 FlashMessage::ERROR
203 );
204 $actionContent .= $flashMessage->render();
205 }
206 } else {
207 // Error if the task is not an instance of \TYPO3\CMS\Taskcenter\TaskInterface
208 $flashMessage = GeneralUtility::makeInstance(
209 FlashMessage::class,
210 sprintf($this->getLanguageService()->getLL('error_no-instance', true), $taskClass, TaskInterface::class),
211 $this->getLanguageService()->getLL('error_header'),
212 FlashMessage::ERROR
213 );
214 $actionContent .= $flashMessage->render();
215 }
216 } else {
217 $flashMessage = GeneralUtility::makeInstance(
218 FlashMessage::class,
219 $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tabdescr'),
220 $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'),
221 FlashMessage::INFO
222 );
223 $actionContent .= $flashMessage->render();
224 }
225 $content = '<div id="taskcenter-main">
226 <div id="taskcenter-menu">' . $this->indexAction() . '</div>
227 <div id="taskcenter-item" class="' . htmlspecialchars(($extKey . '-' . $taskClass)) . '">' . $actionContent . '
228 </div>
229 </div>';
230 $this->content .= $content;
231 }
232
233 /**
234 * Generates the information content
235 *
236 * @return void
237 */
238 protected function renderInformationContent()
239 {
240 $content = $this->description($this->getLanguageService()->getLL('mlang_tabs_tab'), $this->getLanguageService()->sL('LLL:EXT:taskcenter/Resources/Private/Language/locallang_mod.xlf:mlang_labels_tabdescr'));
241 $content .= $this->getLanguageService()->getLL('taskcenter-about');
242 if ($this->getBackendUser()->isAdmin()) {
243 $content .= '<br /><br />' . $this->description($this->getLanguageService()->getLL('taskcenter-adminheader'), $this->getLanguageService()->getLL('taskcenter-admin'));
244 }
245 $this->content .= $content;
246 }
247
248 /**
249 * Render the headline of a task including a title and an optional description.
250 *
251 * @param string $title Title
252 * @param string $description Description
253 * @return string formatted title and description
254 */
255 public function description($title, $description = '')
256 {
257 $content = '<h1>' . nl2br(htmlspecialchars($title)) . '</h1>';
258 if (!empty($description)) {
259 $content .= '<p class="description">' . nl2br(htmlspecialchars($description)) . '</p>';
260 }
261 return $content;
262 }
263
264 /**
265 * Render a list of items as a nicely formated definition list including a
266 * link, icon, title and description.
267 * The keys of a single item are:
268 * - title: Title of the item
269 * - link: Link to the task
270 * - icon: Path to the icon or Icon as HTML if it begins with <img
271 * - description: Description of the task, using htmlspecialchars()
272 * - descriptionHtml: Description allowing HTML tags which will override the
273 * description
274 *
275 * @param array $items List of items to be displayed in the definition list.
276 * @param bool $mainMenu Set it to TRUE to render the main menu
277 * @return string Fefinition list
278 */
279 public function renderListMenu($items, $mainMenu = false)
280 {
281 $content = ($section = '');
282 $count = 0;
283 // Change the sorting of items to the user's one
284 if ($mainMenu) {
285 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Taskcenter/Taskcenter');
286 $userSorting = unserialize($this->getBackendUser()->uc['taskcenter']['sorting']);
287 if (is_array($userSorting)) {
288 $newSorting = array();
289 foreach ($userSorting as $item) {
290 if (isset($items[$item])) {
291 $newSorting[] = $items[$item];
292 unset($items[$item]);
293 }
294 }
295 $items = $newSorting + $items;
296 }
297 }
298 if (is_array($items) && !empty($items)) {
299 foreach ($items as $item) {
300 $title = htmlspecialchars($item['title']);
301 $icon = ($additionalClass = ($collapsedStyle = ''));
302 // Check for custom icon
303 if (!empty($item['icon'])) {
304 if (strpos($item['icon'], '<img ') === false) {
305 $absIconPath = GeneralUtility::getFileAbsFileName($item['icon']);
306 // If the file indeed exists, assemble relative path to it
307 if (file_exists($absIconPath)) {
308 $icon = '../' . str_replace(PATH_site, '', $absIconPath);
309 $icon = '<img src="' . $icon . '" title="' . $title . '" alt="' . $title . '" />';
310 }
311 if (@is_file($icon)) {
312 $icon = '<img src="' . PathUtility::getAbsoluteWebPath($icon) . '" width="16" height="16" title="' . $title . '" alt="' . $title . '" />';
313 }
314 } else {
315 $icon = $item['icon'];
316 }
317 }
318 $description = $item['descriptionHtml'] ?: '<p>' . nl2br(htmlspecialchars($item['description'])) . '</p>';
319 $id = $this->getUniqueKey($item['uid']);
320 // Collapsed & expanded menu items
321 if ($mainMenu && isset($this->getBackendUser()->uc['taskcenter']['states'][$id]) && $this->getBackendUser()->uc['taskcenter']['states'][$id]) {
322 $collapsedStyle = 'style="display:none"';
323 $additionalClass = 'collapsed';
324 } else {
325 $additionalClass = 'expanded';
326 }
327 // First & last menu item
328 if ($count == 0) {
329 $additionalClass .= ' first-item';
330 } elseif ($count + 1 === count($items)) {
331 $additionalClass .= ' last-item';
332 }
333 // Active menu item
334 $active = (string)$this->MOD_SETTINGS['function'] == $item['uid'] ? ' active-task' : '';
335 // Main menu: Render additional syntax to sort tasks
336 if ($mainMenu) {
337 $section = '<div class="down"><i class="fa fa-caret-down fa-fw"></i></div>
338 <div class="drag"><i class="fa fa-arrows"></i></div>';
339 $backgroundClass = 't3-row-header ';
340 } else {
341 $backgroundClass = '';
342 }
343 $content .= '<li class="' . $additionalClass . $active . '" id="el_' . $id . '">
344 ' . $section . '
345 <div class="image">' . $icon . '</div>
346 <div class="' . $backgroundClass . 'link"><a href="' . $item['link'] . '">' . $title . '</a></div>
347 <div class="content " ' . $collapsedStyle . '>' . $description . '</div>
348 </li>';
349 $count++;
350 }
351 $navigationId = $mainMenu ? 'id="task-list"' : '';
352 $content = '<ul ' . $navigationId . ' class="task-list">' . $content . '</ul>';
353 }
354 return $content;
355 }
356
357 /**
358 * Shows an overview list of available reports.
359 *
360 * @return string List of available reports
361 */
362 protected function indexAction()
363 {
364 $content = '';
365 $tasks = array();
366 $icon = ExtensionManagementUtility::extRelPath('taskcenter') . 'Resources/Public/Icons/module-taskcenter.svg';
367 // Render the tasks only if there are any available
368 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter']) && !empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'])) {
369 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'] as $extKey => $extensionReports) {
370 foreach ($extensionReports as $taskClass => $task) {
371 if (!$this->checkAccess($extKey, $taskClass)) {
372 continue;
373 }
374 $link = BackendUtility::getModuleUrl('user_task') . '&SET[function]=' . $extKey . '.' . $taskClass;
375 $taskTitle = $this->getLanguageService()->sL($task['title']);
376 $taskDescriptionHtml = '';
377 // Check for custom icon
378 if (!empty($task['icon'])) {
379 $icon = GeneralUtility::getFileAbsFileName($task['icon']);
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] = array(
390 'title' => $taskTitle,
391 'descriptionHtml' => $taskDescriptionHtml,
392 'description' => $this->getLanguageService()->sL($task['description']),
393 'icon' => $icon,
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', true),
404 '',
405 FlashMessage::INFO
406 );
407 $this->content .= $flashMessage->render();
408 }
409 return $content;
410 }
411
412 /**
413 * Create the panel of buttons for submitting the form or otherwise
414 * perform operations.
415 *
416 * @return void
417 */
418 protected function getButtons()
419 {
420 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
421
422 // Fullscreen Button
423 $url = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
424 $onClick = 'devlogWin=window.open(' . GeneralUtility::quoteJSvalue($url) . ',\'taskcenter\',\'width=790,status=0,menubar=1,resizable=1,location=0,scrollbars=1,toolbar=0\');return false;';
425 $fullscreenButton = $buttonBar->makeLinkButton()
426 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.openInNewWindow', true))
427 ->setOnClick($onClick)
428 ->setHref('#')
429 ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-window-open', Icon::SIZE_SMALL))
430 ;
431 $buttonBar->addButton($fullscreenButton, ButtonBar::BUTTON_POSITION_RIGHT, 1);
432
433 // Shortcut
434 $shortcutButton = $buttonBar->makeShortcutButton()
435 ->setModuleName($this->moduleName)
436 ->setSetVariables(['function']);
437 $buttonBar->addButton($shortcutButton);
438 }
439
440 /**
441 * Check the access to a task. Considered are:
442 * - Admins are always allowed
443 * - Tasks can be restriced to admins only
444 * - Tasks can be blinded for Users with TsConfig taskcenter.<extensionkey>.<taskName> = 0
445 *
446 * @param string $extKey Extension key
447 * @param string $taskClass Name of the task
448 * @return bool Access to the task allowed or not
449 */
450 protected function checkAccess($extKey, $taskClass)
451 {
452 // Check if task is blinded with TsConfig (taskcenter.<extkey>.<taskName>
453 $tsConfig = $this->getBackendUser()->getTSConfig('taskcenter.' . $extKey . '.' . $taskClass);
454 if (isset($tsConfig['value']) && (int)$tsConfig['value'] === 0) {
455 return false;
456 }
457 // Admins are always allowed
458 if ($this->getBackendUser()->isAdmin()) {
459 return true;
460 }
461 // Check if task is restricted to admins
462 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'][$extKey][$taskClass]['admin'] === 1) {
463 return false;
464 }
465 return true;
466 }
467
468 /**
469 * Returns HTML code to dislay an url in an iframe at the right side of the taskcenter
470 *
471 * @param string $url Url to display
472 * @return string Code that inserts the iframe (HTML)
473 */
474 public function urlInIframe($url)
475 {
476 return '<iframe scrolling="auto" width="100%" src="' . $url . '" name="list_frame" id="list_frame" frameborder="no"></iframe>';
477 }
478
479 /**
480 * Create a unique key from a string which can be used in JS for sorting
481 * Therefore '_' are replaced
482 *
483 * @param string $string string which is used to generate the identifier
484 * @return string Modified string
485 */
486 protected function getUniqueKey($string)
487 {
488 $search = array('.', '_');
489 $replace = array('-', '');
490 return str_replace($search, $replace, $string);
491 }
492
493 /**
494 * This method prepares the link for opening the devlog in a new window
495 *
496 * @return string Hyperlink with icon and appropriate JavaScript
497 */
498 protected function openInNewWindow()
499 {
500 $url = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
501 $onClick = 'devlogWin=window.open(' . GeneralUtility::quoteJSvalue($url) . ',\'taskcenter\',\'width=790,status=0,menubar=1,resizable=1,location=0,scrollbars=1,toolbar=0\');return false;';
502 $content = '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.openInNewWindow', true) . '">'
503 . $this->moduleTemplate->getIconFactory()->getIcon('actions-window-open', Icon::SIZE_SMALL)->render()
504 . '</a>';
505 return $content;
506 }
507
508 /**
509 * Returns the current BE user.
510 *
511 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
512 */
513 protected function getBackendUser()
514 {
515 return $GLOBALS['BE_USER'];
516 }
517
518 /**
519 * Returns LanguageService
520 *
521 * @return \TYPO3\CMS\Lang\LanguageService
522 */
523 protected function getLanguageService()
524 {
525 return $GLOBALS['LANG'];
526 }
527
528 /**
529 * @return ModuleTemplate
530 */
531 public function getModuleTemplate()
532 {
533 return $this->moduleTemplate;
534 }
535 }