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