TYPO3 CMS  TYPO3_8-7
SetupModuleController.php
Go to the documentation of this file.
1 <?php
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 
35 
40 {
45 
49  const PASSWORD_UPDATED = 1;
50 
55 
60  const PASSWORD_OLD_WRONG = 3;
61 
65  public $MOD_MENU = [];
66 
70  public $MOD_SETTINGS = [];
71 
75  public $content;
76 
80  public $overrideConf;
81 
87  public $OLD_BE_USER;
88 
93 
97  protected $pagetreeNeedsRefresh = false;
98 
102  protected $isAdmin;
103 
107  protected $tsFieldConf;
108 
112  protected $saveData = false;
113 
117  protected $passwordIsUpdated = self::PASSWORD_NOT_UPDATED;
118 
122  protected $passwordIsSubmitted = false;
123 
127  protected $setupIsUpdated = false;
128 
132  protected $settingsAreResetToDefault = false;
133 
139  protected $formProtection;
140 
144  protected $simulateSelector = '';
145 
149  protected $simUser;
150 
156  protected $moduleName = 'user_setup';
157 
161  protected $loadModules;
162 
166  protected $beUser;
167 
171  public function __construct()
172  {
173  parent::__construct();
174  $this->formProtection = FormProtectionFactory::get();
175  $pageRenderer = $this->moduleTemplate->getPageRenderer();
176  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal');
177  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/FormEngine');
178  $pageRenderer->addInlineSetting('FormEngine', 'formName', 'editform');
179  $pageRenderer->addInlineLanguageLabelArray([
180  'FormEngine.remainingCharacters' => 'LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.remainingCharacters',
181  ], true);
182  }
183 
189  public function getFormProtection()
190  {
191  return $this->formProtection;
192  }
193 
199  public function storeIncomingData()
200  {
201  // First check if something is submitted in the data-array from POST vars
202  $d = GeneralUtility::_POST('data');
203  $columns = $GLOBALS['TYPO3_USER_SETTINGS']['columns'];
204  $beUserId = $this->beUser->user['uid'];
205  $storeRec = [];
206  $fieldList = $this->getFieldsFromShowItem();
207  if (is_array($d) && $this->formProtection->validateToken((string)GeneralUtility::_POST('formToken'), 'BE user setup', 'edit')) {
208  // UC hashed before applying changes
209  $save_before = md5(serialize($this->beUser->uc));
210  // PUT SETTINGS into the ->uc array:
211  // Reload left frame when switching BE language
212  if (isset($d['lang']) && $d['lang'] != $this->beUser->uc['lang']) {
213  $this->languageUpdate = true;
214  }
215  // Reload pagetree if the title length is changed
216  if (isset($d['titleLen']) && $d['titleLen'] !== $this->beUser->uc['titleLen']) {
217  $this->pagetreeNeedsRefresh = true;
218  }
219  if ($d['setValuesToDefault']) {
220  // If every value should be default
221  $this->beUser->resetUC();
222  $this->settingsAreResetToDefault = true;
223  } elseif ($d['save']) {
224  // Save all submitted values if they are no array (arrays are with table=be_users) and exists in $GLOBALS['TYPO3_USER_SETTINGS'][columns]
225  foreach ($columns as $field => $config) {
226  if (!in_array($field, $fieldList)) {
227  continue;
228  }
229  if ($config['table']) {
230  if ($config['table'] === 'be_users' && !in_array($field, ['password', 'password2', 'passwordCurrent', 'email', 'realName', 'admin', 'avatar'])) {
231  if (!isset($config['access']) || $this->checkAccess($config) && $this->beUser->user[$field] !== $d['be_users'][$field]) {
232  if ($config['type'] === 'check') {
233  $fieldValue = isset($d['be_users'][$field]) ? 1 : 0;
234  } else {
235  $fieldValue = $d['be_users'][$field];
236  }
237  $storeRec['be_users'][$beUserId][$field] = $fieldValue;
238  $this->beUser->user[$field] = $fieldValue;
239  }
240  }
241  }
242  if ($config['type'] === 'check') {
243  $this->beUser->uc[$field] = isset($d[$field]) ? 1 : 0;
244  } else {
245  $this->beUser->uc[$field] = htmlspecialchars($d[$field]);
246  }
247  }
248  // Personal data for the users be_user-record (email, name, password...)
249  // If email and name is changed, set it in the users record:
250  $be_user_data = $d['be_users'];
251  // Possibility to modify the transmitted values. Useful to do transformations, like RSA password decryption
252  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'])) {
253  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'] as $function) {
254  $params = ['be_user_data' => &$be_user_data];
255  GeneralUtility::callUserFunction($function, $params, $this);
256  }
257  }
258  $this->passwordIsSubmitted = (string)$be_user_data['password'] !== '';
259  $passwordIsConfirmed = $this->passwordIsSubmitted && $be_user_data['password'] === $be_user_data['password2'];
260  // Update the real name:
261  if ($be_user_data['realName'] !== $this->beUser->user['realName']) {
262  $this->beUser->user['realName'] = ($storeRec['be_users'][$beUserId]['realName'] = substr($be_user_data['realName'], 0, 80));
263  }
264  // Update the email address:
265  if ($be_user_data['email'] !== $this->beUser->user['email']) {
266  $this->beUser->user['email'] = ($storeRec['be_users'][$beUserId]['email'] = substr($be_user_data['email'], 0, 80));
267  }
268  // Update the password:
269  if ($passwordIsConfirmed) {
270  if ($this->isAdmin) {
271  $passwordOk = true;
272  } else {
273  $currentPasswordHashed = $GLOBALS['BE_USER']->user['password'];
274  $saltFactory = SaltFactory::getSaltingInstance($currentPasswordHashed);
275  $passwordOk = $saltFactory->checkPassword($be_user_data['passwordCurrent'], $currentPasswordHashed);
276  }
277  if ($passwordOk) {
278  $this->passwordIsUpdated = self::PASSWORD_UPDATED;
279  $storeRec['be_users'][$beUserId]['password'] = $be_user_data['password'];
280  } else {
281  $this->passwordIsUpdated = self::PASSWORD_OLD_WRONG;
282  }
283  } else {
284  $this->passwordIsUpdated = self::PASSWORD_NOT_THE_SAME;
285  }
286 
287  $this->setAvatarFileUid($beUserId, $be_user_data['avatar'], $storeRec);
288 
289  $this->saveData = true;
290  }
291  // Inserts the overriding values.
292  $this->beUser->overrideUC();
293  $save_after = md5(serialize($this->beUser->uc));
294  // If something in the uc-array of the user has changed, we save the array...
295  if ($save_before != $save_after) {
296  $this->beUser->writeUC($this->beUser->uc);
297  $this->beUser->writelog(254, 1, 0, 1, 'Personal settings changed', []);
298  $this->setupIsUpdated = true;
299  }
300  // Persist data if something has changed:
301  if (!empty($storeRec) && $this->saveData) {
302  // Make instance of TCE for storing the changes.
304  $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
305  // This is so the user can actually update his user record.
306  $realUser = $this->getRealScriptUserObj();
307  $isAdmin = $realUser->user['admin'];
308  $realUser->user['admin'] = 1;
309  $dataHandler->start($storeRec, [], $realUser);
310  // This is to make sure that the users record can be updated even if in another workspace. This is tolerated.
311  $dataHandler->bypassWorkspaceRestrictions = true;
312  $dataHandler->process_datamap();
313  unset($tce);
314  if ($this->passwordIsUpdated === self::PASSWORD_NOT_UPDATED || count($storeRec['be_users'][$beUserId]) > 1) {
315  $this->setupIsUpdated = true;
316  }
317  // Restore admin status after processing
318  $realUser->user['admin'] = $isAdmin;
319 
320  BackendUtility::setUpdateSignal('updateTopbar');
321  }
322  }
323  }
324 
325  /******************************
326  *
327  * Rendering module
328  *
329  ******************************/
333  public function init()
334  {
335  $this->getLanguageService()->includeLLFile('EXT:setup/Resources/Private/Language/locallang.xlf');
336 
337  // Returns the script user - that is the REAL logged in user! ($GLOBALS[BE_USER] might be another user due to simulation!)
338  $scriptUser = $this->getRealScriptUserObj();
339 
340  $this->isAdmin = $scriptUser->isAdmin();
341  // Getting the 'override' values as set might be set in User TSconfig
342  $this->overrideConf = $this->beUser->getTSConfigProp('setup.override');
343  // Getting the disabled fields might be set in User TSconfig (eg setup.fields.password.disabled=1)
344  $this->tsFieldConf = $this->beUser->getTSConfigProp('setup.fields');
345  // id password is disabled, disable repeat of password too (password2)
346  if (isset($this->tsFieldConf['password.']) && $this->tsFieldConf['password.']['disabled']) {
347  $this->tsFieldConf['password2.']['disabled'] = 1;
348  $this->tsFieldConf['passwordCurrent.']['disabled'] = 1;
349  }
350  }
351 
357  protected function getJavaScript()
358  {
359  $javaScript = '';
360  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'])) {
361  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'] as $function) {
362  $params = [];
363  $javaScript .= GeneralUtility::callUserFunction($function, $params, $this);
364  }
365  }
366  return $javaScript;
367  }
368 
372  public function main()
373  {
374  $this->content .= '<form action="' . BackendUtility::getModuleUrl('user_setup') . '" method="post" id="SetupModuleController" name="usersetup" enctype="multipart/form-data">';
375  if ($this->languageUpdate) {
376  $this->moduleTemplate->addJavaScriptCode('languageUpdate', '
377  if (top && top.TYPO3.ModuleMenu.App) {
378  top.TYPO3.ModuleMenu.App.refreshMenu();
379  }
380  ');
381  }
382  if ($this->pagetreeNeedsRefresh) {
383  BackendUtility::setUpdateSignal('updatePageTree');
384  }
385  // Start page:
386  $this->moduleTemplate->getPageRenderer()->addJsFile('EXT:backend/Resources/Public/JavaScript/md5.js');
387  // Use a wrapper div
388  $this->content .= '<div id="user-setup-wrapper">';
389  // Load available backend modules
390  $this->loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
391  $this->loadModules->observeWorkspaces = true;
392  $this->loadModules->load($GLOBALS['TBE_MODULES']);
393  $this->content .= $this->moduleTemplate->header($this->getLanguageService()->getLL('UserSettings'));
394  $this->addFlashMessages();
395 
396  // Render user switch
397  $this->content .= $this->renderSimulateUserSelectAndLabel();
398 
399  // Render the menu items
400  $menuItems = $this->renderUserSetup();
401  $this->content .= $this->moduleTemplate->getDynamicTabMenu($menuItems, 'user-setup', 1, false, false);
402  $formToken = $this->formProtection->generateToken('BE user setup', 'edit');
403  $this->content .= '<div>';
404  $this->content .= '<input type="hidden" name="simUser" value="' . (int)$this->simUser . '" />
405  <input type="hidden" name="formToken" value="' . htmlspecialchars($formToken) . '" />
406  <input type="hidden" value="1" name="data[save]" />
407  <input type="hidden" name="data[setValuesToDefault]" value="0" id="setValuesToDefault" />';
408  $this->content .= '</div>';
409  // End of wrapper div
410  $this->content .= '</div>';
411  // Setting up the buttons and markers for docheader
412  $this->getButtons();
413  // Build the <body> for the module
414  // Renders the module page
415  $this->moduleTemplate->setContent($this->content);
416  $this->content .= '</form>';
417  }
418 
427  public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
428  {
429  $GLOBALS['SOBE'] = $this;
430  $this->simulateUser();
431  $this->init();
432  $this->storeIncomingData();
433  $this->main();
434 
435  $response->getBody()->write($this->moduleTemplate->renderContent());
436  return $response;
437  }
438 
442  protected function getButtons()
443  {
444  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
445  $cshButton = $buttonBar->makeHelpButton()
446  ->setModuleName('_MOD_user_setup')
447  ->setFieldName('');
448  $buttonBar->addButton($cshButton);
449 
450  $saveButton = $buttonBar->makeInputButton()
451  ->setName('data[save]')
452  ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
453  ->setValue('1')
454  ->setForm('SetupModuleController')
455  ->setShowLabelText(true)
456  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
457 
458  $buttonBar->addButton($saveButton);
459  $shortcutButton = $buttonBar->makeShortcutButton()
460  ->setModuleName($this->moduleName);
461  $buttonBar->addButton($shortcutButton);
462  }
463 
464  /******************************
465  *
466  * Render module
467  *
468  ******************************/
469 
476  protected function renderUserSetup()
477  {
478  $html = '';
479  $result = [];
480  $firstTabLabel = '';
481  $code = [];
482  $fieldArray = $this->getFieldsFromShowItem();
483  $tabLabel = '';
484  foreach ($fieldArray as $fieldName) {
485  $config = $GLOBALS['TYPO3_USER_SETTINGS']['columns'][$fieldName];
486  if (isset($config['access']) && !$this->checkAccess($config)) {
487  continue;
488  }
489 
490  if (substr($fieldName, 0, 8) === '--div--;') {
491  if ($firstTabLabel === '') {
492  // First tab
493  $tabLabel = $this->getLabel(substr($fieldName, 8), '', false);
494  $firstTabLabel = $tabLabel;
495  } else {
496  $result[] = [
497  'label' => $tabLabel,
498  'content' => count($code) ? implode(LF, $code) : ''
499  ];
500  $tabLabel = $this->getLabel(substr($fieldName, 8), '', false);
501  $code = [];
502  }
503  continue;
504  }
505  $label = $this->getLabel($config['label'], $fieldName);
506  $label = $this->getCSH($config['csh'] ?: $fieldName, $label);
507  $type = $config['type'];
508  $class = $config['class'];
509  if ($type !== 'check') {
510  $class .= ' form-control';
511  }
512  $more = '';
513  if ($class) {
514  $more .= ' class="' . htmlspecialchars($class) . '"';
515  }
516  $style = $config['style'];
517  if ($style) {
518  $more .= ' style="' . htmlspecialchars($style) . '"';
519  }
520  if (isset($this->overrideConf[$fieldName])) {
521  $more .= ' disabled="disabled"';
522  }
523  $value = $config['table'] === 'be_users' ? $this->beUser->user[$fieldName] : $this->beUser->uc[$fieldName];
524  if (!$value && isset($config['default'])) {
525  $value = $config['default'];
526  }
527  $dataAdd = '';
528  if ($config['table'] === 'be_users') {
529  $dataAdd = '[be_users]';
530  }
531 
532  switch ($type) {
533  case 'text':
534  case 'email':
535  case 'password':
536  $noAutocomplete = '';
537 
538  $maxLength = $config['max'] ?? 0;
539  if ((int)$maxLength > 0) {
540  $more .= ' maxlength="' . (int)$maxLength . '"';
541  }
542 
543  if ($type === 'password') {
544  $value = '';
545  $noAutocomplete = 'autocomplete="new-password" ';
546  $more .= ' data-rsa-encryption=""';
547  }
548  $html = '<input id="field_' . htmlspecialchars($fieldName) . '"
549  type="' . htmlspecialchars($type) . '"
550  name="data' . $dataAdd . '[' . htmlspecialchars($fieldName) . ']" ' .
551  $noAutocomplete .
552  'value="' . htmlspecialchars($value) . '" ' .
553  $more .
554  ' />';
555  break;
556  case 'check':
557  $html = $label . '<div class="checkbox"><label><input id="field_' . htmlspecialchars($fieldName) . '"
558  type="checkbox"
559  name="data' . $dataAdd . '[' . htmlspecialchars($fieldName) . ']"' .
560  ($value ? ' checked="checked"' : '') .
561  $more .
562  ' /></label></div>';
563  $label = '';
564  break;
565  case 'select':
566  if ($config['itemsProcFunc']) {
567  $html = GeneralUtility::callUserFunction($config['itemsProcFunc'], $config, $this);
568  } else {
569  $html = '<select id="field_' . htmlspecialchars($fieldName) . '"
570  name="data' . $dataAdd . '[' . htmlspecialchars($fieldName) . ']"' .
571  $more . '>' . LF;
572  foreach ($config['items'] as $key => $optionLabel) {
573  $html .= '<option value="' . htmlspecialchars($key) . '"' . ($value == $key ? ' selected="selected"' : '') . '>' . $this->getLabel($optionLabel, '', false) . '</option>' . LF;
574  }
575  $html .= '</select>';
576  }
577  break;
578  case 'user':
579  $html = GeneralUtility::callUserFunction($config['userFunc'], $config, $this);
580  break;
581  case 'button':
582  if ($config['onClick']) {
583  $onClick = $config['onClick'];
584  if ($config['onClickLabels']) {
585  foreach ($config['onClickLabels'] as $key => $labelclick) {
586  $config['onClickLabels'][$key] = $this->getLabel($labelclick, '', false);
587  }
588  $onClick = vsprintf($onClick, $config['onClickLabels']);
589  }
590  $html = '<br><input class="btn btn-default" type="button"
591  value="' . $this->getLabel($config['buttonlabel'], '', false) . '"
592  onclick="' . $onClick . '" />';
593  }
594  if (!empty($config['confirm'])) {
595  $confirmData = $config['confirmData'];
596  $html = '<br><input class="btn btn-default t3js-modal-trigger" type="button"'
597  . ' value="' . $this->getLabel($config['buttonlabel'], '', false) . '"'
598  . ' data-href="javascript:' . htmlspecialchars($confirmData['jsCodeAfterOk']) . '"'
599  . ' data-severity="warning"'
600  . ' data-title="' . $this->getLabel($config['label'], '', false) . '"'
601  . ' data-content="' . $this->getLabel($confirmData['message'], '', false) . '" />';
602  }
603  break;
604  case 'avatar':
605  // Get current avatar image
606  $html = '<br>';
607  $avatarFileUid = $this->getAvatarFileUid($this->beUser->user['uid']);
608 
609  if ($avatarFileUid) {
610  $defaultAvatarProvider = GeneralUtility::makeInstance(DefaultAvatarProvider::class);
611  $avatarImage = $defaultAvatarProvider->getImage($this->beUser->user, 32);
612  if ($avatarImage) {
613  $icon = '<span class="avatar"><span class="avatar-image">' .
614  '<img src="' . htmlspecialchars($avatarImage->getUrl(true)) . '"' .
615  ' width="' . (int)$avatarImage->getWidth() . '" ' .
616  'height="' . (int)$avatarImage->getHeight() . '" />' .
617  '</span></span>';
618  $html .= '<span class="pull-left" style="padding-right: 10px" id="image_' . htmlspecialchars($fieldName) . '">' . $icon . ' </span>';
619  }
620  }
621  $html .= '<input id="field_' . htmlspecialchars($fieldName) . '" type="hidden" ' .
622  'name="data' . $dataAdd . '[' . htmlspecialchars($fieldName) . ']"' . $more .
623  ' value="' . (int)$avatarFileUid . '" />';
624 
625  $html .= '<div class="btn-group">';
626  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
627  if ($avatarFileUid) {
628  $html .=
629  '<a id="clear_button_' . htmlspecialchars($fieldName) . '" '
630  . 'onclick="clearExistingImage(); return false;" class="btn btn-default">'
631  . $iconFactory->getIcon('actions-delete', Icon::SIZE_SMALL)
632  . '</a>';
633  }
634  $html .=
635  '<a id="add_button_' . htmlspecialchars($fieldName) . '" class="btn btn-default btn-add-avatar"'
636  . ' onclick="openFileBrowser();return false;">'
637  . $iconFactory->getIcon('actions-insert-record', Icon::SIZE_SMALL)
638  . '</a></div>';
639 
640  $this->addAvatarButtonJs($fieldName);
641  break;
642  default:
643  $html = '';
644  }
645 
646  $code[] = '<div class="form-section"><div class="row"><div class="form-group t3js-formengine-field-item col-md-12">' .
647  $label .
648  $html .
649  '</div></div></div>';
650  }
651 
652  $result[] = [
653  'label' => $tabLabel,
654  'content' => count($code) ? implode(LF, $code) : ''
655  ];
656  return $result;
657  }
658 
659  /******************************
660  *
661  * Helper functions
662  *
663  ******************************/
670  protected function getRealScriptUserObj()
671  {
672  return is_object($this->OLD_BE_USER) ? $this->OLD_BE_USER : $this->beUser;
673  }
674 
682  public function renderLanguageSelect(array $params, $controller)
683  {
684  $languageOptions = [];
685  // Compile the languages dropdown
686  $langDefault = htmlspecialchars($this->getLanguageService()->getLL('lang_default'));
687  $languageOptions[$langDefault] = '<option value=""' . ($controller->beUser->uc['lang'] === '' ? ' selected="selected"' : '') . '>' . $langDefault . '</option>';
688  // Traverse the number of languages
690  $locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
691  $languages = $locales->getLanguages();
692  foreach ($languages as $locale => $name) {
693  if ($locale !== 'default') {
694  $defaultName = isset($GLOBALS['LOCAL_LANG']['default']['lang_' . $locale]) ? $GLOBALS['LOCAL_LANG']['default']['lang_' . $locale][0]['source'] : $name;
695  $localizedName = htmlspecialchars($this->getLanguageService()->getLL('lang_' . $locale));
696  if ($localizedName === '') {
697  $localizedName = htmlspecialchars($name);
698  }
699  $localLabel = ' - [' . htmlspecialchars($defaultName) . ']';
700  $available = is_dir(PATH_typo3conf . 'l10n/' . $locale);
701  if ($available) {
702  $languageOptions[$defaultName] = '<option value="' . $locale . '"' . ($controller->beUser->uc['lang'] === $locale ? ' selected="selected"' : '') . '>' . $localizedName . $localLabel . '</option>';
703  }
704  }
705  }
706  ksort($languageOptions);
707  $languageCode = '
708  <select id="field_lang" name="data[lang]" class="form-control">' . implode('', $languageOptions) . '
709  </select>';
710  if ($controller->beUser->uc['lang'] && !@is_dir((PATH_typo3conf . 'l10n/' . $controller->beUser->uc['lang']))) {
711  // TODO: The text constants have to be moved into language files
712  $languageUnavailableWarning = 'The selected language "' . htmlspecialchars($this->getLanguageService()->getLL('lang_' . $controller->beUser->uc['lang'])) . '" is not available before the language files are installed.&nbsp;&nbsp;<br />&nbsp;&nbsp;' . ($controller->beUser->isAdmin() ? 'You can use the Language module to easily download new language files.' : 'Please ask your system administrator to do this.');
713  $languageCode = '<br /><span class="label label-danger">' . $languageUnavailableWarning . '</span><br /><br />' . $languageCode;
714  }
715  return $languageCode;
716  }
717 
726  public function renderStartModuleSelect($params, $pObj)
727  {
728  // Load available backend modules
729  $this->loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
730  $this->loadModules->observeWorkspaces = true;
731  $this->loadModules->load($GLOBALS['TBE_MODULES']);
732  $startModuleSelect = '<option value="">' . htmlspecialchars($this->getLanguageService()->getLL('startModule.firstInMenu')) . '</option>';
733  foreach ($pObj->loadModules->modules as $mainMod => $modData) {
734  if (!empty($modData['sub']) && is_array($modData['sub'])) {
735  $modules = '';
736  foreach ($modData['sub'] as $subData) {
737  $modName = $subData['name'];
738  $modules .= '<option value="' . htmlspecialchars($modName) . '"';
739  $modules .= $pObj->beUser->uc['startModule'] === $modName ? ' selected="selected"' : '';
740  $modules .= '>' . htmlspecialchars($this->getLanguageService()->sL($this->loadModules->getLabelsForModule($modName)['title'])) . '</option>';
741  }
742  $groupLabel = htmlspecialchars($this->getLanguageService()->sL($this->loadModules->getLabelsForModule($mainMod)['title']));
743  $startModuleSelect .= '<optgroup label="' . htmlspecialchars($groupLabel) . '">' . $modules . '</optgroup>';
744  }
745  }
746  return '<select id="field_startModule" name="data[startModule]" class="form-control">' . $startModuleSelect . '</select>';
747  }
748 
753  public function simulateUser()
754  {
755  // If admin, allow simulation of another user
756  $this->simUser = 0;
757  $this->simulateSelector = '';
758  unset($this->OLD_BE_USER);
759  $currentBeUser = $this->getBackendUser();
760  if ($currentBeUser->isAdmin()) {
761  $this->simUser = (int)GeneralUtility::_GP('simUser');
762  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
763  $users = $queryBuilder
764  ->select('*')
765  ->from('be_users')
766  ->where(
767  $queryBuilder->expr()->neq(
768  'uid',
769  $queryBuilder->createNamedParameter($currentBeUser->user['uid'], \PDO::PARAM_INT)
770  ),
771  $queryBuilder->expr()->notLike(
772  'username',
773  $queryBuilder->createNamedParameter(
774  $queryBuilder->escapeLikeWildcards('_cli_') . '%',
775  \PDO::PARAM_STR
776  )
777  )
778  )
779  ->orderBy('username')
780  ->execute()
781  ->fetchAll();
782  $opt = [];
783  foreach ($users as $rr) {
784  $label = $rr['username'] . ($rr['realName'] ? ' (' . $rr['realName'] . ')' : '');
785  $opt[] = '<option value="' . (int)$rr['uid'] . '"' . ($this->simUser === (int)$rr['uid'] ? ' selected="selected"' : '') . '>' . htmlspecialchars($label) . '</option>';
786  }
787  if (!empty($opt)) {
788  $this->simulateSelector = '<select id="field_simulate" class="form-control" name="simulateUser" onchange="window.location.href=' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('user_setup') . '&simUser=') . '+this.options[this.selectedIndex].value;"><option></option>' . implode('', $opt) . '</select>';
789  }
790  }
791  // This can only be set if the previous code was executed.
792  if ($this->simUser > 0) {
793  // Save old user...
794  $this->OLD_BE_USER = $currentBeUser;
795  // Unset current
796  // New backend user object
797  $currentBeUser = GeneralUtility::makeInstance(BackendUserAuthentication::class);
798  $currentBeUser->setBeUserByUid($this->simUser);
799  $currentBeUser->fetchGroupData();
800  $currentBeUser->backendSetUC();
801  }
802  $this->beUser = $currentBeUser;
803  }
804 
810  protected function renderSimulateUserSelectAndLabel()
811  {
812  if ($this->simulateSelector === '') {
813  return '';
814  }
815 
816  return '<div class="form-inline"><div class="form-group"><p>'
817  . '<label for="field_simulate" style="margin-right: 20px;">'
818  . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:setup/Resources/Private/Language/locallang.xlf:simulate'))
819  . '</label>'
820  . $this->simulateSelector
821  . '</p></div></div>';
822  }
823 
830  protected function checkAccess(array $config)
831  {
832  $access = $config['access'];
833 
834  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['setup']['accessLevelCheck'][$access])) {
835  if (class_exists($access)) {
836  $accessObject = GeneralUtility::makeInstance($access);
837  if (method_exists($accessObject, 'accessLevelCheck')) {
838  // Initialize vars. If method fails, $set will be set to FALSE
839  return $accessObject->accessLevelCheck($config);
840  }
841  }
842  } elseif ($access === 'admin') {
843  return $this->isAdmin;
844  }
845 
846  return false;
847  }
848 
857  protected function getLabel($str, $key = '', $addLabelTag = true)
858  {
859  if (substr($str, 0, 4) === 'LLL:') {
860  $out = htmlspecialchars($this->getLanguageService()->sL($str));
861  } else {
862  $out = htmlspecialchars($str);
863  }
864  if (isset($this->overrideConf[$key ?: $str])) {
865  $out = '<span style="color:#999999">' . $out . '</span>';
866  }
867  if ($addLabelTag) {
868  $out = '<label>' . $out . '</label>';
869  }
870  return $out;
871  }
872 
880  protected function getCSH($str, $label)
881  {
882  $context = '_MOD_user_setup';
883  $field = $str;
884  $strParts = explode(':', $str);
885  if (count($strParts) > 1) {
886  // Setting comes from another extension
887  $context = $strParts[0];
888  $field = $strParts[1];
889  } elseif ($str !== 'language' && $str !== 'simuser' && $str !== 'reset') {
890  $field = 'option_' . $str;
891  }
892  return BackendUtility::wrapInHelp($context, $field, $label);
893  }
894 
901  protected function getFieldsFromShowItem()
902  {
903  $allowedFields = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_USER_SETTINGS']['showitem'], true);
904  // do not ask for current password if admin (unknown for other users and no security gain)
905  if ($this->isAdmin) {
906  $key = array_search('passwordCurrent', $allowedFields);
907  if ($key !== false) {
908  unset($allowedFields[$key]);
909  }
910  }
911  if (!is_array($this->tsFieldConf)) {
912  return $allowedFields;
913  }
914  foreach ($this->tsFieldConf as $fieldName => $userTsFieldConfig) {
915  if (!empty($userTsFieldConfig['disabled'])) {
916  $fieldName = rtrim($fieldName, '.');
917  $key = array_search($fieldName, $allowedFields);
918  if ($key !== false) {
919  unset($allowedFields[$key]);
920  }
921  }
922  }
923  return $allowedFields;
924  }
925 
932  protected function getAvatarFileUid($beUserId)
933  {
934  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_reference');
935  $file = $queryBuilder
936  ->select('uid_local')
937  ->from('sys_file_reference')
938  ->where(
939  $queryBuilder->expr()->eq(
940  'tablenames',
941  $queryBuilder->createNamedParameter('be_users', \PDO::PARAM_STR)
942  ),
943  $queryBuilder->expr()->eq(
944  'fieldname',
945  $queryBuilder->createNamedParameter('avatar', \PDO::PARAM_STR)
946  ),
947  $queryBuilder->expr()->eq(
948  'table_local',
949  $queryBuilder->createNamedParameter('sys_file', \PDO::PARAM_STR)
950  ),
951  $queryBuilder->expr()->eq(
952  'uid_foreign',
953  $queryBuilder->createNamedParameter($beUserId, \PDO::PARAM_INT)
954  )
955  )
956  ->execute()
957  ->fetchColumn();
958  return (int)$file;
959  }
960 
968  protected function setAvatarFileUid($beUserId, $fileUid, array &$storeRec)
969  {
970 
971  // Update is only needed when new fileUid is set
972  if ((int)$fileUid === $this->getAvatarFileUid($beUserId)) {
973  return;
974  }
975 
976  // If user is not allowed to modify avatar $fileUid is empty - so don't overwrite existing avatar
977  if (empty($fileUid)) {
978  return;
979  }
980 
981  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file_reference');
982  $queryBuilder->getRestrictions()->removeAll();
983  $queryBuilder
984  ->delete('sys_file_reference')
985  ->where(
986  $queryBuilder->expr()->eq(
987  'tablenames',
988  $queryBuilder->createNamedParameter('be_users', \PDO::PARAM_STR)
989  ),
990  $queryBuilder->expr()->eq(
991  'fieldname',
992  $queryBuilder->createNamedParameter('avatar', \PDO::PARAM_STR)
993  ),
994  $queryBuilder->expr()->eq(
995  'table_local',
996  $queryBuilder->createNamedParameter('sys_file', \PDO::PARAM_STR)
997  ),
998  $queryBuilder->expr()->eq(
999  'uid_foreign',
1000  $queryBuilder->createNamedParameter($beUserId, \PDO::PARAM_INT)
1001  )
1002  )
1003  ->execute();
1004 
1005  // If Avatar is marked for delete => set it to empty string so it will be updated properly
1006  if ($fileUid === 'delete') {
1007  $fileUid = '';
1008  }
1009 
1010  // Create new reference
1011  if ($fileUid) {
1012 
1013  // Get file object
1014  try {
1015  $file = ResourceFactory::getInstance()->getFileObject($fileUid);
1016  } catch (FileDoesNotExistException $e) {
1017  $file = false;
1018  }
1019 
1020  // Check if user is allowed to use the image (only when not in simulation mode)
1021  if ($file && $this->simUser === 0 && !$file->getStorage()->checkFileActionPermission('read', $file)) {
1022  $file = false;
1023  }
1024 
1025  // Check if extension is allowed
1026  if ($file && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $file->getExtension())) {
1027 
1028  // Create new file reference
1029  $storeRec['sys_file_reference']['NEW1234'] = [
1030  'uid_local' => (int)$fileUid,
1031  'uid_foreign' => (int)$beUserId,
1032  'tablenames' => 'be_users',
1033  'fieldname' => 'avatar',
1034  'pid' => 0,
1035  'table_local' => 'sys_file',
1036  ];
1037  $storeRec['be_users'][(int)$beUserId]['avatar'] = 'NEW1234';
1038  }
1039  }
1040  }
1041 
1047  protected function addAvatarButtonJs($fieldName)
1048  {
1049  $this->moduleTemplate->addJavaScriptCode('avatar-button', '
1050  var browserWin="";
1051 
1052  function openFileBrowser() {
1053  var url = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('wizard_element_browser', ['mode' => 'file', 'bparams' => '||||dummy|setFileUid'])) . ';
1054  browserWin = window.open(url,"Typo3WinBrowser","height=650,width=800,status=0,menubar=0,resizable=1,scrollbars=1");
1055  browserWin.focus();
1056  }
1057 
1058  function clearExistingImage() {
1059  $(' . GeneralUtility::quoteJSvalue('#image_' . htmlspecialchars($fieldName)) . ').hide();
1060  $(' . GeneralUtility::quoteJSvalue('#clear_button_' . htmlspecialchars($fieldName)) . ').hide();
1061  $(' . GeneralUtility::quoteJSvalue('#field_' . htmlspecialchars($fieldName)) . ').val(\'delete\');
1062  }
1063 
1064  function setFileUid(field, value, fileUid) {
1065  clearExistingImage();
1066  $(' . GeneralUtility::quoteJSvalue('#field_' . htmlspecialchars($fieldName)) . ').val(fileUid);
1067  $(' . GeneralUtility::quoteJSvalue('#add_button_' . htmlspecialchars($fieldName)) . ').removeClass(\'btn-default\').addClass(\'btn-info\');
1068 
1069  browserWin.close();
1070  }
1071  ');
1072  }
1073 
1079  protected function getBackendUser()
1080  {
1081  return $GLOBALS['BE_USER'];
1082  }
1083 
1089  protected function getLanguageService()
1090  {
1091  return $GLOBALS['LANG'];
1092  }
1093 
1097  protected function addFlashMessages()
1098  {
1099  $flashMessages = [];
1100 
1101  // Show if setup was saved
1102  if ($this->setupIsUpdated && !$this->settingsAreResetToDefault) {
1103  $flashMessages[] = $this->getFlashMessage('setupWasUpdated', 'UserSettings');
1104  }
1105 
1106  // Show if temporary data was cleared
1107  if ($this->settingsAreResetToDefault) {
1108  $flashMessages[] = $this->getFlashMessage('settingsAreReset', 'resetConfiguration');
1109  }
1110 
1111  // Notice
1112  if ($this->setupIsUpdated || $this->settingsAreResetToDefault) {
1113  $flashMessages[] = $this->getFlashMessage('activateChanges', '', FlashMessage::INFO);
1114  }
1115 
1116  // If password is updated, output whether it failed or was OK.
1117  if ($this->passwordIsSubmitted) {
1118  $flashMessage = null;
1119  switch ($this->passwordIsUpdated) {
1120  case self::PASSWORD_OLD_WRONG:
1121  $flashMessages[] = $this->getFlashMessage('oldPassword_failed', 'newPassword', FlashMessage::ERROR);
1122  break;
1123  case self::PASSWORD_NOT_THE_SAME:
1124  $flashMessages[] = $this->getFlashMessage('newPassword_failed', 'newPassword', FlashMessage::ERROR);
1125  break;
1126  case self::PASSWORD_UPDATED:
1127  $flashMessages[] = $this->getFlashMessage('newPassword_ok', 'newPassword');
1128  break;
1129  }
1130  }
1131  if (!empty($flashMessages)) {
1132  $this->enqueueFlashMessages($flashMessages);
1133  }
1134  }
1135 
1140  protected function enqueueFlashMessages(array $flashMessages)
1141  {
1142  $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
1143  $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1144  foreach ($flashMessages as $flashMessage) {
1145  $defaultFlashMessageQueue->enqueue($flashMessage);
1146  }
1147  }
1148 
1155  protected function getFlashMessage($message, $title, $severity = FlashMessage::OK)
1156  {
1157  $title = !empty($title) ? $this->getLanguageService()->getLL($title) : ' ';
1159  FlashMessage::class,
1160  $this->getLanguageService()->getLL($message),
1161  $title,
1162  $severity
1163  );
1164  }
1165 }
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static getSaltingInstance($saltedHash='', $mode=TYPO3_MODE)
Definition: SaltFactory.php:83
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
getFlashMessage($message, $title, $severity=FlashMessage::OK)
static makeInstance($className,... $constructorArguments)
setAvatarFileUid($beUserId, $fileUid, array &$storeRec)
static get($classNameOrType='default',... $constructorArguments)
static setUpdateSignal($set='', $params='')
mainAction(ServerRequestInterface $request, ResponseInterface $response)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
$locales
Definition: be_users.php:6