| 1 | <?php |
| 2 | |
| 3 | namespace wcf\acp\form; |
| 4 | |
| 5 | use wcf\data\style\Style; |
| 6 | use wcf\data\user\avatar\UserAvatar; |
| 7 | use wcf\data\user\avatar\UserAvatarAction; |
| 8 | use wcf\data\user\cover\photo\UserCoverPhoto; |
| 9 | use wcf\data\user\group\UserGroup; |
| 10 | use wcf\data\user\User; |
| 11 | use wcf\data\user\UserAction; |
| 12 | use wcf\data\user\UserEditor; |
| 13 | use wcf\data\user\UserProfileAction; |
| 14 | use wcf\form\AbstractForm; |
| 15 | use wcf\system\cache\runtime\UserProfileRuntimeCache; |
| 16 | use wcf\system\exception\IllegalLinkException; |
| 17 | use wcf\system\exception\PermissionDeniedException; |
| 18 | use wcf\system\exception\UserInputException; |
| 19 | use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; |
| 20 | use wcf\system\moderation\queue\ModerationQueueManager; |
| 21 | use wcf\system\option\user\UserOptionHandler; |
| 22 | use wcf\system\style\StyleHandler; |
| 23 | use wcf\system\user\command\SetColorScheme; |
| 24 | use wcf\system\user\multifactor\Setup; |
| 25 | use wcf\system\WCF; |
| 26 | use wcf\util\StringUtil; |
| 27 | |
| 28 | /** |
| 29 | * Shows the user edit form. |
| 30 | * |
| 31 | * @author Marcel Werk |
| 32 | * @copyright 2001-2020 WoltLab GmbH |
| 33 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
| 34 | */ |
| 35 | class UserEditForm extends UserAddForm |
| 36 | { |
| 37 | /** |
| 38 | * @inheritDoc |
| 39 | */ |
| 40 | public $activeMenuItem = 'wcf.acp.menu.link.user.list'; |
| 41 | |
| 42 | /** |
| 43 | * @inheritDoc |
| 44 | */ |
| 45 | public $neededPermissions = ['admin.user.canEditUser']; |
| 46 | |
| 47 | /** |
| 48 | * user id |
| 49 | * @var int |
| 50 | */ |
| 51 | public $userID = 0; |
| 52 | |
| 53 | /** |
| 54 | * user editor object |
| 55 | * @var UserEditor |
| 56 | */ |
| 57 | public $user; |
| 58 | |
| 59 | /** |
| 60 | * ban status |
| 61 | * @var bool |
| 62 | */ |
| 63 | public $banned = 0; |
| 64 | |
| 65 | /** |
| 66 | * ban reason |
| 67 | * @var string |
| 68 | */ |
| 69 | public $banReason = ''; |
| 70 | |
| 71 | /** |
| 72 | * date when the ban expires |
| 73 | * @var int |
| 74 | */ |
| 75 | public $banExpires = 0; |
| 76 | |
| 77 | /** |
| 78 | * user avatar object |
| 79 | * @var UserAvatar |
| 80 | */ |
| 81 | public $userAvatar; |
| 82 | |
| 83 | /** |
| 84 | * avatar type |
| 85 | * @var string |
| 86 | */ |
| 87 | public $avatarType = 'none'; |
| 88 | |
| 89 | /** |
| 90 | * true to disable this avatar |
| 91 | * @var bool |
| 92 | */ |
| 93 | public $disableAvatar = 0; |
| 94 | |
| 95 | /** |
| 96 | * reason |
| 97 | * @var string |
| 98 | */ |
| 99 | public $disableAvatarReason = ''; |
| 100 | |
| 101 | /** |
| 102 | * date when the avatar will be enabled again |
| 103 | * @var int |
| 104 | */ |
| 105 | public $disableAvatarExpires = 0; |
| 106 | |
| 107 | /** |
| 108 | * user cover photo object |
| 109 | * @var UserCoverPhoto |
| 110 | */ |
| 111 | public $userCoverPhoto; |
| 112 | |
| 113 | /** |
| 114 | * true to disable this cover photo |
| 115 | * @var bool |
| 116 | */ |
| 117 | public $disableCoverPhoto = 0; |
| 118 | |
| 119 | /** |
| 120 | * reason |
| 121 | * @var string |
| 122 | */ |
| 123 | public $disableCoverPhotoReason = ''; |
| 124 | |
| 125 | /** |
| 126 | * date when the cover photo will be enabled again |
| 127 | * @var int |
| 128 | */ |
| 129 | public $disableCoverPhotoExpires = 0; |
| 130 | |
| 131 | /** |
| 132 | * true to delete the current cover photo |
| 133 | * @var bool |
| 134 | */ |
| 135 | public $deleteCoverPhoto = 0; |
| 136 | |
| 137 | /** |
| 138 | * true to delete the current auth data |
| 139 | * @var bool |
| 140 | */ |
| 141 | public $disconnect3rdParty = 0; |
| 142 | |
| 143 | /** |
| 144 | * true to disable multifactor authentication |
| 145 | * @var bool |
| 146 | */ |
| 147 | public $multifactorDisable = 0; |
| 148 | |
| 149 | /** |
| 150 | * list of available styles for the edited user |
| 151 | * @var Style[] |
| 152 | * @since 5.3 |
| 153 | */ |
| 154 | public $availableStyles = []; |
| 155 | |
| 156 | /** |
| 157 | * id of the used style |
| 158 | * @var int |
| 159 | * @since 5.3 |
| 160 | */ |
| 161 | public $styleID = 0; |
| 162 | |
| 163 | /** |
| 164 | * @since 6.0 |
| 165 | */ |
| 166 | public string $colorScheme = 'system'; |
| 167 | |
| 168 | /** |
| 169 | * @inheritDoc |
| 170 | */ |
| 171 | public function readParameters() |
| 172 | { |
| 173 | if (isset($_REQUEST['id'])) { |
| 174 | $this->userID = \intval($_REQUEST['id']); |
| 175 | } |
| 176 | $user = new User($this->userID); |
| 177 | if (!$user->userID) { |
| 178 | throw new IllegalLinkException(); |
| 179 | } |
| 180 | |
| 181 | $this->user = new UserEditor($user); |
| 182 | if (!UserGroup::isAccessibleGroup($this->user->getGroupIDs())) { |
| 183 | throw new PermissionDeniedException(); |
| 184 | } |
| 185 | $this->attachmentObjectID = $this->user->userID; |
| 186 | |
| 187 | parent::readParameters(); |
| 188 | } |
| 189 | |
| 190 | /** |
| 191 | * @inheritDoc |
| 192 | */ |
| 193 | protected function initOptionHandler() |
| 194 | { |
| 195 | \assert($this->optionHandler instanceof UserOptionHandler); |
| 196 | $this->optionHandler->setUser($this->user->getDecoratedObject()); |
| 197 | } |
| 198 | |
| 199 | /** |
| 200 | * @inheritDoc |
| 201 | */ |
| 202 | public function readFormParameters() |
| 203 | { |
| 204 | parent::readFormParameters(); |
| 205 | |
| 206 | if (!WCF::getSession()->getPermission('admin.user.canEditPassword') || !empty($this->user->authData)) { |
| 207 | $this->password = ''; |
| 208 | } |
| 209 | if (!WCF::getSession()->getPermission('admin.user.canEditMailAddress')) { |
| 210 | $this->email = $this->user->email; |
| 211 | } |
| 212 | |
| 213 | if (!empty($_POST['banned'])) { |
| 214 | $this->banned = 1; |
| 215 | } |
| 216 | if (isset($_POST['banReason'])) { |
| 217 | $this->banReason = StringUtil::trim($_POST['banReason']); |
| 218 | } |
| 219 | if ($this->banned && !isset($_POST['banNeverExpires'])) { |
| 220 | if (isset($_POST['banExpires'])) { |
| 221 | $this->banExpires = @\intval(\strtotime(StringUtil::trim($_POST['banExpires']))); |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | if (isset($_POST['avatarType'])) { |
| 226 | $this->avatarType = $_POST['avatarType']; |
| 227 | } |
| 228 | if (isset($_POST['styleID'])) { |
| 229 | $this->styleID = \intval($_POST['styleID']); |
| 230 | } |
| 231 | if (isset($_POST['colorScheme'])) { |
| 232 | $this->colorScheme = $_POST['colorScheme']; |
| 233 | } |
| 234 | |
| 235 | if (WCF::getSession()->getPermission('admin.user.canDisableAvatar')) { |
| 236 | if (!empty($_POST['disableAvatar'])) { |
| 237 | $this->disableAvatar = 1; |
| 238 | } |
| 239 | if (isset($_POST['disableAvatarReason'])) { |
| 240 | $this->disableAvatarReason = StringUtil::trim($_POST['disableAvatarReason']); |
| 241 | } |
| 242 | if ($this->disableAvatar && !isset($_POST['disableAvatarNeverExpires'])) { |
| 243 | if (isset($_POST['disableAvatarExpires'])) { |
| 244 | $this->disableAvatarExpires = @\intval(@\strtotime(StringUtil::trim($_POST['disableAvatarExpires']))); |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | if (WCF::getSession()->getPermission('admin.user.canDisableCoverPhoto')) { |
| 250 | if (isset($_POST['deleteCoverPhoto'])) { |
| 251 | $this->deleteCoverPhoto = 1; |
| 252 | } |
| 253 | if (!empty($_POST['disableCoverPhoto'])) { |
| 254 | $this->disableCoverPhoto = 1; |
| 255 | } |
| 256 | if (isset($_POST['disableCoverPhotoReason'])) { |
| 257 | $this->disableCoverPhotoReason = StringUtil::trim($_POST['disableCoverPhotoReason']); |
| 258 | } |
| 259 | if ($this->disableCoverPhoto && !isset($_POST['disableCoverPhotoNeverExpires'])) { |
| 260 | if (isset($_POST['disableCoverPhotoExpires'])) { |
| 261 | $this->disableCoverPhotoExpires = @\intval(@\strtotime(StringUtil::trim($_POST['disableCoverPhotoExpires']))); |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | if (WCF::getSession()->getPermission('admin.user.canEditPassword') && isset($_POST['disconnect3rdParty'])) { |
| 267 | $this->disconnect3rdParty = 1; |
| 268 | } |
| 269 | if (WCF::getSession()->getPermission('admin.user.canEditPassword') && isset($_POST['multifactorDisable'])) { |
| 270 | $this->multifactorDisable = 1; |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | /** |
| 275 | * @inheritDoc |
| 276 | */ |
| 277 | public function readData() |
| 278 | { |
| 279 | if (empty($_POST)) { |
| 280 | // get visible languages |
| 281 | $this->readVisibleLanguages(); |
| 282 | |
| 283 | // default values |
| 284 | $this->readDefaultValues(); |
| 285 | } |
| 286 | |
| 287 | $userProfile = UserProfileRuntimeCache::getInstance()->getObject($this->userID); |
| 288 | foreach (StyleHandler::getInstance()->getStyles() as $style) { |
| 289 | if (!$style->isDisabled || $userProfile->getPermission('admin.style.canUseDisabledStyle')) { |
| 290 | $this->availableStyles[$style->styleID] = $style; |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | parent::readData(); |
| 295 | |
| 296 | // get the avatar object |
| 297 | if ($this->avatarType == 'custom' && $this->user->avatarID) { |
| 298 | $this->userAvatar = new UserAvatar($this->user->avatarID); |
| 299 | } |
| 300 | |
| 301 | // get the user cover photo object |
| 302 | if ($this->user->coverPhotoHash) { |
| 303 | // If the editing user lacks the permissions to view the cover photo, the system |
| 304 | // will try to load the default cover photo. However, the default cover photo depends |
| 305 | // on the style, eventually triggering a change to the template group which will |
| 306 | // fail in the admin panel. |
| 307 | if ($userProfile->canSeeCoverPhoto()) { |
| 308 | $this->userCoverPhoto = UserProfileRuntimeCache::getInstance() |
| 309 | ->getObject($this->userID) |
| 310 | ->getCoverPhoto(true); |
| 311 | } |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | * Sets the selected languages. |
| 317 | */ |
| 318 | protected function readVisibleLanguages() |
| 319 | { |
| 320 | $this->visibleLanguages = $this->user->getLanguageIDs(); |
| 321 | } |
| 322 | |
| 323 | /** |
| 324 | * Sets the default values. |
| 325 | */ |
| 326 | protected function readDefaultValues() |
| 327 | { |
| 328 | $this->username = $this->user->username; |
| 329 | $this->email = $this->user->email; |
| 330 | $this->groupIDs = $this->user->getGroupIDs(true); |
| 331 | $this->languageID = $this->user->languageID; |
| 332 | $this->banned = $this->user->banned; |
| 333 | $this->banReason = $this->user->banReason; |
| 334 | $this->banExpires = $this->user->banExpires; |
| 335 | $this->userTitle = $this->user->userTitle; |
| 336 | $this->styleID = $this->user->styleID; |
| 337 | |
| 338 | $this->signature = $this->user->signature; |
| 339 | $this->disableSignature = $this->user->disableSignature; |
| 340 | $this->disableSignatureReason = $this->user->disableSignatureReason; |
| 341 | $this->disableSignatureExpires = $this->user->disableSignatureExpires; |
| 342 | |
| 343 | $this->disableAvatar = $this->user->disableAvatar; |
| 344 | $this->disableAvatarReason = $this->user->disableAvatarReason; |
| 345 | $this->disableAvatarExpires = $this->user->disableAvatarExpires; |
| 346 | |
| 347 | $this->disableCoverPhoto = $this->user->disableCoverPhoto; |
| 348 | $this->disableCoverPhotoReason = $this->user->disableCoverPhotoReason; |
| 349 | $this->disableCoverPhotoExpires = $this->user->disableCoverPhotoExpires; |
| 350 | |
| 351 | if ($this->user->avatarID) { |
| 352 | $this->avatarType = 'custom'; |
| 353 | } |
| 354 | |
| 355 | $this->colorScheme = $this->user->getUserOption('colorScheme'); |
| 356 | } |
| 357 | |
| 358 | /** |
| 359 | * @inheritDoc |
| 360 | */ |
| 361 | public function assignVariables() |
| 362 | { |
| 363 | parent::assignVariables(); |
| 364 | |
| 365 | WCF::getTPL()->assign([ |
| 366 | 'userID' => $this->user->userID, |
| 367 | 'action' => 'edit', |
| 368 | 'url' => '', |
| 369 | 'markedUsers' => 0, |
| 370 | 'user' => $this->user, |
| 371 | 'banned' => $this->banned, |
| 372 | 'banReason' => $this->banReason, |
| 373 | 'avatarType' => $this->avatarType, |
| 374 | 'disableAvatar' => $this->disableAvatar, |
| 375 | 'disableAvatarReason' => $this->disableAvatarReason, |
| 376 | 'disableAvatarExpires' => $this->disableAvatarExpires, |
| 377 | 'userAvatar' => $this->userAvatar, |
| 378 | 'banExpires' => $this->banExpires, |
| 379 | 'userCoverPhoto' => $this->userCoverPhoto, |
| 380 | 'disableCoverPhoto' => $this->disableCoverPhoto, |
| 381 | 'disableCoverPhotoReason' => $this->disableCoverPhotoReason, |
| 382 | 'disableCoverPhotoExpires' => $this->disableCoverPhotoExpires, |
| 383 | 'deleteCoverPhoto' => $this->deleteCoverPhoto, |
| 384 | 'ownerGroupID' => UserGroup::getOwnerGroupID(), |
| 385 | 'availableStyles' => $this->availableStyles, |
| 386 | 'styleID' => $this->styleID, |
| 387 | 'colorScheme' => $this->colorScheme, |
| 388 | ]); |
| 389 | } |
| 390 | |
| 391 | /** |
| 392 | * @inheritDoc |
| 393 | */ |
| 394 | public function save() |
| 395 | { |
| 396 | AbstractForm::save(); |
| 397 | $this->htmlInputProcessor->setObjectID($this->userID); |
| 398 | MessageEmbeddedObjectManager::getInstance()->registerObjects($this->htmlInputProcessor); |
| 399 | |
| 400 | // handle avatar |
| 401 | if ($this->avatarType != 'custom') { |
| 402 | // delete custom avatar |
| 403 | if ($this->user->avatarID) { |
| 404 | $action = new UserAvatarAction([$this->user->avatarID], 'delete'); |
| 405 | $action->executeAction(); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | $avatarData = []; |
| 410 | if ($this->avatarType === 'none') { |
| 411 | $avatarData = [ |
| 412 | 'avatarID' => null, |
| 413 | ]; |
| 414 | } |
| 415 | |
| 416 | $this->additionalFields = \array_merge($this->additionalFields, $avatarData); |
| 417 | |
| 418 | if ($this->disconnect3rdParty) { |
| 419 | $this->additionalFields['authData'] = ''; |
| 420 | } |
| 421 | |
| 422 | // add default groups |
| 423 | $defaultGroups = UserGroup::getAccessibleGroups([UserGroup::GUESTS, UserGroup::EVERYONE, UserGroup::USERS]); |
| 424 | $oldGroupIDs = $this->user->getGroupIDs(true); |
| 425 | foreach ($oldGroupIDs as $oldGroupID) { |
| 426 | if (isset($defaultGroups[$oldGroupID])) { |
| 427 | $this->groupIDs[] = $oldGroupID; |
| 428 | } |
| 429 | } |
| 430 | $this->groupIDs = \array_unique($this->groupIDs); |
| 431 | |
| 432 | // save user |
| 433 | $saveOptions = $this->optionHandler->save(); |
| 434 | |
| 435 | $data = [ |
| 436 | 'data' => \array_merge($this->additionalFields, [ |
| 437 | 'username' => $this->username, |
| 438 | 'email' => $this->email, |
| 439 | 'password' => $this->password, |
| 440 | 'languageID' => $this->languageID, |
| 441 | 'userTitle' => $this->userTitle, |
| 442 | 'signature' => $this->htmlInputProcessor->getHtml(), |
| 443 | 'signatureEnableHtml' => 1, |
| 444 | 'styleID' => $this->styleID, |
| 445 | ]), |
| 446 | 'groups' => $this->groupIDs, |
| 447 | 'languageIDs' => $this->visibleLanguages, |
| 448 | 'options' => $saveOptions, |
| 449 | 'signatureAttachmentHandler' => $this->attachmentHandler, |
| 450 | ]; |
| 451 | // handle changed username |
| 452 | if (\mb_strtolower($this->username) != \mb_strtolower($this->user->username)) { |
| 453 | $data['data']['lastUsernameChange'] = TIME_NOW; |
| 454 | $data['data']['oldUsername'] = $this->user->username; |
| 455 | } |
| 456 | |
| 457 | // handle ban |
| 458 | if (WCF::getSession()->getPermission('admin.user.canBanUser')) { |
| 459 | $data['data']['banned'] = $this->banned; |
| 460 | $data['data']['banReason'] = $this->banReason; |
| 461 | $data['data']['banExpires'] = $this->banExpires; |
| 462 | } |
| 463 | |
| 464 | // handle disabled signature |
| 465 | if (WCF::getSession()->getPermission('admin.user.canDisableSignature')) { |
| 466 | $data['data']['disableSignature'] = $this->disableSignature; |
| 467 | $data['data']['disableSignatureReason'] = $this->disableSignatureReason; |
| 468 | $data['data']['disableSignatureExpires'] = $this->disableSignatureExpires; |
| 469 | } |
| 470 | |
| 471 | // handle disabled avatar |
| 472 | if (WCF::getSession()->getPermission('admin.user.canDisableAvatar')) { |
| 473 | $data['data']['disableAvatar'] = $this->disableAvatar; |
| 474 | $data['data']['disableAvatarReason'] = $this->disableAvatarReason; |
| 475 | $data['data']['disableAvatarExpires'] = $this->disableAvatarExpires; |
| 476 | } |
| 477 | |
| 478 | // handle disabled cover photo |
| 479 | if (WCF::getSession()->getPermission('admin.user.canDisableCoverPhoto')) { |
| 480 | $data['data']['disableCoverPhoto'] = $this->disableCoverPhoto; |
| 481 | $data['data']['disableCoverPhotoReason'] = $this->disableCoverPhotoReason; |
| 482 | $data['data']['disableCoverPhotoExpires'] = $this->disableCoverPhotoExpires; |
| 483 | |
| 484 | if ($this->deleteCoverPhoto) { |
| 485 | UserProfileRuntimeCache::getInstance()->getObject($this->userID)->getCoverPhoto()->delete(); |
| 486 | |
| 487 | $data['data']['coverPhotoHash'] = null; |
| 488 | $data['data']['coverPhotoExtension'] = ''; |
| 489 | |
| 490 | UserProfileRuntimeCache::getInstance()->removeObject($this->userID); |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | $this->objectAction = new UserAction([$this->userID], 'update', $data); |
| 495 | $this->objectAction->executeAction(); |
| 496 | |
| 497 | // disable multifactor authentication |
| 498 | if (WCF::getSession()->getPermission('admin.user.canEditPassword') && $this->multifactorDisable) { |
| 499 | WCF::getDB()->beginTransaction(); |
| 500 | $setups = Setup::getAllForUser($this->user->getDecoratedObject()); |
| 501 | foreach ($setups as $setup) { |
| 502 | $setup->delete(); |
| 503 | } |
| 504 | |
| 505 | $this->user->update([ |
| 506 | 'multifactorActive' => 0, |
| 507 | ]); |
| 508 | WCF::getDB()->commitTransaction(); |
| 509 | } |
| 510 | |
| 511 | if ($this->user->getUserOption('colorScheme') !== $this->colorScheme) { |
| 512 | $command = new SetColorScheme($this->user->getDecoratedObject(), $this->colorScheme); |
| 513 | $command(); |
| 514 | } |
| 515 | |
| 516 | // reload user |
| 517 | $this->user = new UserEditor(new User($this->userID)); |
| 518 | |
| 519 | // update user rank |
| 520 | if (MODULE_USER_RANK) { |
| 521 | $action = new UserProfileAction([$this->user], 'updateUserRank'); |
| 522 | $action->executeAction(); |
| 523 | } |
| 524 | if (MODULE_USERS_ONLINE) { |
| 525 | $action = new UserProfileAction([$this->user], 'updateUserOnlineMarking'); |
| 526 | $action->executeAction(); |
| 527 | } |
| 528 | |
| 529 | // remove assignments |
| 530 | $sql = "DELETE FROM wcf" . WCF_N . "_moderation_queue_to_user |
| 531 | WHERE userID = ?"; |
| 532 | $statement = WCF::getDB()->prepareStatement($sql); |
| 533 | $statement->execute([$this->user->userID]); |
| 534 | |
| 535 | // reset moderation count |
| 536 | ModerationQueueManager::getInstance()->resetModerationCount($this->user->userID); |
| 537 | $this->saved(); |
| 538 | |
| 539 | // reset password |
| 540 | $this->password = ''; |
| 541 | |
| 542 | // reload user |
| 543 | $this->user = new UserEditor(new User($this->userID)); |
| 544 | |
| 545 | // show success message |
| 546 | WCF::getTPL()->assign('success', true); |
| 547 | } |
| 548 | |
| 549 | /** |
| 550 | * @inheritDoc |
| 551 | */ |
| 552 | protected function validateUsername($username) |
| 553 | { |
| 554 | try { |
| 555 | if (\mb_strtolower($this->user->username) != \mb_strtolower($username)) { |
| 556 | parent::validateUsername($username); |
| 557 | } |
| 558 | } catch (UserInputException $e) { |
| 559 | if ($e->getField() === 'username' && $e->getType() === 'notUnique') { |
| 560 | $user2 = User::getUserByUsername($username); |
| 561 | if ($user2->userID != $this->user->userID) { |
| 562 | throw $e; |
| 563 | } |
| 564 | } else { |
| 565 | throw $e; |
| 566 | } |
| 567 | } |
| 568 | } |
| 569 | |
| 570 | #[\Override] |
| 571 | protected function validateEmail(string $email): void |
| 572 | { |
| 573 | if (\mb_strtolower($this->user->email) != \mb_strtolower($email)) { |
| 574 | parent::validateEmail($email); |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | #[\Override] |
| 579 | protected function validatePassword( |
| 580 | #[\SensitiveParameter] |
| 581 | string $password |
| 582 | ): void { |
| 583 | if (!empty($password)) { |
| 584 | parent::validatePassword($password); |
| 585 | } |
| 586 | } |
| 587 | |
| 588 | /** |
| 589 | * Validates the user avatar. |
| 590 | */ |
| 591 | protected function validateAvatar() |
| 592 | { |
| 593 | if ($this->avatarType != 'custom') { |
| 594 | $this->avatarType = 'none'; |
| 595 | } |
| 596 | |
| 597 | try { |
| 598 | switch ($this->avatarType) { |
| 599 | case 'custom': |
| 600 | if (!$this->user->avatarID) { |
| 601 | throw new UserInputException('customAvatar'); |
| 602 | } |
| 603 | break; |
| 604 | } |
| 605 | } catch (UserInputException $e) { |
| 606 | $this->errorType[$e->getField()] = $e->getType(); |
| 607 | } |
| 608 | } |
| 609 | |
| 610 | /** |
| 611 | * @inheritDoc |
| 612 | */ |
| 613 | public function validate() |
| 614 | { |
| 615 | if ($this->user->userID == WCF::getUser()->userID && WCF::getUser()->hasOwnerAccess()) { |
| 616 | $ownerGroupID = UserGroup::getOwnerGroupID(); |
| 617 | if ($ownerGroupID && !\in_array($ownerGroupID, $this->groupIDs)) { |
| 618 | // Members of the owner group cannot remove themselves. |
| 619 | throw new PermissionDeniedException(); |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | $this->validateAvatar(); |
| 624 | |
| 625 | parent::validate(); |
| 626 | |
| 627 | if (!isset($this->availableStyles[$this->styleID])) { |
| 628 | $this->styleID = 0; |
| 629 | } |
| 630 | |
| 631 | if ($this->colorScheme !== 'light' && $this->colorScheme !== 'dark') { |
| 632 | $this->colorScheme = 'system'; |
| 633 | } |
| 634 | } |
| 635 | } |