1<?php 2/** 3 * Elgg user settings functions. 4 * Functions for adding and manipulating options on the user settings panel. 5 */ 6 7use Elgg\Request; 8use Elgg\Http\ResponseBuilder; 9 10/** 11 * Set a user's password 12 * Returns null if no change is required 13 * Returns true or false indicating success or failure if change was needed 14 * 15 * @elgg_plugin_hook usersettings:save user 16 * 17 * @param \Elgg\Hook $hook 'usersettings:save', 'user' 18 * 19 * @return bool|null|void 20 * @since 1.8.0 21 * @internal 22 */ 23function _elgg_set_user_password(\Elgg\Hook $hook) { 24 25 $actor = elgg_get_logged_in_user_entity(); 26 if (!$actor instanceof ElggUser) { 27 return; 28 } 29 30 $user = $hook->getUserParam(); 31 $request = $hook->getParam('request'); 32 33 if (!$user instanceof ElggUser || !$request instanceof Request) { 34 return; 35 } 36 37 $password = $request->getParam('password', null, false); 38 $password2 = $request->getParam('password2', null, false); 39 40 if (!$password) { 41 return null; 42 } 43 44 if (!$actor->isAdmin() || $user->guid === $actor->guid) { 45 // let admin user change anyone's password without knowing it except his own. 46 47 $current_password = $request->getParam('current_password', null, false); 48 49 try { 50 elgg()->accounts->assertCurrentPassword($user, $current_password); 51 } catch (RegistrationException $e) { 52 $request->validation()->fail('password', '', elgg_echo('LoginException:ChangePasswordFailure')); 53 54 return false; 55 } 56 } 57 58 try { 59 elgg()->accounts->assertValidPassword([$password, $password2]); 60 } catch (RegistrationException $e) { 61 $request->validation()->fail('password', '', $e->getMessage()); 62 63 return false; 64 } 65 66 $user->setPassword($password); 67 _elgg_services()->persistentLogin->handlePasswordChange($user, $actor); 68 69 if (elgg_get_config('security_notify_user_password')) { 70 // notify the user that their password has changed 71 $site = elgg_get_site_entity(); 72 73 $subject = elgg_echo('user:notification:password_change:subject', [], $user->language); 74 $body = elgg_echo('user:notification:password_change:body', [ 75 $user->getDisplayName(), 76 $site->getDisplayName(), 77 elgg_generate_url('account:password:reset'), 78 $site->getURL(), 79 ], $user->language); 80 81 $params = [ 82 'object' => $user, 83 'action' => 'password_change', 84 ]; 85 86 notify_user($user->guid, $site->guid, $subject, $body, $params, ['email']); 87 } 88 89 $request->validation()->pass('password', '', elgg_echo('user:password:success')); 90} 91 92/** 93 * Set a user's display name 94 * Returns null if no change is required or input is not present in the form 95 * Returns true or false indicating success or failure if change was needed 96 * 97 * @elgg_plugin_hook usersettings:save user 98 * 99 * @param \Elgg\Hook $hook Hook 100 * 101 * @return bool|null 102 * @since 1.8.0 103 * @internal 104 */ 105function _elgg_set_user_name(\Elgg\Hook $hook) { 106 107 $user = $hook->getUserParam(); 108 $request = $hook->getParam('request'); 109 110 if (!$user instanceof ElggUser || !$request instanceof Request) { 111 return; 112 } 113 114 $name = $request->getParam('name'); 115 if (!isset($name)) { 116 return null; 117 } 118 119 $name = strip_tags($name); 120 if (empty($name)) { 121 $request->validation()->fail('name', $request->getParam('name'), elgg_echo('user:name:fail')); 122 123 return false; 124 } 125 126 if ($name === $user->name) { 127 return null; 128 } 129 130 $user->name = $name; 131 132 $request->validation()->pass('name', $name, elgg_echo('user:name:success')); 133} 134 135/** 136 * Set a user's username 137 * Returns null if no change is required or input is not present in the form 138 * Returns true or false indicating success or failure if change was needed 139 * 140 * @elgg_plugin_hook usersettings:save user 141 * 142 * @param \Elgg\Hook $hook Hook 143 * 144 * @return bool|null 145 * 146 * @since 3.0 147 * @internal 148 */ 149function _elgg_set_user_username(\Elgg\Hook $hook) { 150 151 $user = $hook->getUserParam(); 152 $request = $hook->getParam('request'); 153 154 if (!$user instanceof ElggUser || !$request instanceof Request) { 155 return null; 156 } 157 158 $username = $request->getParam('username'); 159 if (!isset($username)) { 160 return null; 161 } 162 163 if (!elgg_is_admin_logged_in() && !elgg_get_config('can_change_username', false)) { 164 return null; 165 } 166 167 if (!$user->canEdit()) { 168 return null; 169 } 170 171 if ($user->username === $username) { 172 return null; 173 } 174 175 // check if username is valid and does not exist 176 try { 177 elgg()->accounts->assertValidUsername($username, true); 178 } catch (RegistrationException $ex) { 179 $request->validation()->fail('username', $username, $ex->getMessage()); 180 181 return false; 182 } 183 184 $user->username = $username; 185 186 $request->validation()->pass('username', $username, elgg_echo('user:username:success')); 187 188 // correctly forward after after a username change 189 elgg_register_plugin_hook_handler('response', 'action:usersettings/save', function (\Elgg\Hook $hook) use ($username) { 190 $response = $hook->getValue(); 191 if (!$response instanceof ResponseBuilder) { 192 return; 193 } 194 195 if ($response->getForwardURL() === REFERRER) { 196 $response->setForwardURL(elgg_generate_url('settings:account', [ 197 'username' => $username, 198 ])); 199 } 200 201 return $response; 202 }); 203} 204 205/** 206 * Set a user's language 207 * Returns null if no change is required or input is not present in the form 208 * Returns true or false indicating success or failure if change was needed 209 * 210 * @elgg_plugin_hook usersettings:save user 211 * 212 * @param \Elgg\Hook $hook Hook 213 * 214 * @return bool|null 215 * @since 1.8.0 216 * @internal 217 */ 218function _elgg_set_user_language(\Elgg\Hook $hook) { 219 220 $user = $hook->getUserParam(); 221 $request = $hook->getParam('request'); 222 223 if (!$user instanceof ElggUser || !$request instanceof Request) { 224 return null; 225 } 226 227 $language = $request->getParam('language'); 228 if (!isset($language)) { 229 return null; 230 } 231 232 if ($language === $user->language) { 233 return null; 234 } 235 236 if (!in_array($language, elgg()->translator->getAllowedLanguages())) { 237 return null; 238 } 239 240 $user->language = $language; 241 242 $request->validation()->pass('language', $language, elgg_echo('user:language:success')); 243} 244 245/** 246 * Set a user's email address 247 * Returns null if no change is required or input is not present in the form 248 * Returns true or false indicating success or failure if change was needed 249 * 250 * @elgg_plugin_hook usersettings:save user 251 * 252 * @param \Elgg\Hook $hook Hook 253 * 254 * @return bool|null 255 * @since 1.8.0 256 * @internal 257 */ 258function _elgg_set_user_email(\Elgg\Hook $hook) { 259 260 $actor = elgg_get_logged_in_user_entity(); 261 if (!$actor instanceof ElggUser) { 262 return null; 263 } 264 265 $user = $hook->getUserParam(); 266 $request = $hook->getParam('request'); 267 268 if (!$user instanceof ElggUser || !$request instanceof Request) { 269 return null; 270 } 271 272 $email = $request->getParam('email'); 273 if (!isset($email)) { 274 return null; 275 } 276 277 if (strcmp($email, $user->email) === 0) { 278 // no change 279 return null; 280 } 281 282 try { 283 elgg()->accounts->assertValidEmail($email, true); 284 } catch (RegistrationException $ex) { 285 $request->validation()->fail('email', $email, $ex->getMessage()); 286 287 return false; 288 } 289 290 if (elgg()->config->security_email_require_password && $user->guid === $actor->guid) { 291 try { 292 // validate password 293 elgg()->accounts->assertCurrentPassword($user, $request->getParam('email_password')); 294 } catch (RegistrationException $e) { 295 $request->validation()->fail('email', $email, elgg_echo('email:save:fail:password')); 296 return false; 297 } 298 } 299 300 $hook_params = $hook->getParams(); 301 $hook_params['email'] = $email; 302 303 if (!elgg_trigger_plugin_hook('change:email', 'user', $hook_params, true)) { 304 return null; 305 } 306 307 if (elgg()->config->security_email_require_confirmation) { 308 // validate the new email address 309 try { 310 elgg()->accounts->requestNewEmailValidation($user, $email); 311 312 $request->validation()->pass('email', $email, elgg_echo('account:email:request:success', [$email])); 313 return true; 314 } catch (InvalidParameterException $e) { 315 $request->validation()->fail('email', $email, elgg_echo('email:save:fail:password')); 316 return false; 317 } 318 } 319 320 $user->email = $email; 321 $request->validation()->pass('email', $email, elgg_echo('email:save:success')); 322} 323 324/** 325 * Set a user's default access level 326 * Returns null if no change is required or input is not present in the form 327 * Returns true or false indicating success or failure if change was needed 328 * 329 * @elgg_plugin_hook usersettings:save user 330 * 331 * @param \Elgg\Hook $hook Hook 332 * 333 * @return bool|null 334 * @since 1.8.0 335 * @internal 336 * @throws DatabaseException 337 */ 338function _elgg_set_user_default_access(\Elgg\Hook $hook) { 339 340 if (!elgg()->config->allow_user_default_access) { 341 return null; 342 } 343 344 $user = $hook->getUserParam(); 345 $request = $hook->getParam('request'); 346 347 if (!$user instanceof ElggUser || !$request instanceof Request) { 348 return null; 349 } 350 351 $default_access = $request->getParam('default_access'); 352 if (!isset($default_access)) { 353 return null; 354 } 355 356 if ($user->setPrivateSetting('elgg_default_access', $default_access)) { 357 $request->validation()->pass('default_access', $default_access, elgg_echo('user:default_access:success')); 358 } else { 359 $request->validation()->fail('default_access', $default_access, elgg_echo(elgg_echo('user:default_access:failure'))); 360 } 361} 362 363/** 364 * Register menu items for the user settings page menu 365 * 366 * @param \Elgg\Hook $hook 'register', 'menu:page' 367 * 368 * @return void|ElggMenuItem[] 369 * 370 * @internal 371 * @since 3.0 372 */ 373function _elgg_user_settings_menu_register(\Elgg\Hook $hook) { 374 $user = elgg_get_page_owner_entity(); 375 if (!$user) { 376 return; 377 } 378 379 if (!elgg_in_context('settings')) { 380 return; 381 } 382 383 $return = $hook->getValue(); 384 385 $return[] = \ElggMenuItem::factory([ 386 'name' => '1_account', 387 'text' => elgg_echo('usersettings:user:opt:linktext'), 388 'href' => "settings/user/{$user->username}", 389 'section' => 'configure', 390 ]); 391 392 $return[] = \ElggMenuItem::factory([ 393 'name' => '1_plugins', 394 'text' => elgg_echo('usersettings:plugins:opt:linktext'), 395 'href' => '#', 396 'section' => 'configure', 397 ]); 398 399 $return[] = \ElggMenuItem::factory([ 400 'name' => '1_statistics', 401 'text' => elgg_echo('usersettings:statistics:opt:linktext'), 402 'href' => "settings/statistics/{$user->username}", 403 'section' => 'configure', 404 ]); 405 406 // register plugin user settings menu items 407 $active_plugins = elgg_get_plugins(); 408 409 foreach ($active_plugins as $plugin) { 410 $plugin_id = $plugin->getID(); 411 if (!elgg_view_exists("usersettings/$plugin_id/edit") && !elgg_view_exists("plugins/$plugin_id/usersettings")) { 412 continue; 413 } 414 415 if (elgg_language_key_exists($plugin_id . ':usersettings:title')) { 416 $title = elgg_echo($plugin_id . ':usersettings:title'); 417 } else { 418 $title = $plugin->getDisplayName(); 419 } 420 421 $return[] = \ElggMenuItem::factory([ 422 'name' => $plugin_id, 423 'text' => $title, 424 'href' => elgg_generate_url('settings:tools', [ 425 'username' => $user->username, 426 'plugin_id' => $plugin_id, 427 ]), 428 'parent_name' => '1_plugins', 429 'section' => 'configure', 430 ]); 431 } 432 433 return $return; 434} 435 436/** 437 * Prepares the page menu to strip out empty plugins menu item for user settings 438 * 439 * @param \Elgg\Hook $hook 'prepare', 'menu:page' 440 * 441 * @return void|array 442 * @internal 443 */ 444function _elgg_user_settings_menu_prepare(\Elgg\Hook $hook) { 445 $value = $hook->getValue(); 446 if (empty($value)) { 447 return; 448 } 449 450 if (!elgg_in_context("settings")) { 451 return; 452 } 453 454 $configure = elgg_extract("configure", $value); 455 if (empty($configure)) { 456 return; 457 } 458 459 foreach ($configure as $index => $menu_item) { 460 if (!($menu_item instanceof ElggMenuItem)) { 461 continue; 462 } 463 464 if ($menu_item->getName() == "1_plugins") { 465 if (!$menu_item->getChildren()) { 466 // no need for this menu item if it has no children 467 unset($value["configure"][$index]); 468 } 469 } 470 } 471 472 return $value; 473} 474 475/** 476 * Initialize the user settings library 477 * 478 * @return void 479 * @internal 480 */ 481function _elgg_user_settings_init() { 482 483 elgg_register_plugin_hook_handler('register', 'menu:page', '_elgg_user_settings_menu_register'); 484 elgg_register_plugin_hook_handler('prepare', 'menu:page', '_elgg_user_settings_menu_prepare'); 485 486 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_language'); 487 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_password'); // this needs to be before email change, for security reasons 488 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_default_access'); 489 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_name'); 490 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_username'); 491 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_set_user_email'); 492 493 // extend the account settings form 494 elgg_extend_view('forms/usersettings/save', 'core/settings/account/username', 100); 495 elgg_extend_view('forms/usersettings/save', 'core/settings/account/name', 100); 496 elgg_extend_view('forms/usersettings/save', 'core/settings/account/password', 100); 497 elgg_extend_view('forms/usersettings/save', 'core/settings/account/email', 100); 498 elgg_extend_view('forms/usersettings/save', 'core/settings/account/language', 100); 499 elgg_extend_view('forms/usersettings/save', 'core/settings/account/default_access', 100); 500} 501 502/** 503 * @see \Elgg\Application::loadCore Do not do work here. Just register for events. 504 */ 505return function (\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) { 506 $events->registerHandler('init', 'system', '_elgg_user_settings_init'); 507}; 508