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