[TASK] Correct directory names for Resources
[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 TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Taskcenter\TaskInterface;
23
24 /**
25 * This class provides a taskcenter for BE users
26 */
27 class TaskModuleController extends \TYPO3\CMS\Backend\Module\BaseScriptClass {
28
29 /**
30 * @var array
31 */
32 protected $pageinfo;
33
34 /**
35 * The name of the module
36 *
37 * @var string
38 */
39 protected $moduleName = 'user_task';
40
41 /**
42 * Initializes the Module
43 */
44 public function __construct() {
45 $this->getLanguageService()->includeLLFile('EXT:taskcenter/task/locallang.xlf');
46 $this->MCONF = array(
47 'name' => $this->moduleName
48 );
49 parent::init();
50 // Initialize document
51 $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
52 $this->doc->setModuleTemplate(ExtensionManagementUtility::extPath('taskcenter') . 'Resources/Private/Templates/mod_template.html');
53 $this->doc->backPath = $GLOBALS['BACK_PATH'];
54 $this->getPageRenderer()->loadJquery();
55 $this->doc->addStyleSheet('tx_taskcenter', '../' . ExtensionManagementUtility::siteRelPath('taskcenter') . 'Resources/Public/Css/styles.css');
56 }
57
58 /**
59 * Adds items to the ->MOD_MENU array. Used for the function menu selector.
60 *
61 * @return void
62 */
63 public function menuConfig() {
64 $this->MOD_MENU = array('mode' => array());
65 $this->MOD_MENU['mode']['information'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/locallang.xlf:task_overview');
66 $this->MOD_MENU['mode']['tasks'] = $this->getLanguageService()->sL('LLL:EXT:taskcenter/locallang.xlf:task_tasks');
67 /* Copied from parent::menuConfig, because parent is hardcoded to menu.function,
68 * however menu.function is already used for the individual tasks.
69 * Therefore we use menu.mode here.
70 */
71 // Page/be_user TSconfig settings and blinding of menu-items
72 $this->modTSconfig = BackendUtility::getModTSconfig($this->id, 'mod.' . $this->moduleName);
73 $this->MOD_MENU['mode'] = $this->mergeExternalItems($this->MCONF['name'], 'mode', $this->MOD_MENU['mode']);
74 $this->MOD_MENU['mode'] = BackendUtility::unsetMenuItems($this->modTSconfig['properties'], $this->MOD_MENU['mode'], 'menu.mode');
75 parent::menuConfig();
76 }
77
78 /**
79 * Creates the module's content. In this case it rather acts as a kind of #
80 * dispatcher redirecting requests to specific tasks.
81 *
82 * @return void
83 */
84 public function main() {
85 $docHeaderButtons = $this->getButtons();
86 $markers = array();
87 $this->doc->postCode = $this->doc->wrapScriptTags('if (top.fsMod) { top.fsMod.recentIds["web"] = 0; }');
88
89 // Render content depending on the mode
90 $mode = (string)$this->MOD_SETTINGS['mode'];
91 if ($mode === 'information') {
92 $this->renderInformationContent();
93 } else {
94 $this->renderModuleContent();
95 }
96 // Compile document
97 $markers['FUNC_MENU'] = BackendUtility::getFuncMenu(0, 'SET[mode]', $this->MOD_SETTINGS['mode'], $this->MOD_MENU['mode']);
98 $markers['CONTENT'] = $this->content;
99 // Build the <body> for the module
100 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
101 // Renders the module page
102 $this->content = $this->doc->render($this->getLanguageService()->getLL('title'), $this->content);
103 }
104
105 /**
106 * Prints out the module's HTML
107 *
108 * @return void
109 */
110 public function printContent() {
111 echo $this->content;
112 }
113
114 /**
115 * Generates the module content by calling the selected task
116 *
117 * @return void
118 */
119 protected function renderModuleContent() {
120 $chosenTask = (string)$this->MOD_SETTINGS['function'];
121 // Render the taskcenter task as default
122 if (empty($chosenTask) || $chosenTask == 'index') {
123 $chosenTask = 'taskcenter.tasks';
124 }
125 // Render the task
126 $actionContent = '';
127 list($extKey, $taskClass) = explode('.', $chosenTask, 2);
128 if (class_exists($taskClass)) {
129 $taskInstance = GeneralUtility::makeInstance($taskClass, $this);
130 if ($taskInstance instanceof TaskInterface) {
131 // Check if the task is restricted to admins only
132 if ($this->checkAccess($extKey, $taskClass)) {
133 $actionContent .= $taskInstance->getTask();
134 } else {
135 $flashMessage = GeneralUtility::makeInstance(
136 FlashMessage::class,
137 $this->getLanguageService()->getLL('error-access', TRUE),
138 $this->getLanguageService()->getLL('error_header'),
139 FlashMessage::ERROR
140 );
141 $actionContent .= $flashMessage->render();
142 }
143 } else {
144 // Error if the task is not an instance of \TYPO3\CMS\Taskcenter\TaskInterface
145 $flashMessage = GeneralUtility::makeInstance(
146 FlashMessage::class,
147 sprintf($this->getLanguageService()->getLL('error_no-instance', TRUE), $taskClass, TaskInterface::class),
148 $this->getLanguageService()->getLL('error_header'),
149 FlashMessage::ERROR
150 );
151 $actionContent .= $flashMessage->render();
152 }
153 } else {
154 $flashMessage = GeneralUtility::makeInstance(
155 FlashMessage::class,
156 $this->getLanguageService()->sL('LLL:EXT:taskcenter/task/locallang_mod.xlf:mlang_labels_tabdescr'),
157 $this->getLanguageService()->sL('LLL:EXT:taskcenter/task/locallang_mod.xlf:mlang_tabs_tab'),
158 FlashMessage::INFO
159 );
160 $actionContent .= $flashMessage->render();
161 }
162 $content = '<div id="taskcenter-main">
163 <div id="taskcenter-menu">' . $this->indexAction() . '</div>
164 <div id="taskcenter-item" class="' . htmlspecialchars(($extKey . '-' . $taskClass)) . '">' . $actionContent . '
165 </div>
166 </div>';
167 $this->content .= $content;
168 }
169
170 /**
171 * Generates the information content
172 *
173 * @return void
174 */
175 protected function renderInformationContent() {
176 $content = $this->description($this->getLanguageService()->getLL('mlang_tabs_tab'), $this->getLanguageService()->sL('LLL:EXT:taskcenter/task/locallang_mod.xlf:mlang_labels_tabdescr'));
177 $content .= $this->getLanguageService()->getLL('taskcenter-about');
178 if ($this->getBackendUser()->isAdmin()) {
179 $content .= '<br /><br />' . $this->description($this->getLanguageService()->getLL('taskcenter-adminheader'), $this->getLanguageService()->getLL('taskcenter-admin'));
180 }
181 $this->content .= $content;
182 }
183
184 /**
185 * Render the headline of a task including a title and an optional description.
186 *
187 * @param string $title Title
188 * @param string $description Description
189 * @return string formatted title and description
190 */
191 public function description($title, $description = '') {
192 $content = '<h1>' . nl2br(htmlspecialchars($title)) . '</h1>';
193 if (!empty($description)) {
194 $content .= '<p class="description">' . nl2br(htmlspecialchars($description)) . '</p>';
195 }
196 return $content;
197 }
198
199 /**
200 * Render a list of items as a nicely formated definition list including a
201 * link, icon, title and description.
202 * The keys of a single item are:
203 * - title: Title of the item
204 * - link: Link to the task
205 * - icon: Path to the icon or Icon as HTML if it begins with <img
206 * - description: Description of the task, using htmlspecialchars()
207 * - descriptionHtml: Description allowing HTML tags which will override the
208 * description
209 *
210 * @param array $items List of items to be displayed in the definition list.
211 * @param bool $mainMenu Set it to TRUE to render the main menu
212 * @return string Fefinition list
213 */
214 public function renderListMenu($items, $mainMenu = FALSE) {
215 $content = ($section = '');
216 $count = 0;
217 // Change the sorting of items to the user's one
218 if ($mainMenu) {
219 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Taskcenter/Taskcenter');
220 $userSorting = unserialize($this->getBackendUser()->uc['taskcenter']['sorting']);
221 if (is_array($userSorting)) {
222 $newSorting = array();
223 foreach ($userSorting as $item) {
224 if (isset($items[$item])) {
225 $newSorting[] = $items[$item];
226 unset($items[$item]);
227 }
228 }
229 $items = $newSorting + $items;
230 }
231 }
232 if (is_array($items) && !empty($items)) {
233 foreach ($items as $item) {
234 $title = htmlspecialchars($item['title']);
235 $icon = ($additionalClass = ($collapsedStyle = ''));
236 // Check for custom icon
237 if (!empty($item['icon'])) {
238 if (strpos($item['icon'], '<img ') === FALSE) {
239 $absIconPath = GeneralUtility::getFileAbsFilename($item['icon']);
240 // If the file indeed exists, assemble relative path to it
241 if (file_exists($absIconPath)) {
242 $icon = $GLOBALS['BACK_PATH'] . '../' . str_replace(PATH_site, '', $absIconPath);
243 $icon = '<img src="' . $icon . '" title="' . $title . '" alt="' . $title . '" />';
244 }
245 if (@is_file($icon)) {
246 $icon = '<img' . IconUtility::skinImg($GLOBALS['BACK_PATH'], $icon, 'width="16" height="16"') . ' title="' . $title . '" alt="' . $title . '" />';
247 }
248 } else {
249 $icon = $item['icon'];
250 }
251 }
252 $description = $item['descriptionHtml'] ?: '<p>' . nl2br(htmlspecialchars($item['description'])) . '</p>';
253 $id = $this->getUniqueKey($item['uid']);
254 // Collapsed & expanded menu items
255 if ($mainMenu && isset($this->getBackendUser()->uc['taskcenter']['states'][$id]) && $this->getBackendUser()->uc['taskcenter']['states'][$id]) {
256 $collapsedStyle = 'style="display:none"';
257 $additionalClass = 'collapsed';
258 } else {
259 $additionalClass = 'expanded';
260 }
261 // First & last menu item
262 if ($count == 0) {
263 $additionalClass .= ' first-item';
264 } elseif ($count + 1 === count($items)) {
265 $additionalClass .= ' last-item';
266 }
267 // Active menu item
268 $active = (string)$this->MOD_SETTINGS['function'] == $item['uid'] ? ' active-task' : '';
269 // Main menu: Render additional syntax to sort tasks
270 if ($mainMenu) {
271 $dragIcon = IconUtility::getSpriteIcon('actions-document-move', array('title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.move', TRUE)));
272 $section = '<div class="down">&nbsp;</div>
273 <div class="drag">' . $dragIcon . '</div>';
274 $backgroundClass = 't3-row-header ';
275 } else {
276 $backgroundClass = '';
277 }
278 $content .= '<li class="' . $additionalClass . $active . '" id="el_' . $id . '">
279 ' . $section . '
280 <div class="image">' . $icon . '</div>
281 <div class="' . $backgroundClass . 'link"><a href="' . $item['link'] . '">' . $title . '</a></div>
282 <div class="content " ' . $collapsedStyle . '>' . $description . '</div>
283 </li>';
284 $count++;
285 }
286 $navigationId = $mainMenu ? 'id="task-list"' : '';
287 $content = '<ul ' . $navigationId . ' class="task-list">' . $content . '</ul>';
288 }
289 return $content;
290 }
291
292 /**
293 * Shows an overview list of available reports.
294 *
295 * @return string List of available reports
296 */
297 protected function indexAction() {
298 $content = '';
299 $tasks = array();
300 $icon = ExtensionManagementUtility::extRelPath('taskcenter') . 'Resources/Public/Icons/module-taskcenter.svg';
301 // Render the tasks only if there are any available
302 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter']) && !empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'])) {
303 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'] as $extKey => $extensionReports) {
304 foreach ($extensionReports as $taskClass => $task) {
305 if (!$this->checkAccess($extKey, $taskClass)) {
306 continue;
307 }
308 $link = BackendUtility::getModuleUrl('user_task') . '&SET[function]=' . $extKey . '.' . $taskClass;
309 $taskTitle = $this->getLanguageService()->sL($task['title']);
310 $taskDescriptionHtml = '';
311 // Check for custom icon
312 if (!empty($task['icon'])) {
313 $icon = GeneralUtility::getFileAbsFilename($task['icon']);
314 }
315 if (class_exists($taskClass)) {
316 $taskInstance = GeneralUtility::makeInstance($taskClass, $this);
317 if ($taskInstance instanceof TaskInterface) {
318 $taskDescriptionHtml = $taskInstance->getOverview();
319 }
320 }
321 // Generate an array of all tasks
322 $uniqueKey = $this->getUniqueKey($extKey . '.' . $taskClass);
323 $tasks[$uniqueKey] = array(
324 'title' => $taskTitle,
325 'descriptionHtml' => $taskDescriptionHtml,
326 'description' => $this->getLanguageService()->sL($task['description']),
327 'icon' => $icon,
328 'link' => $link,
329 'uid' => $extKey . '.' . $taskClass
330 );
331 }
332 }
333 $content .= $this->renderListMenu($tasks, TRUE);
334 } else {
335 $flashMessage = GeneralUtility::makeInstance(
336 FlashMessage::class,
337 $this->getLanguageService()->getLL('no-tasks', TRUE),
338 '',
339 FlashMessage::INFO
340 );
341 $this->content .= $flashMessage->render();
342 }
343 return $content;
344 }
345
346 /**
347 * Create the panel of buttons for submitting the form or otherwise
348 * perform operations.
349 *
350 * @return array All available buttons as an assoc. array
351 */
352 protected function getButtons() {
353 $buttons = array(
354 'shortcut' => '',
355 'open_new_window' => $this->openInNewWindow()
356 );
357 // Shortcut
358 if ($this->getBackendUser()->mayMakeShortcut()) {
359 $buttons['shortcut'] = $this->doc->makeShortcutIcon('', 'function', $this->moduleName);
360 }
361 return $buttons;
362 }
363
364 /**
365 * Check the access to a task. Considered are:
366 * - Admins are always allowed
367 * - Tasks can be restriced to admins only
368 * - Tasks can be blinded for Users with TsConfig taskcenter.<extensionkey>.<taskName> = 0
369 *
370 * @param string $extKey Extension key
371 * @param string $taskClass Name of the task
372 * @return bool Access to the task allowed or not
373 */
374 protected function checkAccess($extKey, $taskClass) {
375 // Check if task is blinded with TsConfig (taskcenter.<extkey>.<taskName>
376 $tsConfig = $this->getBackendUser()->getTSConfig('taskcenter.' . $extKey . '.' . $taskClass);
377 if (isset($tsConfig['value']) && (int)$tsConfig['value'] === 0) {
378 return FALSE;
379 }
380 // Admins are always allowed
381 if ($this->getBackendUser()->isAdmin()) {
382 return TRUE;
383 }
384 // Check if task is restricted to admins
385 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['taskcenter'][$extKey][$taskClass]['admin'] === 1) {
386 return FALSE;
387 }
388 return TRUE;
389 }
390
391 /**
392 * Returns HTML code to dislay an url in an iframe at the right side of the taskcenter
393 *
394 * @param string $url Url to display
395 * @param int $max
396 * @return string Code that inserts the iframe (HTML)
397 */
398 public function urlInIframe($url, $max = 0) {
399 return '<iframe scrolling="auto" width="100%" src="' . $url . '" name="list_frame" id="list_frame" frameborder="no"></iframe>';
400 }
401
402 /**
403 * Create a unique key from a string which can be used in Prototype's Sortable
404 * Therefore '_' are replaced
405 *
406 * @param string $string string which is used to generate the identifier
407 * @return string Modified string
408 */
409 protected function getUniqueKey($string) {
410 $search = array('.', '_');
411 $replace = array('-', '');
412 return str_replace($search, $replace, $string);
413 }
414
415 /**
416 * This method prepares the link for opening the devlog in a new window
417 *
418 * @return string Hyperlink with icon and appropriate JavaScript
419 */
420 protected function openInNewWindow() {
421 $url = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
422 $onClick = 'devlogWin=window.open(' . GeneralUtility::quoteJSvalue($url) . ',\'taskcenter\',\'width=790,status=0,menubar=1,resizable=1,location=0,scrollbars=1,toolbar=0\');return false;';
423 $content = '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' .
424 IconUtility::getSpriteIcon('actions-window-open', array('title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.openInNewWindow', TRUE))) .
425 '</a>';
426 return $content;
427 }
428
429 /**
430 * Returns the current BE user.
431 *
432 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
433 */
434 protected function getBackendUser() {
435 return $GLOBALS['BE_USER'];
436 }
437
438 /**
439 * Returns LanguageService
440 *
441 * @return \TYPO3\CMS\Lang\LanguageService
442 */
443 protected function getLanguageService() {
444 return $GLOBALS['LANG'];
445 }
446
447 }