TYPO3  7.6
SetupModuleController.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Setup\Controller;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
29 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
32 
37 {
42 
46  const PASSWORD_UPDATED = 1;
47 
52 
57  const PASSWORD_OLD_WRONG = 3;
58 
62  public $MOD_MENU = array();
63 
67  public $MOD_SETTINGS = array();
68 
72  public $doc;
73 
77  public $content;
78 
82  public $overrideConf;
83 
89  public $OLD_BE_USER;
90 
95 
99  protected $pagetreeNeedsRefresh = false;
100 
104  protected $isAdmin;
105 
109  protected $tsFieldConf;
110 
114  protected $saveData = false;
115 
119  protected $passwordIsUpdated = self::PASSWORD_NOT_UPDATED;
120 
124  protected $passwordIsSubmitted = false;
125 
129  protected $setupIsUpdated = false;
130 
134  protected $settingsAreResetToDefault = false;
135 
141  protected $formProtection;
142 
146  protected $simulateSelector = '';
147 
151  protected $simUser = '';
152 
158  protected $moduleName = 'user_setup';
159 
163  protected $loadModules;
164 
168  public function __construct()
169  {
170  parent::__construct();
171  $this->formProtection = FormProtectionFactory::get();
172  }
173 
179  public function getFormProtection()
180  {
181  return $this->formProtection;
182  }
183 
191  public function storeIncomingData()
192  {
193  // First check if something is submitted in the data-array from POST vars
194  $d = GeneralUtility::_POST('data');
195  $columns = $GLOBALS['TYPO3_USER_SETTINGS']['columns'];
196  $beUser = $this->getBackendUser();
197  $beUserId = $beUser->user['uid'];
198  $storeRec = array();
199  $fieldList = $this->getFieldsFromShowItem();
200  if (is_array($d) && $this->formProtection->validateToken((string)GeneralUtility::_POST('formToken'), 'BE user setup', 'edit')) {
201  // UC hashed before applying changes
202  $save_before = md5(serialize($beUser->uc));
203  // PUT SETTINGS into the ->uc array:
204  // Reload left frame when switching BE language
205  if (isset($d['lang']) && $d['lang'] != $beUser->uc['lang']) {
206  $this->languageUpdate = true;
207  }
208  // Reload pagetree if the title length is changed
209  if (isset($d['titleLen']) && $d['titleLen'] !== $beUser->uc['titleLen']) {
210  $this->pagetreeNeedsRefresh = true;
211  }
212  if ($d['setValuesToDefault']) {
213  // If every value should be default
214  $beUser->resetUC();
215  $this->settingsAreResetToDefault = true;
216  } elseif ($d['save']) {
217  // Save all submitted values if they are no array (arrays are with table=be_users) and exists in $GLOBALS['TYPO3_USER_SETTINGS'][columns]
218  foreach ($columns as $field => $config) {
219  if (!in_array($field, $fieldList)) {
220  continue;
221  }
222  if ($config['table']) {
223  if ($config['table'] === 'be_users' && !in_array($field, array('password', 'password2', 'passwordCurrent', 'email', 'realName', 'admin', 'avatar'))) {
224  if (!isset($config['access']) || $this->checkAccess($config) && $beUser->user[$field] !== $d['be_users'][$field]) {
225  if ($config['type'] === 'check') {
226  $fieldValue = isset($d['be_users'][$field]) ? 1 : 0;
227  } else {
228  $fieldValue = $d['be_users'][$field];
229  }
230  $storeRec['be_users'][$beUserId][$field] = $fieldValue;
231  $beUser->user[$field] = $fieldValue;
232  }
233  }
234  }
235  if ($config['type'] === 'check') {
236  $beUser->uc[$field] = isset($d[$field]) ? 1 : 0;
237  } else {
238  $beUser->uc[$field] = htmlspecialchars($d[$field]);
239  }
240  }
241  // Personal data for the users be_user-record (email, name, password...)
242  // If email and name is changed, set it in the users record:
243  $be_user_data = $d['be_users'];
244  // Possibility to modify the transmitted values. Useful to do transformations, like RSA password decryption
245  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'])) {
246  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['modifyUserDataBeforeSave'] as $function) {
247  $params = array('be_user_data' => &$be_user_data);
248  GeneralUtility::callUserFunction($function, $params, $this);
249  }
250  }
251  $this->passwordIsSubmitted = (string)$be_user_data['password'] !== '';
252  $passwordIsConfirmed = $this->passwordIsSubmitted && $be_user_data['password'] === $be_user_data['password2'];
253  // Update the real name:
254  if ($be_user_data['realName'] !== $beUser->user['realName']) {
255  $beUser->user['realName'] = ($storeRec['be_users'][$beUserId]['realName'] = substr($be_user_data['realName'], 0, 80));
256  }
257  // Update the email address:
258  if ($be_user_data['email'] !== $beUser->user['email']) {
259  $beUser->user['email'] = ($storeRec['be_users'][$beUserId]['email'] = substr($be_user_data['email'], 0, 80));
260  }
261  // Update the password:
262  if ($passwordIsConfirmed) {
263  $currentPasswordHashed = $GLOBALS['BE_USER']->user['password'];
264  $saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($currentPasswordHashed);
265  if ($saltFactory->checkPassword($be_user_data['passwordCurrent'], $currentPasswordHashed)) {
266  $this->passwordIsUpdated = self::PASSWORD_UPDATED;
267  $storeRec['be_users'][$beUserId]['password'] = $be_user_data['password'];
268  } else {
269  $this->passwordIsUpdated = self::PASSWORD_OLD_WRONG;
270  }
271  } else {
272  $this->passwordIsUpdated = self::PASSWORD_NOT_THE_SAME;
273  }
274 
275  $this->setAvatarFileUid($beUserId, $be_user_data['avatar'], $storeRec);
276 
277  $this->saveData = true;
278  }
279  // Inserts the overriding values.
280  $beUser->overrideUC();
281  $save_after = md5(serialize($beUser->uc));
282  // If something in the uc-array of the user has changed, we save the array...
283  if ($save_before != $save_after) {
284  $beUser->writeUC($beUser->uc);
285  $beUser->writelog(254, 1, 0, 1, 'Personal settings changed', array());
286  $this->setupIsUpdated = true;
287  }
288  // Persist data if something has changed:
289  if (!empty($storeRec) && $this->saveData) {
290  // Make instance of TCE for storing the changes.
292  $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
293  $dataHandler->stripslashes_values = false;
294  // This is so the user can actually update his user record.
295  $isAdmin = $beUser->user['admin'];
296  $beUser->user['admin'] = 1;
297  $dataHandler->start($storeRec, array(), $beUser);
298  // This is to make sure that the users record can be updated even if in another workspace. This is tolerated.
299  $dataHandler->bypassWorkspaceRestrictions = true;
300  $dataHandler->process_datamap();
301  unset($tce);
302  if ($this->passwordIsUpdated === self::PASSWORD_NOT_UPDATED || count($storeRec['be_users'][$beUserId]) > 1) {
303  $this->setupIsUpdated = true;
304  }
305  // Restore admin status after processing
306  $beUser->user['admin'] = $isAdmin;
307  }
308  }
309  }
310 
311  /******************************
312  *
313  * Rendering module
314  *
315  ******************************/
321  public function init()
322  {
323  $this->getLanguageService()->includeLLFile('EXT:setup/Resources/Private/Language/locallang.xlf');
324 
325  // Returns the script user - that is the REAL logged in user! ($GLOBALS[BE_USER] might be another user due to simulation!)
326  $scriptUser = $this->getRealScriptUserObj();
327 
328  $this->isAdmin = $scriptUser->isAdmin();
329  // Getting the 'override' values as set might be set in User TSconfig
330  $this->overrideConf = $this->getBackendUser()->getTSConfigProp('setup.override');
331  // Getting the disabled fields might be set in User TSconfig (eg setup.fields.password.disabled=1)
332  $this->tsFieldConf = $this->getBackendUser()->getTSConfigProp('setup.fields');
333  // id password is disabled, disable repeat of password too (password2)
334  if (isset($this->tsFieldConf['password.']) && $this->tsFieldConf['password.']['disabled']) {
335  $this->tsFieldConf['password2.']['disabled'] = 1;
336  $this->tsFieldConf['passwordCurrent.']['disabled'] = 1;
337  }
338  // Create instance of object for output of data
339  $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
340  }
341 
347  protected function getJavaScript()
348  {
349  $javaScript = '';
350  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'])) {
351  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/setup/mod/index.php']['setupScriptHook'] as $function) {
352  $params = array();
353  $javaScript .= GeneralUtility::callUserFunction($function, $params, $this);
354  }
355  }
356  return $javaScript;
357  }
358 
364  public function main()
365  {
366  $this->content .= '<form action="' . BackendUtility::getModuleUrl('user_setup') . '" method="post" id="SetupModuleController" name="usersetup" enctype="multipart/form-data">';
367  if ($this->languageUpdate) {
368  $this->moduleTemplate->addJavaScriptCode('languageUpdate', '
369  if (top.refreshMenu) {
370  top.refreshMenu();
371  } else {
372  top.TYPO3ModuleMenu.refreshMenu();
373  }
374  ');
375  }
376  if ($this->pagetreeNeedsRefresh) {
377  BackendUtility::setUpdateSignal('updatePageTree');
378  }
379  // Start page:
380  $this->moduleTemplate->loadJavascriptLib('sysext/backend/Resources/Public/JavaScript/md5.js');
381  // Use a wrapper div
382  $this->content .= '<div id="user-setup-wrapper">';
383  // Load available backend modules
384  $this->loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
385  $this->loadModules->observeWorkspaces = true;
386  $this->loadModules->load($GLOBALS['TBE_MODULES']);
387  $this->content .= $this->doc->header($this->getLanguageService()->getLL('UserSettings'));
388  // Show if setup was saved
389  if ($this->setupIsUpdated && !$this->settingsAreResetToDefault) {
390  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('setupWasUpdated'), $this->getLanguageService()->getLL('UserSettings'));
391  $this->content .= $flashMessage->render();
392  }
393 
394  // Show if temporary data was cleared
395  if ($this->settingsAreResetToDefault) {
396  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('settingsAreReset'), $this->getLanguageService()->getLL('resetConfiguration'));
397  $this->content .= $flashMessage->render();
398  }
399 
400  // Notice
401  if ($this->setupIsUpdated || $this->settingsAreResetToDefault) {
402  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('activateChanges'), '', FlashMessage::INFO);
403  $this->content .= $flashMessage->render();
404  }
405 
406  // If password is updated, output whether it failed or was OK.
407  if ($this->passwordIsSubmitted) {
408  $flashMessage = null;
409  switch ($this->passwordIsUpdated) {
410  case self::PASSWORD_OLD_WRONG:
411  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('oldPassword_failed'), $this->getLanguageService()->getLL('newPassword'), FlashMessage::ERROR);
412  break;
413  case self::PASSWORD_NOT_THE_SAME:
414  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('newPassword_failed'), $this->getLanguageService()->getLL('newPassword'), FlashMessage::ERROR);
415  break;
416  case self::PASSWORD_UPDATED:
417  $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->getLL('newPassword_ok'), $this->getLanguageService()->getLL('newPassword'));
418  break;
419  }
420  if ($flashMessage) {
421  $this->content .= $flashMessage->render();
422  }
423  }
424 
425  // Render user switch
426  $this->content .= $this->renderSimulateUserSelectAndLabel();
427 
428  // Render the menu items
429  $menuItems = $this->renderUserSetup();
430  $this->content .= $this->moduleTemplate->getDynamicTabMenu($menuItems, 'user-setup', 1, false, false);
431  $formToken = $this->formProtection->generateToken('BE user setup', 'edit');
432  $this->content .= '<div>';
433  $this->content .= '<input type="hidden" name="simUser" value="' . $this->simUser . '" />
434  <input type="hidden" name="formToken" value="' . $formToken . '" />
435  <input type="hidden" value="1" name="data[save]" />
436  <input type="hidden" name="data[setValuesToDefault]" value="0" id="setValuesToDefault" />';
437  $this->content .= '</div>';
438  // End of wrapper div
439  $this->content .= '</div>';
440  // Setting up the buttons and markers for docheader
441  $this->getButtons();
442  // Build the <body> for the module
443  // Renders the module page
444  $this->moduleTemplate->setContent($this->content);
445  $this->content .= '</form>';
446  }
447 
448 
458  {
459  $GLOBALS['SOBE'] = $this;
460  $this->simulateUser();
461  $this->storeIncomingData();
462  $this->init();
463  $this->main();
464 
465  $response->getBody()->write($this->moduleTemplate->renderContent());
466  return $response;
467  }
468 
475  public function printContent()
476  {
478  echo $this->content;
479  }
480 
484  protected function getButtons()
485  {
486  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
487  $cshButton = $buttonBar->makeHelpButton()
488  ->setModuleName('_MOD_user_setup')
489  ->setFieldName('');
490  $buttonBar->addButton($cshButton);
491 
492  $saveButton = $buttonBar->makeInputButton()
493  ->setName('data[save]')
494  ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', true))
495  ->setValue('1')
496  ->setForm('SetupModuleController')
497  ->setShowLabelText(true)
498  ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
499 
500  $buttonBar->addButton($saveButton);
501  $shortcutButton = $buttonBar->makeShortcutButton()
502  ->setModuleName($this->moduleName);
503  $buttonBar->addButton($shortcutButton);
504  }
505 
506  /******************************
507  *
508  * Render module
509  *
510  ******************************/
511 
518  protected function renderUserSetup()
519  {
520  $html = '';
521  $result = array();
522  $firstTabLabel = '';
523  $code = array();
524  $fieldArray = $this->getFieldsFromShowItem();
525  $tabLabel = '';
526  foreach ($fieldArray as $fieldName) {
527  $more = '';
528  if (substr($fieldName, 0, 8) === '--div--;') {
529  if ($firstTabLabel === '') {
530  // First tab
531  $tabLabel = $this->getLabel(substr($fieldName, 8), '', false);
532  $firstTabLabel = $tabLabel;
533  } else {
534  $result[] = array(
535  'label' => $tabLabel,
536  'content' => count($code) ? implode(LF, $code) : ''
537  );
538  $tabLabel = $this->getLabel(substr($fieldName, 8), '', false);
539  $code = array();
540  }
541  continue;
542  }
543  $config = $GLOBALS['TYPO3_USER_SETTINGS']['columns'][$fieldName];
544 
545  // Field my be disabled in setup.fields
546  if (isset($this->tsFieldConf[$fieldName . '.']['disabled']) && $this->tsFieldConf[$fieldName . '.']['disabled'] == 1) {
547  continue;
548  }
549  if (isset($config['access']) && !$this->checkAccess($config)) {
550  continue;
551  }
552  $label = $this->getLabel($config['label'], $fieldName);
553  $label = $this->getCSH($config['csh'] ?: $fieldName, $label);
554  $type = $config['type'];
555  $class = $config['class'];
556 
557  if ($type !== 'check') {
558  $class .= ' form-control';
559  }
560 
561  $style = $config['style'];
562  if ($class) {
563  $more .= ' class="' . $class . '"';
564  }
565  if ($style) {
566  $more .= ' style="' . $style . '"';
567  }
568  if (isset($this->overrideConf[$fieldName])) {
569  $more .= ' disabled="disabled"';
570  }
571  $value = $config['table'] === 'be_users' ? $this->getBackendUser()->user[$fieldName] : $this->getBackendUser()->uc[$fieldName];
572  if (!$value && isset($config['default'])) {
573  $value = $config['default'];
574  }
575  $dataAdd = '';
576  if ($config['table'] === 'be_users') {
577  $dataAdd = '[be_users]';
578  }
579 
580  switch ($type) {
581  case 'text':
582  case 'email':
583  case 'password':
584  $noAutocomplete = '';
585  if ($type === 'password') {
586  $value = '';
587  $noAutocomplete = 'autocomplete="off" ';
588  $more .= ' data-rsa-encryption=""';
589  }
590  $html = '<input id="field_' . $fieldName . '"
591  type="' . $type . '"
592  name="data' . $dataAdd . '[' . $fieldName . ']" ' .
593  $noAutocomplete .
594  'value="' . htmlspecialchars($value) . '" ' .
595  $more .
596  ' />';
597  break;
598  case 'check':
599  $html = $label . '<div class="checkbox"><label><input id="field_' . $fieldName . '"
600  type="checkbox"
601  name="data' . $dataAdd . '[' . $fieldName . ']"' .
602  ($value ? ' checked="checked"' : '') .
603  $more .
604  ' /></label></div>';
605  $label = '';
606  break;
607  case 'select':
608  if ($config['itemsProcFunc']) {
609  $html = GeneralUtility::callUserFunction($config['itemsProcFunc'], $config, $this, '');
610  } else {
611  $html = '<select id="field_' . $fieldName . '"
612  name="data' . $dataAdd . '[' . $fieldName . ']"' .
613  $more . '>' . LF;
614  foreach ($config['items'] as $key => $optionLabel) {
615  $html .= '<option value="' . $key . '"' . ($value == $key ? ' selected="selected"' : '') . '>' . $this->getLabel($optionLabel, '', false) . '</option>' . LF;
616  }
617  $html .= '</select>';
618  }
619  break;
620  case 'user':
621  $html = GeneralUtility::callUserFunction($config['userFunc'], $config, $this, '');
622  break;
623  case 'button':
624  if ($config['onClick']) {
625  $onClick = $config['onClick'];
626  if ($config['onClickLabels']) {
627  foreach ($config['onClickLabels'] as $key => $labelclick) {
628  $config['onClickLabels'][$key] = $this->getLabel($labelclick, '', false);
629  }
630  $onClick = vsprintf($onClick, $config['onClickLabels']);
631  }
632  $html = '<br><input class="btn btn-default" type="button"
633  value="' . $this->getLabel($config['buttonlabel'], '', false) . '"
634  onclick="' . $onClick . '" />';
635  }
636  break;
637  case 'avatar':
638  // Get current avatar image
639  $html = '<br>';
640  $avatarFileUid = $this->getAvatarFileUid($this->getBackendUser()->user['uid']);
641 
642  if ($avatarFileUid) {
643  $defaultAvatarProvider = GeneralUtility::makeInstance(DefaultAvatarProvider::class);
644  $avatarImage = $defaultAvatarProvider->getImage($this->getBackendUser()->user, 32);
645  if ($avatarImage) {
646  $icon = '<span class="avatar"><span class="avatar-image">' .
647  '<img src="' . htmlspecialchars($avatarImage->getUrl(true)) . '"' .
648  ' width="' . (int)$avatarImage->getWidth() . '" ' .
649  'height="' . (int)$avatarImage->getHeight() . '" />' .
650  '</span></span>';
651  $html .= '<span class="pull-left" style="padding-right: 10px" id="image_' . htmlspecialchars($fieldName) . '">' . $icon . ' </span>';
652  }
653  }
654  $html .= '<input id="field_' . htmlspecialchars($fieldName) . '" type="hidden" ' .
655  'name="data' . $dataAdd . '[' . htmlspecialchars($fieldName) . ']"' . $more .
656  ' value="' . $avatarFileUid . '" />';
657 
658  $html .= '<div class="btn-group">';
659  if ($avatarFileUid) {
660  $html .= '<a id="clear_button_' . htmlspecialchars($fieldName) . '" onclick="clearExistingImage(); return false;" class="btn btn-default"><span class="t3-icon fa t3-icon fa fa-remove"> </span></a>';
661  }
662  $html .= '<a id="add_button_' . htmlspecialchars($fieldName) . '" class="btn btn-default btn-add-avatar" onclick="openFileBrowser();return false;"><span class="t3-icon t3-icon-actions t3-icon-actions-insert t3-icon-insert-record"> </span></a>' .
663  '</div>';
664 
665  $this->addAvatarButtonJs($fieldName);
666  break;
667  default:
668  $html = '';
669  }
670 
671  $code[] = '<div class="form-section"><div class="form-group">' .
672  $label .
673  $html .
674  '</div></div>';
675  }
676 
677  $result[] = array(
678  'label' => $tabLabel,
679  'content' => count($code) ? implode(LF, $code) : ''
680  );
681  return $result;
682  }
683 
684  /******************************
685  *
686  * Helper functions
687  *
688  ******************************/
695  protected function getRealScriptUserObj()
696  {
697  return is_object($this->OLD_BE_USER) ? $this->OLD_BE_USER : $this->getBackendUser();
698  }
699 
707  public function renderLanguageSelect($params)
708  {
709  $languageOptions = array();
710  // Compile the languages dropdown
711  $langDefault = $this->getLanguageService()->getLL('lang_default', true);
712  $languageOptions[$langDefault] = '<option value=""' . ($this->getBackendUser()->uc['lang'] === '' ? ' selected="selected"' : '') . '>' . $langDefault . '</option>';
713  // Traverse the number of languages
715  $locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
716  $languages = $locales->getLanguages();
717  foreach ($languages as $locale => $name) {
718  if ($locale !== 'default') {
719  $defaultName = isset($GLOBALS['LOCAL_LANG']['default']['lang_' . $locale]) ? $GLOBALS['LOCAL_LANG']['default']['lang_' . $locale][0]['source'] : $name;
720  $localizedName = $this->getLanguageService()->getLL('lang_' . $locale, true);
721  if ($localizedName === '') {
722  $localizedName = htmlspecialchars($name);
723  }
724  $localLabel = ' - [' . htmlspecialchars($defaultName) . ']';
725  $available = is_dir(PATH_typo3conf . 'l10n/' . $locale);
726  if ($available) {
727  $languageOptions[$defaultName] = '<option value="' . $locale . '"' . ($this->getBackendUser()->uc['lang'] === $locale ? ' selected="selected"' : '') . '>' . $localizedName . $localLabel . '</option>';
728  }
729  }
730  }
731  ksort($languageOptions);
732  $languageCode = '
733  <select id="field_lang" name="data[lang]" class="form-control">' . implode('', $languageOptions) . '
734  </select>';
735  if ($this->getBackendUser()->uc['lang'] && !@is_dir((PATH_typo3conf . 'l10n/' . $this->getBackendUser()->uc['lang']))) {
736  $languageUnavailableWarning = 'The selected language "' . $this->getLanguageService()->getLL(('lang_' . $this->getBackendUser()->uc['lang']), true) . '" is not available before the language files are installed.<br />' . ($this->getBackendUser()->isAdmin() ? 'You can use the Language module to easily download new language files.' : 'Please ask your system administrator to do this.');
737  $languageUnavailableMessage = GeneralUtility::makeInstance(FlashMessage::class, $languageUnavailableWarning, '', FlashMessage::WARNING);
738  $languageCode = $languageUnavailableMessage->render() . $languageCode;
739  }
740  return $languageCode;
741  }
742 
751  public function renderStartModuleSelect($params, $pObj)
752  {
753  $startModuleSelect = '<option value="">' . $this->getLanguageService()->getLL('startModule.firstInMenu', true) . '</option>';
754  foreach ($pObj->loadModules->modules as $mainMod => $modData) {
755  if (!empty($modData['sub']) && is_array($modData['sub'])) {
756  $modules = '';
757  foreach ($modData['sub'] as $subData) {
758  $modName = $subData['name'];
759  $modules .= '<option value="' . htmlspecialchars($modName) . '"';
760  $modules .= $this->getBackendUser()->uc['startModule'] === $modName ? ' selected="selected"' : '';
761  $modules .= '>' . $this->getLanguageService()->moduleLabels['tabs'][$modName . '_tab'] . '</option>';
762  }
763  $groupLabel = $this->getLanguageService()->moduleLabels['tabs'][$mainMod . '_tab'];
764  $startModuleSelect .= '<optgroup label="' . htmlspecialchars($groupLabel) . '">' . $modules . '</optgroup>';
765  }
766  }
767  return '<select id="field_startModule" name="data[startModule]" class="form-control">' . $startModuleSelect . '</select>';
768  }
769 
776  public function simulateUser()
777  {
778  // If admin, allow simulation of another user
779  $this->simUser = 0;
780  $this->simulateSelector = '';
781  unset($this->OLD_BE_USER);
782  if ($this->getBackendUser()->isAdmin()) {
783  $this->simUser = (int)GeneralUtility::_GP('simUser');
784  // Make user-selector:
785  $db = $this->getDatabaseConnection();
786  $where = 'AND username NOT LIKE ' . $db->fullQuoteStr($db->escapeStrForLike('_cli_', 'be_users') . '%', 'be_users');
787  $where .= ' AND uid <> ' . (int)$this->getBackendUser()->user['uid'] . BackendUtility::BEenableFields('be_users');
788  $users = BackendUtility::getUserNames('username,usergroup,usergroup_cached_list,uid,realName', $where);
789  $opt = array();
790  foreach ($users as $rr) {
791  $label = htmlspecialchars(($rr['username'] . ($rr['realName'] ? ' (' . $rr['realName'] . ')' : '')));
792  $opt[] = '<option value="' . $rr['uid'] . '"' . ($this->simUser == $rr['uid'] ? ' selected="selected"' : '') . '>' . $label . '</option>';
793  }
794  if (!empty($opt)) {
795  $this->simulateSelector = '<select id="field_simulate" name="simulateUser" onchange="window.location.href=' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('user_setup') . '&simUser=') . '+this.options[this.selectedIndex].value;"><option></option>' . implode('', $opt) . '</select>';
796  }
797  }
798  // This can only be set if the previous code was executed.
799  if ($this->simUser > 0) {
800  // Save old user...
801  $this->OLD_BE_USER = $this->getBackendUser();
802  unset($GLOBALS['BE_USER']);
803  // Unset current
804  // New backend user object
805  $BE_USER = GeneralUtility::makeInstance(BackendUserAuthentication::class);
806  $BE_USER->setBeUserByUid($this->simUser);
807  $BE_USER->fetchGroupData();
808  $BE_USER->backendSetUC();
809  // Must do this, because unsetting $BE_USER before apparently unsets the reference to the global variable by this name!
810  $GLOBALS['BE_USER'] = $BE_USER;
811  }
812  }
813 
819  protected function renderSimulateUserSelectAndLabel()
820  {
821  if ($this->simulateSelector === '') {
822  return '';
823  }
824 
825  return '<p>' .
826  '<label for="field_simulate" style="margin-right: 20px;">' .
827  $this->getLanguageService()->sL('LLL:EXT:setup/Resources/Private/Language/locallang.xlf:simulate') .
828  '</label>' .
829  $this->simulateSelector .
830  '</p>';
831  }
832 
839  protected function checkAccess(array $config)
840  {
841  $access = $config['access'];
842 
843  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['setup']['accessLevelCheck'][$access])) {
844  if (class_exists($access)) {
845  $accessObject = GeneralUtility::makeInstance($access);
846  if (method_exists($accessObject, 'accessLevelCheck')) {
847  // Initialize vars. If method fails, $set will be set to FALSE
848  return $accessObject->accessLevelCheck($config);
849  }
850  }
851  } elseif ($access == 'admin') {
852  return $this->isAdmin;
853  }
854 
855  return false;
856  }
857 
867  protected function getLabel($str, $key = '', $addLabelTag = true, $altLabelTagId = '')
868  {
869  if (substr($str, 0, 4) === 'LLL:') {
870  $out = $this->getLanguageService()->sL($str);
871  } else {
872  $out = htmlspecialchars($str);
873  }
874  if (isset($this->overrideConf[$key ?: $str])) {
875  $out = '<span style="color:#999999">' . $out . '</span>';
876  }
877  if ($addLabelTag) {
878  $out = '<label for="' . ($altLabelTagId ?: 'field_' . $key) . '">' . $out . '</label>';
879  }
880  return $out;
881  }
882 
890  protected function getCSH($str, $label)
891  {
892  $context = '_MOD_user_setup';
893  $field = $str;
894  $strParts = explode(':', $str);
895  if (count($strParts) > 1) {
896  // Setting comes from another extension
897  $context = $strParts[0];
898  $field = $strParts[1];
899  } elseif (!GeneralUtility::inList('language,simuser,reset', $str)) {
900  $field = 'option_' . $str;
901  }
902  return BackendUtility::wrapInHelp($context, $field, $label);
903  }
904 
910  protected function getFieldsFromShowItem()
911  {
912  return GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_USER_SETTINGS']['showitem'], true);
913  }
914 
921  protected function getAvatarFileUid($beUserId)
922  {
923  $file = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
924  'uid_local',
925  'sys_file_reference',
926  'tablenames = \'be_users\' AND fieldname = \'avatar\' AND ' .
927  'table_local = \'sys_file\' AND uid_foreign = ' . (int)$beUserId .
928  BackendUtility::BEenableFields('sys_file_reference') . BackendUtility::deleteClause('sys_file_reference')
929  );
930  return $file ? $file['uid_local'] : 0;
931  }
932 
940  protected function setAvatarFileUid($beUserId, $fileUid, array &$storeRec)
941  {
942 
943  // Update is only needed when new fileUid is set
944  if ((int)$fileUid === $this->getAvatarFileUid($beUserId)) {
945  return;
946  }
947 
948  // Delete old file reference
949  $this->getDatabaseConnection()->exec_DELETEquery(
950  'sys_file_reference',
951  'tablenames = \'be_users\' AND fieldname = \'avatar\' AND ' .
952  'table_local = \'sys_file\' AND uid_foreign = ' . (int)$beUserId
953  );
954 
955  // Create new reference
956  if ($fileUid) {
957 
958  // Get file object
959  try {
960  $file = ResourceFactory::getInstance()->getFileObject($fileUid);
961  } catch (FileDoesNotExistException $e) {
962  $file = false;
963  }
964 
965  // Check if user is allowed to use the image (only when not in simulation mode)
966  if ($file && $this->simUser === 0 && !$file->getStorage()->checkFileActionPermission('read', $file)) {
967  $file = false;
968  }
969 
970  // Check if extension is allowed
971  if ($file && GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $file->getExtension())) {
972 
973  // Create new file reference
974  $storeRec['sys_file_reference']['NEW1234'] = array(
975  'uid_local' => $fileUid,
976  'uid_foreign' => $beUserId,
977  'tablenames' => 'be_users',
978  'fieldname' => 'avatar',
979  'pid' => 0,
980  'table_local' => 'sys_file',
981  );
982  $storeRec['be_users'][(int)$beUserId]['avatar'] = 'NEW1234';
983  }
984  }
985  }
986 
992  protected function addAvatarButtonJs($fieldName)
993  {
994  $this->moduleTemplate->addJavaScriptCode('avatar-button', '
995  var browserWin="";
996 
997  function openFileBrowser() {
998  var url = ' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('wizard_element_browser', ['mode' => 'file', 'bparams' => '||||dummy|setFileUid'])) . ';
999  browserWin = window.open(url,"Typo3WinBrowser","height=650,width=800,status=0,menubar=0,resizable=1,scrollbars=1");
1000  browserWin.focus();
1001  }
1002 
1003  function clearExistingImage() {
1004  TYPO3.jQuery(\'#image_' . htmlspecialchars($fieldName) . '\').hide();
1005  TYPO3.jQuery(\'#clear_button_' . htmlspecialchars($fieldName) . '\').hide();
1006  TYPO3.jQuery(\'#field_' . htmlspecialchars($fieldName) . '\').val(\'\');
1007  }
1008 
1009  function setFileUid(field, value, fileUid) {
1010  clearExistingImage();
1011  TYPO3.jQuery(\'#field_' . htmlspecialchars($fieldName) . '\').val(fileUid);
1012  TYPO3.jQuery(\'#add_button_' . htmlspecialchars($fieldName) . '\').removeClass(\'btn-default\').addClass(\'btn-info\');
1013 
1014  browserWin.close();
1015  }
1016  ');
1017  }
1018 
1024  protected function getBackendUser()
1025  {
1026  return $GLOBALS['BE_USER'];
1027  }
1028 
1034  protected function getLanguageService()
1035  {
1036  return $GLOBALS['LANG'];
1037  }
1038 
1042  protected function getDatabaseConnection()
1043  {
1044  return $GLOBALS['TYPO3_DB'];
1045  }
1046 }