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