[BUGFIX] Taskcenter: Removed call to deprecated method render()
[Packages/TYPO3.CMS.git] / typo3 / sysext / sys_action / Classes / ActionTask.php
1 <?php
2 namespace TYPO3\CMS\SysAction;
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\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\Page\PageRenderer;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * This class provides a task for the taskcenter
25 */
26 class ActionTask implements \TYPO3\CMS\Taskcenter\TaskInterface
27 {
28 /**
29 * @var \TYPO3\CMS\Taskcenter\Controller\TaskModuleController
30 */
31 protected $taskObject;
32
33 /**
34 * All hook objects get registered here for later use
35 *
36 * @var array
37 */
38 protected $hookObjects = array();
39
40 /**
41 * URL to task module
42 *
43 * @var string
44 */
45 protected $moduleUrl;
46
47 /**
48 * @var IconFactory
49 */
50 protected $iconFactory;
51
52 /**
53 * Constructor
54 */
55 public function __construct(\TYPO3\CMS\Taskcenter\Controller\TaskModuleController $taskObject)
56 {
57 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
58 $this->moduleUrl = BackendUtility::getModuleUrl('user_task');
59 $this->taskObject = $taskObject;
60 $this->getLanguageService()->includeLLFile('EXT:sys_action/Resources/Private/Language/locallang.xlf');
61 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['sys_action']['tx_sysaction_task'])) {
62 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['sys_action']['tx_sysaction_task'] as $classRef) {
63 $this->hookObjects[] = GeneralUtility::getUserObj($classRef);
64 }
65 }
66 }
67
68 /**
69 * This method renders the task
70 *
71 * @return string The task as HTML
72 */
73 public function getTask()
74 {
75 $content = '';
76 $show = (int)GeneralUtility::_GP('show');
77 foreach ($this->hookObjects as $hookObject) {
78 if (method_exists($hookObject, 'getTask')) {
79 $show = $hookObject->getTask($show, $this);
80 }
81 }
82 // If no task selected, render the menu
83 if ($show == 0) {
84 $content .= $this->taskObject->description($this->getLanguageService()->getLL('sys_action'), $this->getLanguageService()->getLL('description'));
85 $content .= $this->renderActionList();
86 } else {
87 $record = BackendUtility::getRecord('sys_action', $show);
88 // If the action is not found
89 if (empty($record)) {
90 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_error-not-found', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
91 $content .= $flashMessage->render();
92 } else {
93 // Render the task
94 $content .= $this->taskObject->description($record['title'], $record['description']);
95 // Output depends on the type
96 switch ($record['type']) {
97 case 1:
98 $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
99 $pageRenderer->loadRequireJsModule('TYPO3/CMS/SysAction/ActionTask');
100 $content .= $this->viewNewBackendUser($record);
101 break;
102 case 2:
103 $content .= $this->viewSqlQuery($record);
104 break;
105 case 3:
106 $content .= $this->viewRecordList($record);
107 break;
108 case 4:
109 $content .= $this->viewEditRecord($record);
110 break;
111 case 5:
112 $content .= $this->viewNewRecord($record);
113 break;
114 default:
115 $flashMessage = GeneralUtility::makeInstance(
116 \TYPO3\CMS\Core\Messaging\FlashMessage::class,
117 $this->getLanguageService()->getLL('action_noType', true),
118 $this->getLanguageService()->getLL('action_error'),
119 \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR
120 );
121 $content .= '<br />' . $flashMessage->render();
122 }
123 }
124 }
125 return $content;
126 }
127
128 /**
129 * General overview over the task in the taskcenter menu
130 *
131 * @return string Overview as HTML
132 */
133 public function getOverview()
134 {
135 $content = '<p>' . $this->getLanguageService()->getLL('description') . '</p>';
136 // Get the actions
137 $actionList = $this->getActions();
138 if (!empty($actionList)) {
139 $items = '';
140 // Render a single action menu item
141 foreach ($actionList as $action) {
142 $active = GeneralUtility::_GP('show') === $action['uid'] ? ' class="active" ' : '';
143 $items .= '<li' . $active . '>
144 <a href="' . $action['link'] . '" title="' . htmlspecialchars($action['description']) . '">' . htmlspecialchars($action['title']) . '</a>
145 </li>';
146 }
147 $content .= '<ul>' . $items . '</ul>';
148 }
149 return $content;
150 }
151
152 /**
153 * Get all actions of an user. Admins can see any action, all others only those
154 * which are allowed in sys_action record itself.
155 *
156 * @return array Array holding every needed information of a sys_action
157 */
158 protected function getActions()
159 {
160 $actionList = array();
161 // admins can see any record
162 if ($this->getBackendUser()->isAdmin()) {
163 $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_action', '', '', 'sys_action.sorting');
164 } else {
165 // Editors can only see the actions which are assigned to a usergroup they belong to
166 $additionalWhere = 'be_groups.uid IN (' . ($this->getBackendUser()->groupList ?: 0) . ')';
167 $res = $this->getDatabaseConnection()->exec_SELECT_mm_query('sys_action.*', 'sys_action', 'sys_action_asgr_mm', 'be_groups', ' AND sys_action.hidden=0 AND ' . $additionalWhere, 'sys_action.uid', 'sys_action.sorting');
168 }
169 while ($actionRow = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
170 $editActionLink = '';
171 // Admins are allowed to edit sys_action records
172 if ($this->getBackendUser()->isAdmin()) {
173 $link = BackendUtility::getModuleUrl(
174 'record_edit',
175 array(
176 'edit[sys_action][' . $actionRow['uid'] . ']' => 'edit',
177 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
178 ),
179 false,
180 true
181 );
182 $title = 'title="' . $this->getLanguageService()->getLL('edit-sys_action') . '"';
183 $icon = $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render();
184 $editActionLink = '<a class="edit" href="' . $link . '"' . $title . '>';
185 $editActionLink .= $icon . $this->getLanguageService()->getLL('edit-sys_action') . '</a>';
186 }
187 $actionList[] = array(
188 'uid' => $actionRow['uid'],
189 'title' => $actionRow['title'],
190 'description' => $actionRow['description'],
191 'descriptionHtml' => nl2br(htmlspecialchars($actionRow['description'])) . $editActionLink,
192 'link' => $this->moduleUrl . '&SET[function]=sys_action.TYPO3\\CMS\\SysAction\\ActionTask&show=' . $actionRow['uid']
193 );
194 }
195 $this->getDatabaseConnection()->sql_free_result($res);
196 return $actionList;
197 }
198
199 /**
200 * Render the menu of sys_actions
201 *
202 * @return string List of sys_actions as HTML
203 */
204 protected function renderActionList()
205 {
206 $content = '';
207 // Get the sys_action records
208 $actionList = $this->getActions();
209 // If any actions are found for the current users
210 if (!empty($actionList)) {
211 $content .= $this->taskObject->renderListMenu($actionList);
212 } else {
213 $flashMessage = GeneralUtility::makeInstance(
214 \TYPO3\CMS\Core\Messaging\FlashMessage::class,
215 $this->getLanguageService()->getLL('action_not-found-description', true),
216 $this->getLanguageService()->getLL('action_not-found'),
217 \TYPO3\CMS\Core\Messaging\FlashMessage::INFO);
218 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
219 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
220 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
221 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
222 $defaultFlashMessageQueue->enqueue($flashMessage);
223 }
224 // Admin users can create a new action
225 if ($this->getBackendUser()->isAdmin()) {
226 $link = BackendUtility::getModuleUrl(
227 'record_edit',
228 array(
229 'edit[sys_action][0]' => 'new',
230 'returnUrl' => $this->moduleUrl
231 ),
232 false,
233 true
234 );
235 $content .= '<p>' .
236 '<a href="' . $link . '" title="' . $this->getLanguageService()->getLL('new-sys_action') . '">' .
237 $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() .
238 $this->getLanguageService()->getLL('new-sys_action') .
239 '</a></p>';
240 }
241 return $content;
242 }
243
244 /**
245 * Action to create a new BE user
246 *
247 * @param array $record sys_action record
248 * @return string form to create a new user
249 */
250 protected function viewNewBackendUser($record)
251 {
252 $content = '';
253 $beRec = BackendUtility::getRecord('be_users', (int)$record['t1_copy_of_user']);
254 // A record is need which is used as copy for the new user
255 if (!is_array($beRec)) {
256 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_notReady', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
257 $content .= $flashMessage->render();
258 return $content;
259 }
260 $vars = GeneralUtility::_POST('data');
261 $key = 'NEW';
262 if ($vars['sent'] == 1) {
263 $errors = array();
264 // Basic error checks
265 if (!empty($vars['email']) && !GeneralUtility::validEmail($vars['email'])) {
266 $errors[] = $this->getLanguageService()->getLL('error-wrong-email');
267 }
268 if (empty($vars['username'])) {
269 $errors[] = $this->getLanguageService()->getLL('error-username-empty');
270 }
271 if ($vars['key'] === 'NEW' && empty($vars['password'])) {
272 $errors[] = $this->getLanguageService()->getLL('error-password-empty');
273 }
274 if ($vars['key'] !== 'NEW' && !$this->isCreatedByUser($vars['key'], $record)) {
275 $errors[] = $this->getLanguageService()->getLL('error-wrong-user');
276 }
277 foreach ($this->hookObjects as $hookObject) {
278 if (method_exists($hookObject, 'viewNewBackendUser_Error')) {
279 $errors = $hookObject->viewNewBackendUser_Error($vars, $errors, $this);
280 }
281 }
282 // Show errors if there are any
283 if (!empty($errors)) {
284 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, implode('<br />', $errors), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
285 $content .= $flashMessage->render() . '<br />';
286 } else {
287 // Save user
288 $key = $this->saveNewBackendUser($record, $vars);
289 // Success message
290 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $vars['key'] === 'NEW' ? $this->getLanguageService()->getLL('success-user-created') : $this->getLanguageService()->getLL('success-user-updated'), $this->getLanguageService()->getLL('success'), \TYPO3\CMS\Core\Messaging\FlashMessage::OK);
291 $content .= $flashMessage->render() . '<br />';
292 }
293 }
294 // Load BE user to edit
295 if ((int)GeneralUtility::_GP('be_users_uid') > 0) {
296 $tmpUserId = (int)GeneralUtility::_GP('be_users_uid');
297 // Check if the selected user is created by the current user
298 $rawRecord = $this->isCreatedByUser($tmpUserId, $record);
299 if ($rawRecord) {
300 // Delete user
301 if (GeneralUtility::_GP('delete') == 1) {
302 $this->deleteUser($tmpUserId, $record['uid']);
303 }
304 $key = $tmpUserId;
305 $vars = $rawRecord;
306 }
307 }
308 $content .= '<form action="" method="post" enctype="multipart/form-data">
309 <fieldset class="fields">
310 <legend>' . $this->getLanguageService()->getLL('action_t1_legend_generalFields') . '</legend>
311 <div class="row">
312 <label for="field_disable">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.disable') . '</label>
313 <input type="checkbox" id="field_disable" name="data[disable]" value="1" class="checkbox" ' . ($vars['disable'] == 1 ? ' checked="checked" ' : '') . ' />
314 </div>
315 <div class="row">
316 <label for="field_realname">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.name') . '</label>
317 <input type="text" id="field_realname" name="data[realName]" value="' . htmlspecialchars($vars['realName']) . '" />
318 </div>
319 <div class="row">
320 <label for="field_username">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_tca.xlf:be_users.username') . '</label>
321 <input type="text" id="field_username" name="data[username]" value="' . htmlspecialchars($vars['username']) . '" />
322 </div>
323 <div class="row">
324 <label for="field_password">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_tca.xlf:be_users.password') . '</label>
325 <input type="password" id="field_password" name="data[password]" value="" />
326 </div>
327 <div class="row">
328 <label for="field_email">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.email') . '</label>
329 <input type="text" id="field_email" name="data[email]" value="' . htmlspecialchars($vars['email']) . '" />
330 </div>
331 </fieldset>
332 <fieldset class="fields">
333 <legend>' . $this->getLanguageService()->getLL('action_t1_legend_configuration') . '</legend>
334
335 <div class="row">
336 <label for="field_usergroup">' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_tca.xlf:be_users.usergroup') . '</label>
337 <select id="field_usergroup" name="data[usergroup][]" multiple="multiple">
338 ' . $this->getUsergroups($record, $vars) . '
339 </select>
340 </div>
341 <div class="row">
342 <input type="hidden" name="data[key]" value="' . $key . '" />
343 <input type="hidden" name="data[sent]" value="1" />
344 <input class="btn btn-default" type="submit" value="' . ($key === 'NEW' ? $this->getLanguageService()->getLL('action_Create') : $this->getLanguageService()->getLL('action_Update')) . '" />
345 </div>
346 </fieldset>
347 </form>';
348 $content .= $this->getCreatedUsers($record, $key);
349 return $content;
350 }
351
352 /**
353 * Delete a BE user and redirect to the action by its id
354 *
355 * @param int $userId Id of the BE user
356 * @param int $actionId Id of the action
357 * @return void
358 */
359 protected function deleteUser($userId, $actionId)
360 {
361 $this->getDatabaseConnection()->exec_UPDATEquery('be_users', 'uid=' . $userId, array(
362 'deleted' => 1,
363 'tstamp' => $GLOBALS['ACCESS_TIME']
364 ));
365 // redirect to the original task
366 $redirectUrl = $this->moduleUrl . '&show=' . $actionId;
367 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($redirectUrl);
368 }
369
370 /**
371 * Check if a BE user is created by the current user
372 *
373 * @param int $id Id of the BE user
374 * @param array $action sys_action record.
375 * @return mixed The record of the BE user if found, otherwise FALSE
376 */
377 protected function isCreatedByUser($id, $action)
378 {
379 $record = BackendUtility::getRecord('be_users', $id, '*', ' AND cruser_id=' . $this->getBackendUser()->user['uid'] . ' AND createdByAction=' . $action['uid']);
380 if (is_array($record)) {
381 return $record;
382 } else {
383 return false;
384 }
385 }
386
387 /**
388 * Render all users who are created by the current BE user including a link to edit the record
389 *
390 * @param array $action sys_action record.
391 * @param int $selectedUser Id of a selected user
392 * @return string html list of users
393 */
394 protected function getCreatedUsers($action, $selectedUser)
395 {
396 $content = '';
397 $userList = array();
398 // List of users
399 $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'be_users', 'cruser_id=' . $this->getBackendUser()->user['uid'] . ' AND createdByAction=' . (int)$action['uid'] . BackendUtility::deleteClause('be_users'), '', 'username');
400 // Render the user records
401 while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
402 $icon = '<span title="' . htmlspecialchars('uid=' . $row['uid']) . '">' . $this->iconFactory->getIconForRecord('be_users', $row, Icon::SIZE_SMALL)->render() . '</span>';
403 $line = $icon . $this->action_linkUserName($row['username'], $row['realName'], $action['uid'], $row['uid']);
404 // Selected user
405 if ($row['uid'] == $selectedUser) {
406 $line = '<strong>' . $line . '</strong>';
407 }
408 $userList[] = $line;
409 }
410 $this->getDatabaseConnection()->sql_free_result($res);
411 // If any records found
412 if (!empty($userList)) {
413 $content .= '<br /><h3>' . $this->getLanguageService()->getLL('action_t1_listOfUsers', true) . '</h3><div>' . implode('<br />', $userList) . '</div>';
414 }
415 return $content;
416 }
417
418 /**
419 * Create a link to edit a user
420 *
421 * @param string $username Username
422 * @param string $realName Real name of the user
423 * @param int $sysActionUid Id of the sys_action record
424 * @param int $userId Id of the user
425 * @return string html link
426 */
427 protected function action_linkUserName($username, $realName, $sysActionUid, $userId)
428 {
429 if (!empty($realName)) {
430 $username .= ' (' . $realName . ')';
431 }
432 // Link to update the user record
433 $href = $this->moduleUrl . '&SET[function]=sys_action.TYPO3\\CMS\\SysAction\\ActionTask&show=' . (int)$sysActionUid . '&be_users_uid=' . (int)$userId;
434 $link = '<a href="' . htmlspecialchars($href) . '">' . htmlspecialchars($username) . '</a>';
435 // Link to delete the user record
436 $link .= '
437 <a href="' . htmlspecialchars(($href . '&delete=1')) . '" class="t3js-confirm-trigger" data-title="' . $this->getLanguageService()->getLL('lDelete_warning_title', true) . '" data-message="' . $this->getLanguageService()->getLL('lDelete_warning', true) . '">'
438 . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render() .
439 '</a>';
440 return $link;
441 }
442
443 /**
444 * Save/Update a BE user
445 *
446 * @param array $record Current action record
447 * @param array $vars POST vars
448 * @return int Id of the new/updated user
449 */
450 protected function saveNewBackendUser($record, $vars)
451 {
452 // Check if the db mount is a page the current user is allowed to.);
453 $vars['db_mountpoints'] = $this->fixDbMount($vars['db_mountpoints']);
454 // Check if the usergroup is allowed
455 $vars['usergroup'] = $this->fixUserGroup($vars['usergroup'], $record);
456 $key = $vars['key'];
457 $vars['password'] = trim($vars['password']);
458 // Check if md5 is used as password encryption
459 if ($vars['password'] !== '' && strpos($GLOBALS['TCA']['be_users']['columns']['password']['config']['eval'], 'md5') !== false) {
460 $vars['password'] = md5($vars['password']);
461 }
462 $data = '';
463 $newUserId = 0;
464 if ($key === 'NEW') {
465 $beRec = BackendUtility::getRecord('be_users', (int)$record['t1_copy_of_user']);
466 if (is_array($beRec)) {
467 $data = array();
468 $data['be_users'][$key] = $beRec;
469 $data['be_users'][$key]['username'] = $this->fixUsername($vars['username'], $record['t1_userprefix']);
470 $data['be_users'][$key]['password'] = $vars['password'];
471 $data['be_users'][$key]['realName'] = $vars['realName'];
472 $data['be_users'][$key]['email'] = $vars['email'];
473 $data['be_users'][$key]['disable'] = (int)$vars['disable'];
474 $data['be_users'][$key]['admin'] = 0;
475 $data['be_users'][$key]['usergroup'] = $vars['usergroup'];
476 $data['be_users'][$key]['db_mountpoints'] = $vars['db_mountpoints'];
477 $data['be_users'][$key]['createdByAction'] = $record['uid'];
478 }
479 } else {
480 // Check ownership
481 $beRec = BackendUtility::getRecord('be_users', (int)$key);
482 if (is_array($beRec) && $beRec['cruser_id'] == $this->getBackendUser()->user['uid']) {
483 $data = array();
484 $data['be_users'][$key]['username'] = $this->fixUsername($vars['username'], $record['t1_userprefix']);
485 if ($vars['password'] !== '') {
486 $data['be_users'][$key]['password'] = $vars['password'];
487 }
488 $data['be_users'][$key]['realName'] = $vars['realName'];
489 $data['be_users'][$key]['email'] = $vars['email'];
490 $data['be_users'][$key]['disable'] = (int)$vars['disable'];
491 $data['be_users'][$key]['admin'] = 0;
492 $data['be_users'][$key]['usergroup'] = $vars['usergroup'];
493 $data['be_users'][$key]['db_mountpoints'] = $vars['db_mountpoints'];
494 $newUserId = $key;
495 }
496 }
497 // Save/update user by using TCEmain
498 if (is_array($data)) {
499 $tce = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
500 $tce->start($data, array(), $this->getBackendUser());
501 $tce->admin = 1;
502 $tce->process_datamap();
503 $newUserId = (int)$tce->substNEWwithIDs['NEW'];
504 if ($newUserId) {
505 // Create
506 $this->action_createDir($newUserId);
507 } else {
508 // Update
509 $newUserId = (int)$key;
510 }
511 unset($tce);
512 }
513 return $newUserId;
514 }
515
516 /**
517 * Create the username based on the given username and the prefix
518 *
519 * @param string $username Username
520 * @param string $prefix Prefix
521 * @return string Combined username
522 */
523 protected function fixUsername($username, $prefix)
524 {
525 $prefix = trim($prefix);
526 if (substr($username, 0, strlen($prefix)) === $prefix) {
527 $username = substr($username, strlen($prefix));
528 }
529 return $prefix . $username;
530 }
531
532 /**
533 * Clean the to be applied usergroups from not allowed ones
534 *
535 * @param array $appliedUsergroups Array of to be applied user groups
536 * @param array $actionRecord The action record
537 * @return array Cleaned array
538 */
539 protected function fixUserGroup($appliedUsergroups, $actionRecord)
540 {
541 if (is_array($appliedUsergroups)) {
542 $cleanGroupList = array();
543 // Create an array from the allowed usergroups using the uid as key
544 $allowedUsergroups = array_flip(explode(',', $actionRecord['t1_allowed_groups']));
545 // Walk through the array and check every uid if it is under the allowed ines
546 foreach ($appliedUsergroups as $group) {
547 if (isset($allowedUsergroups[$group])) {
548 $cleanGroupList[] = $group;
549 }
550 }
551 $appliedUsergroups = $cleanGroupList;
552 }
553 return $appliedUsergroups;
554 }
555
556 /**
557 * Clean the to be applied DB-Mounts from not allowed ones
558 *
559 * @param string $appliedDbMounts List of pages like pages_123,pages456
560 * @return string Cleaned list
561 */
562 protected function fixDbMount($appliedDbMounts)
563 {
564 // Admins can see any page, no need to check there
565 if (!empty($appliedDbMounts) && !$this->getBackendUser()->isAdmin()) {
566 $cleanDbMountList = array();
567 $dbMounts = GeneralUtility::trimExplode(',', $appliedDbMounts, true);
568 // Walk through every wanted DB-Mount and check if it allowed for the current user
569 foreach ($dbMounts as $dbMount) {
570 $uid = (int)substr($dbMount, strrpos($dbMount, '_') + 1);
571 $page = BackendUtility::getRecord('pages', $uid);
572 // Check rootline and access rights
573 if ($this->checkRootline($uid) && $this->getBackendUser()->calcPerms($page)) {
574 $cleanDbMountList[] = 'pages_' . $uid;
575 }
576 }
577 // Build the clean list
578 $appliedDbMounts = implode(',', $cleanDbMountList);
579 }
580 return $appliedDbMounts;
581 }
582
583 /**
584 * Check if a page is inside the rootline the current user can see
585 *
586 * @param int $pageId Id of the the page to be checked
587 * @return bool Access to the page
588 */
589 protected function checkRootline($pageId)
590 {
591 $access = false;
592 $dbMounts = array_flip(explode(',', trim($this->getBackendUser()->dataLists['webmount_list'], ',')));
593 $rootline = BackendUtility::BEgetRootLine($pageId);
594 foreach ($rootline as $page) {
595 if (isset($dbMounts[$page['uid']]) && !$access) {
596 $access = true;
597 }
598 }
599 return $access;
600 }
601
602 /**
603 * Create a user directory if defined
604 *
605 * @param int $uid Id of the user record
606 * @return void
607 */
608 protected function action_createDir($uid)
609 {
610 $path = $this->action_getUserMainDir();
611 if ($path) {
612 GeneralUtility::mkdir($path . $uid);
613 GeneralUtility::mkdir($path . $uid . '/_temp_/');
614 }
615 }
616
617 /**
618 * Get the path to the user home directory which is set in the localconf.php
619 *
620 * @return string Path
621 */
622 protected function action_getUserMainDir()
623 {
624 $path = $GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath'];
625 // If path is set and a valid directory
626 if ($path && @is_dir($path) && $GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath'] && GeneralUtility::isFirstPartOfStr($path, $GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath']) && substr($path, -1) == '/') {
627 return $path;
628 }
629 }
630
631 /**
632 * Get all allowed usergroups which can be applied to a user record
633 *
634 * @param array $record sys_action record
635 * @param array $vars Selected be_user record
636 * @return string Rendered user groups
637 */
638 protected function getUsergroups($record, $vars)
639 {
640 $content = '';
641 // Do nothing if no groups are allowed
642 if (empty($record['t1_allowed_groups'])) {
643 return $content;
644 }
645 $content .= '<option value=""></option>';
646 $grList = GeneralUtility::trimExplode(',', $record['t1_allowed_groups'], true);
647 foreach ($grList as $group) {
648 $checkGroup = BackendUtility::getRecord('be_groups', $group);
649 if (is_array($checkGroup)) {
650 $selected = GeneralUtility::inList($vars['usergroup'], $checkGroup['uid']) ? ' selected="selected" ' : '';
651 $content .= '<option ' . $selected . 'value="' . $checkGroup['uid'] . '">' . htmlspecialchars($checkGroup['title']) . '</option>';
652 }
653 }
654 return $content;
655 }
656
657 /**
658 * Action to create a new record
659 *
660 * @param array $record sys_action record
661 * @return void Redirect to form to create a record
662 */
663 protected function viewNewRecord($record)
664 {
665 $link = BackendUtility::getModuleUrl(
666 'record_edit',
667 array(
668 'edit[' . $record['t3_tables'] . '][' . (int)$record['t3_listPid'] . ']' => 'new',
669 'returnUrl' => $this->moduleUrl
670 ),
671 false,
672 true
673 );
674 \TYPO3\CMS\Core\Utility\HttpUtility::redirect($link);
675 }
676
677 /**
678 * Action to edit records
679 *
680 * @param array $record sys_action record
681 * @return string list of records
682 */
683 protected function viewEditRecord($record)
684 {
685 $content = '';
686 $actionList = array();
687 $dbAnalysis = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
688 $dbAnalysis->setFetchAllFields(true);
689 $dbAnalysis->start($record['t4_recordsToEdit'], '*');
690 $dbAnalysis->getFromDB();
691 // collect the records
692 foreach ($dbAnalysis->itemArray as $el) {
693 $path = BackendUtility::getRecordPath($el['id'], $this->taskObject->perms_clause, $this->getBackendUser()->uc['titleLen']);
694 $record = BackendUtility::getRecord($el['table'], $dbAnalysis->results[$el['table']][$el['id']]);
695 $title = BackendUtility::getRecordTitle($el['table'], $dbAnalysis->results[$el['table']][$el['id']]);
696 $description = $this->getLanguageService()->sL($GLOBALS['TCA'][$el['table']]['ctrl']['title'], true);
697 // @todo: which information could be needful
698 if (isset($record['crdate'])) {
699 $description .= ' - ' . BackendUtility::dateTimeAge($record['crdate']);
700 }
701 $link = BackendUtility::getModuleUrl(
702 'record_edit',
703 array(
704 'edit[' . $el['table'] . '][' . $el['id'] . ']' => 'edit',
705 'returnUrl' => $this->moduleUrl
706 ),
707 false,
708 true
709 );
710 $actionList[$el['id']] = array(
711 'title' => $title,
712 'description' => BackendUtility::getRecordTitle($el['table'], $dbAnalysis->results[$el['table']][$el['id']]),
713 'descriptionHtml' => $description,
714 'link' => $link,
715 'icon' => '<span title="' . htmlspecialchars($path) . '">' . $this->iconFactory->getIconForRecord($el['table'], $dbAnalysis->results[$el['table']][$el['id']], Icon::SIZE_SMALL)->render() . '</span>'
716 );
717 }
718 // Render the record list
719 $content .= $this->taskObject->renderListMenu($actionList);
720 return $content;
721 }
722
723 /**
724 * Action to view the result of a SQL query
725 *
726 * @param array $record sys_action record
727 * @return string Result of the query
728 */
729 protected function viewSqlQuery($record)
730 {
731 $content = '';
732 if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('lowlevel')) {
733 $sql_query = unserialize($record['t2_data']);
734 if (!is_array($sql_query) || is_array($sql_query) && strtoupper(substr(trim($sql_query['qSelect']), 0, 6)) === 'SELECT') {
735 $actionContent = '';
736 $fullsearch = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\QueryView::class);
737 $fullsearch->formW = 40;
738 $fullsearch->noDownloadB = 1;
739 $type = $sql_query['qC']['search_query_makeQuery'];
740 if ($sql_query['qC']['labels_noprefix'] === 'on') {
741 $GLOBALS['SOBE']->MOD_SETTINGS['labels_noprefix'] = 'on';
742 }
743 $sqlQuery = $sql_query['qSelect'];
744 $queryIsEmpty = false;
745 if ($sqlQuery) {
746 $res = $this->getDatabaseConnection()->sql_query($sqlQuery);
747 if (!$this->getDatabaseConnection()->sql_error()) {
748 $fullsearch->formW = 48;
749 // Additional configuration
750 $GLOBALS['SOBE']->MOD_SETTINGS['search_result_labels'] = 1;
751 $GLOBALS['SOBE']->MOD_SETTINGS['queryFields'] = $sql_query['qC']['queryFields'];
752 $cP = $fullsearch->getQueryResultCode($type, $res, $sql_query['qC']['queryTable']);
753 $actionContent = $cP['content'];
754 // If the result is rendered as csv or xml, show a download link
755 if ($type === 'csv' || $type === 'xml') {
756 $actionContent .= '<br /><br /><a href="' . GeneralUtility::getIndpEnv('REQUEST_URI') . '&download_file=1"><strong>' . $this->getLanguageService()->getLL('action_download_file') . '</strong></a>';
757 }
758 } else {
759 $actionContent .= $this->getDatabaseConnection()->sql_error();
760 }
761 } else {
762 // Query is empty (not built)
763 $queryIsEmpty = true;
764 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_emptyQuery', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
765 $content .= '<br />' . $flashMessage->render();
766 }
767 // Admin users are allowed to see and edit the query
768 if ($this->getBackendUser()->isAdmin()) {
769 if (!$queryIsEmpty) {
770 $actionContent .= '<hr /> ' . $fullsearch->tableWrap($sql_query['qSelect']);
771 }
772 $actionContent .= '<br /><a title="' . $this->getLanguageService()->getLL('action_editQuery') . '" href="'
773 . htmlspecialchars(BackendUtility::getModuleUrl('system_dbint')
774 . '&id=' . '&SET[function]=search' . '&SET[search]=query'
775 . '&storeControl[STORE]=-' . $record['uid'] . '&storeControl[LOAD]=1')
776 . '">'
777 . $this->iconFactory->getIcon('actions-document-info', Icon::SIZE_SMALL)->render()
778 . $this->getLanguageService()->getLL(($queryIsEmpty ? 'action_createQuery'
779 : 'action_editQuery')) . '</a><br /><br />';
780 }
781 $content .= '<h2>' . $this->getLanguageService()->getLL('action_t2_result', true) . '</h2><div>' . $actionContent . '</div>';
782 } else {
783 // Query is not configured
784 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_notReady', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
785 $content .= '<br />' . $flashMessage->render();
786 }
787 } else {
788 // Required sysext lowlevel is not installed
789 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_lowlevelMissing', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
790 $content .= '<br />' . $flashMessage->render();
791 }
792 return $content;
793 }
794
795 /**
796 * Action to create a list of records of a specific table and pid
797 *
798 * @param array $record sys_action record
799 * @return string list of records
800 */
801 protected function viewRecordList($record)
802 {
803 $content = '';
804 $this->id = (int)$record['t3_listPid'];
805 $this->table = $record['t3_tables'];
806 if ($this->id == 0) {
807 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_notReady', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
808 $content .= '<br />' . $flashMessage->render();
809 return $content;
810 }
811 // Loading current page record and checking access:
812 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->taskObject->perms_clause);
813 $access = is_array($this->pageinfo) ? 1 : 0;
814 // If there is access to the page, then render the list contents and set up the document template object:
815 if ($access) {
816 // Initialize the dblist object:
817 $dblist = GeneralUtility::makeInstance(\TYPO3\CMS\SysAction\ActionList::class);
818 $dblist->script = GeneralUtility::getIndpEnv('REQUEST_URI');
819 $dblist->calcPerms = $this->getBackendUser()->calcPerms($this->pageinfo);
820 $dblist->thumbs = $this->getBackendUser()->uc['thumbnailsByDefault'];
821 $dblist->returnUrl = $this->taskObject->returnUrl;
822 $dblist->allFields = 1;
823 $dblist->localizationView = 1;
824 $dblist->showClipboard = 0;
825 $dblist->disableSingleTableView = 1;
826 $dblist->pageRow = $this->pageinfo;
827 $dblist->counter++;
828 $dblist->MOD_MENU = array('bigControlPanel' => '', 'clipBoard' => '', 'localization' => '');
829 $dblist->modTSconfig = $this->taskObject->modTSconfig;
830 $dblist->dontShowClipControlPanels = (!$this->taskObject->MOD_SETTINGS['bigControlPanel'] && $dblist->clipObj->current == 'normal' && !$this->modTSconfig['properties']['showClipControlPanelsDespiteOfCMlayers']);
831 // Initialize the listing object, dblist, for rendering the list:
832 $this->pointer = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(GeneralUtility::_GP('pointer'), 0, 100000);
833 $dblist->start($this->id, $this->table, $this->pointer, $this->taskObject->search_field, $this->taskObject->search_levels, $this->taskObject->showLimit);
834 $dblist->setDispFields();
835 // Render the list of tables:
836 $dblist->generateList();
837 // Add JavaScript functions to the page:
838 $this->taskObject->getModuleTemplate()->addJavaScriptCode(
839 'ActionTaskInlineJavascript',
840 '
841
842 function jumpExt(URL,anchor) {
843 var anc = anchor?anchor:"";
844 window.location.href = URL+(T3_THIS_LOCATION?"&returnUrl="+T3_THIS_LOCATION:"")+anc;
845 return false;
846 }
847 function jumpSelf(URL) {
848 window.location.href = URL+(T3_RETURN_URL?"&returnUrl="+T3_RETURN_URL:"");
849 return false;
850 }
851
852 function setHighlight(id) {
853 top.fsMod.recentIds["web"]=id;
854 top.fsMod.navFrameHighlightedID["web"]="pages"+id+"_"+top.fsMod.currentBank; // For highlighting
855
856 if (top.content && top.content.nav_frame && top.content.nav_frame.refresh_nav) {
857 top.content.nav_frame.refresh_nav();
858 }
859 }
860
861 ' . $dblist->CBfunctions() . '
862 function editRecords(table,idList,addParams,CBflag) {
863 window.location.href="' . BackendUtility::getModuleUrl('record_edit', array('returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'))) . '&edit["+table+"]["+idList+"]=edit"+addParams;
864 }
865 function editList(table,idList) {
866 var list="";
867
868 // Checking how many is checked, how many is not
869 var pointer=0;
870 var pos = idList.indexOf(",");
871 while (pos!=-1) {
872 if (cbValue(table+"|"+idList.substr(pointer,pos-pointer))) {
873 list+=idList.substr(pointer,pos-pointer)+",";
874 }
875 pointer=pos+1;
876 pos = idList.indexOf(",",pointer);
877 }
878 if (cbValue(table+"|"+idList.substr(pointer))) {
879 list+=idList.substr(pointer)+",";
880 }
881
882 return list ? list : idList;
883 }
884 T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'))) . ';
885
886 if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';
887 '
888 );
889 // Setting up the context sensitive menu:
890 $this->taskObject->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
891 // Begin to compile the whole page
892 $content .= '<form action="' . htmlspecialchars($dblist->listURL()) . '" method="post" name="dblistForm">' . $dblist->HTMLcode . '<input type="hidden" name="cmd_table" /><input type="hidden" name="cmd" />
893 </form>';
894 // If a listing was produced, create the page footer with search form etc:
895 // Making field select box (when extended view for a single table is enabled):
896 if ($dblist->HTMLcode && $dblist->table) {
897 $content .= $dblist->fieldSelectBox($dblist->table);
898 }
899 } else {
900 // Not enough rights to access the list view or the page
901 $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('action_error-access', true), $this->getLanguageService()->getLL('action_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
902 $content .= $flashMessage->render();
903 }
904 return $content;
905 }
906
907 /**
908 * Returns LanguageService
909 *
910 * @return \TYPO3\CMS\Lang\LanguageService
911 */
912 protected function getLanguageService()
913 {
914 return $GLOBALS['LANG'];
915 }
916
917 /**
918 * Returns the current BE user.
919 *
920 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
921 */
922 protected function getBackendUser()
923 {
924 return $GLOBALS['BE_USER'];
925 }
926
927 /**
928 * Returns the database connection
929 *
930 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
931 */
932 protected function getDatabaseConnection()
933 {
934 return $GLOBALS['TYPO3_DB'];
935 }
936 }