1<?php 2/** 3 * Elgg admin functions. 4 * 5 * Admin pages 6 * Plugins no not need to provide their own page handler to add a page to the 7 * admin area. A view placed at admin/<section>/<subsection> can be access 8 * at http://example.org/admin/<section>/<subsection>. The title of the page 9 * will be elgg_echo('admin:<section>:<subsection>'). For an example of how to 10 * add a page to the admin area, see the diagnostics plugin. 11 * 12 * Admin notices 13 * System messages (success and error messages) are used in both the main site 14 * and the admin area. There is a special presistent message for the admin area 15 * called an admin notice. It should be used when a plugin requires an 16 * administrator to take an action. @see elgg_add_admin_notice() 17 */ 18 19use Elgg\Menu\MenuItems; 20use Elgg\Database\QueryBuilder; 21use Elgg\Http\ResponseBuilder; 22 23/** 24 * Get the admin users 25 * 26 * @param array $options Options array, @see elgg_get_entities() for parameters 27 * 28 * @return mixed Array of admin users or false on failure. If a count, returns int. 29 * @since 1.8.0 30 */ 31function elgg_get_admins(array $options = []) { 32 $options['type'] = 'user'; 33 $options['metadata_name_value_pairs'] = elgg_extract('metadata_name_value_pairs', $options, []); 34 35 $options['metadata_name_value_pairs']['admin'] = 'yes'; 36 37 return elgg_get_entities($options); 38} 39 40/** 41 * Write a persistent message to the admin view. 42 * Useful to alert the admin to take a certain action. 43 * The id is a unique ID that can be cleared once the admin 44 * completes the action. 45 * 46 * eg: add_admin_notice('twitter_services_no_api', 47 * 'Before your users can use Twitter services on this site, you must set up 48 * the Twitter API key in the <a href="link">Twitter Services Settings</a>'); 49 * 50 * @param string $id A unique ID that your plugin can remember 51 * @param string $message Body of the message 52 * 53 * @return ElggAdminNotice|bool 54 * @since 1.8.0 55 */ 56function elgg_add_admin_notice($id, $message) { 57 return _elgg_services()->adminNotices->add($id, $message); 58} 59 60/** 61 * Remove an admin notice by ID. 62 * 63 * @param string $id The unique ID assigned in add_admin_notice() 64 * 65 * @return bool 66 * @since 1.8.0 67 */ 68function elgg_delete_admin_notice($id) { 69 return _elgg_services()->adminNotices->delete($id); 70} 71 72/** 73 * Get admin notices. An admin must be logged in since the notices are private. 74 * 75 * @param array $options Query options 76 * 77 * @return \ElggObject[]|int|mixed Admin notices 78 * @since 1.8.0 79 */ 80function elgg_get_admin_notices(array $options = []) { 81 return _elgg_services()->adminNotices->find($options); 82} 83 84/** 85 * Check if an admin notice is currently active. (Ignores access) 86 * 87 * @param string $id The unique ID used to register the notice. 88 * 89 * @return bool 90 * @since 1.8.0 91 */ 92function elgg_admin_notice_exists($id) { 93 return _elgg_services()->adminNotices->exists($id); 94} 95 96/** 97 * Add an admin notice when a new \ElggUpgrade object is created. 98 * 99 * @param \Elgg\Event $event 'create', 'object' 100 * 101 * @return void 102 * 103 * @internal 104 */ 105function _elgg_create_notice_of_pending_upgrade(\Elgg\Event $event) { 106 if (!$event->getObject() instanceof \ElggUpgrade) { 107 return; 108 } 109 110 // Link to the Upgrades section 111 $link = elgg_view('output/url', [ 112 'href' => 'admin/upgrades', 113 'text' => elgg_echo('admin:view_upgrades'), 114 ]); 115 116 $message = elgg_echo('admin:pending_upgrades'); 117 118 elgg_add_admin_notice('pending_upgrades', "$message $link"); 119} 120 121/** 122 * Initialize the admin backend. 123 * @return void 124 * @internal 125 */ 126function _elgg_admin_init() { 127 128 elgg_register_external_file('css', 'elgg.admin', elgg_get_simplecache_url('admin.css')); 129 elgg_register_external_file('css', 'admin/users/unvalidated', elgg_get_simplecache_url('admin/users/unvalidated.css')); 130 131 elgg_define_js('admin/users/unvalidated', [ 132 'src' => elgg_get_simplecache_url('admin/users/unvalidated.js'), 133 ]); 134 135 elgg_extend_view('admin.css', 'lightbox/elgg-colorbox-theme/colorbox.css'); 136 137 elgg_register_ajax_view('forms/admin/user/change_email'); 138 139 elgg_register_plugin_hook_handler('register', 'menu:admin_header', '_elgg_admin_header_menu'); 140 elgg_register_plugin_hook_handler('register', 'menu:admin_footer', '_elgg_admin_footer_menu'); 141 elgg_register_plugin_hook_handler('register', 'menu:filter:admin/upgrades', '_elgg_admin_upgrades_menu'); 142 elgg_register_plugin_hook_handler('register', 'menu:page', '_elgg_admin_page_menu'); 143 elgg_register_plugin_hook_handler('register', 'menu:page', '_elgg_admin_page_menu_plugin_settings'); 144 elgg_register_plugin_hook_handler('register', 'menu:user:unvalidated:bulk', '_elgg_admin_user_unvalidated_bulk_menu'); 145 146 // maintenance mode 147 if (elgg_get_config('elgg_maintenance_mode', null)) { 148 elgg_register_plugin_hook_handler('route', 'all', '_elgg_admin_maintenance_handler', 600); 149 elgg_register_plugin_hook_handler('action', 'all', '_elgg_admin_maintenance_action_check', 600); 150 elgg_register_external_file('css', 'maintenance', elgg_get_simplecache_url('maintenance.css')); 151 152 elgg_register_menu_item('topbar', [ 153 'name' => 'maintenance_mode', 154 'href' => 'admin/configure_utilities/maintenance', 155 'text' => elgg_echo('admin:maintenance_mode:indicator_menu_item'), 156 'icon' => 'wrench', 157 'priority' => 900, 158 ]); 159 } 160 161 elgg_register_simplecache_view('admin.css'); 162 163 // widgets 164 $widgets = ['online_users', 'new_users', 'content_stats', 'banned_users', 'admin_welcome', 'control_panel', 'cron_status']; 165 foreach ($widgets as $widget) { 166 elgg_register_widget_type( 167 $widget, 168 elgg_echo("admin:widget:$widget"), 169 elgg_echo("admin:widget:$widget:help"), 170 ['admin'] 171 ); 172 } 173 174 // automatic adding of widgets for admin 175 elgg_register_event_handler('make_admin', 'user', '_elgg_add_admin_widgets'); 176 177 elgg_register_notification_event('user', 'user', ['make_admin', 'remove_admin']); 178 elgg_register_plugin_hook_handler('get', 'subscriptions', '_elgg_admin_get_admin_subscribers_admin_action'); 179 elgg_register_plugin_hook_handler('get', 'subscriptions', '_elgg_admin_get_user_subscriber_admin_action'); 180 elgg_register_plugin_hook_handler('prepare', 'notification:make_admin:user:user', '_elgg_admin_prepare_admin_notification_make_admin'); 181 elgg_register_plugin_hook_handler('prepare', 'notification:make_admin:user:user', '_elgg_admin_prepare_user_notification_make_admin'); 182 elgg_register_plugin_hook_handler('prepare', 'notification:remove_admin:user:user', '_elgg_admin_prepare_admin_notification_remove_admin'); 183 elgg_register_plugin_hook_handler('prepare', 'notification:remove_admin:user:user', '_elgg_admin_prepare_user_notification_remove_admin'); 184 185 // new users require admin validation 186 elgg_register_event_handler('login:before', 'user', '_elgg_admin_user_validation_login_attempt', 999); // allow others to throw exceptions earlier 187 elgg_register_event_handler('validate:after', 'user', '_elgg_admin_user_validation_notification'); 188 elgg_register_plugin_hook_handler('cron', 'daily', '_elgg_admin_notify_admins_pending_user_validation'); 189 elgg_register_plugin_hook_handler('cron', 'weekly', '_elgg_admin_notify_admins_pending_user_validation'); 190 elgg_register_plugin_hook_handler('register', 'user', '_elgg_admin_check_admin_validation', 999); // allow others to also disable the user 191 elgg_register_plugin_hook_handler('response', 'action:register', '_elgg_admin_set_registration_forward_url', 999); // allow other to set forwar url first 192 elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_admin_save_notification_setting'); 193 194 // Add notice about pending upgrades 195 elgg_register_event_handler('create', 'object', '_elgg_create_notice_of_pending_upgrade'); 196} 197 198/** 199 * Returns plugin listing and admin menu to the client (used after plugin (de)activation) 200 * 201 * @internal 202 * @return Elgg\Http\OkResponse 203 */ 204function _elgg_ajax_plugins_update() { 205 elgg_admin_gatekeeper(); 206 elgg_set_context('admin'); 207 208 return elgg_ok_response([ 209 'list' => elgg_view('admin/plugins', ['list_only' => true]), 210 'sidebar' => elgg_view('admin/sidebar'), 211 ]); 212} 213 214/** 215 * Register menu items for the admin_header menu 216 * 217 * @param \Elgg\Hook $hook 'register', 'menu:admin_header' 218 * 219 * @return void|MenuItems 220 * 221 * @internal 222 * @since 3.0 223 */ 224function _elgg_admin_header_menu(\Elgg\Hook $hook) { 225 if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { 226 return; 227 } 228 229 $return = $hook->getValue(); 230 231 $admin = elgg_get_logged_in_user_entity(); 232 233 $return[] = \ElggMenuItem::factory([ 234 'name' => 'account', 235 'text' => $admin->getDisplayName(), 236 'href' => $admin->getURL(), 237 'icon' => elgg_view('output/img', [ 238 'src' => $admin->getIconURL('small'), 239 'alt' => $admin->getDisplayName(), 240 ]), 241 'link_class' => 'elgg-avatar-small', 242 'priority' => 1000, 243 ]); 244 245 $return[] = \ElggMenuItem::factory([ 246 'name' => 'admin_logout', 247 'href' => 'action/logout', 248 'text' => elgg_echo('logout'), 249 'priority' => 900, 250 ]); 251 252 $return[] = \ElggMenuItem::factory([ 253 'name' => 'view_site', 254 'href' => elgg_get_site_url(), 255 'text' => elgg_echo('admin:view_site'), 256 'priority' => 800, 257 ]); 258 259 if (elgg_get_config('elgg_maintenance_mode')) { 260 $return[] = \ElggMenuItem::factory([ 261 'name' => 'maintenance', 262 'href' => 'admin/configure_utilities/maintenance', 263 'text' => elgg_echo('admin:configure_utilities:maintenance'), 264 'link_class' => 'elgg-maintenance-mode-warning', 265 'priority' => 700, 266 ]); 267 } 268 269 return $return; 270} 271 272/** 273 * Register menu items for the admin_footer menu 274 * 275 * @param \Elgg\Hook $hook 'register', 'menu:admin_footer' 276 * 277 * @return void|\ElggMenuItem[] 278 * 279 * @internal 280 * @since 3.0 281 */ 282function _elgg_admin_footer_menu(\Elgg\Hook $hook) { 283 if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { 284 return; 285 } 286 287 $return = $hook->getValue(); 288 289 $return[] = \ElggMenuItem::factory([ 290 'name' => 'faq', 291 'text' => elgg_echo('admin:footer:faq'), 292 'href' => 'http://learn.elgg.org/en/stable/appendix/faqs.html', 293 ]); 294 295 $return[] = \ElggMenuItem::factory([ 296 'name' => 'manual', 297 'text' => elgg_echo('admin:footer:manual'), 298 'href' => 'http://learn.elgg.org/en/stable/admin/index.html', 299 ]); 300 301 $return[] = \ElggMenuItem::factory([ 302 'name' => 'community_forums', 303 'text' => elgg_echo('admin:footer:community_forums'), 304 'href' => 'http://elgg.org/groups/all/', 305 ]); 306 307 $return[] = \ElggMenuItem::factory([ 308 'name' => 'blog', 309 'text' => elgg_echo('admin:footer:blog'), 310 'href' => 'https://elgg.org/blog/all', 311 ]); 312 313 return $return; 314} 315 316/** 317 * Register menu items for the page menu 318 * 319 * @param \Elgg\Hook $hook 'register' 'menu:page' 320 * @return array 321 * 322 * @internal 323 * @see _elgg_default_widgets_init() for default widgets menu items setup 324 * @since 3.0 325 */ 326function _elgg_admin_page_menu(\Elgg\Hook $hook) { 327 if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { 328 return; 329 } 330 331 $return = $hook->getValue(); 332 333 // administer 334 $return[] = \ElggMenuItem::factory([ 335 'name' => 'dashboard', 336 'href' => 'admin', 337 'text' => elgg_echo('admin:dashboard'), 338 'priority' => 10, 339 'section' => 'administer', 340 ]); 341 342 $return[] = \ElggMenuItem::factory([ 343 'name' => 'plugins', 344 'href' => 'admin/plugins', 345 'text' => elgg_echo('admin:plugins'), 346 'priority' => 30, 347 'section' => 'administer', 348 ]); 349 350 $return[] = \ElggMenuItem::factory([ 351 'name' => 'users', 352 'text' => elgg_echo('admin:users'), 353 'priority' => 40, 354 'section' => 'administer', 355 ]); 356 $return[] = \ElggMenuItem::factory([ 357 'name' => 'users:online', 358 'text' => elgg_echo('admin:users:online'), 359 'href' => 'admin/users/online', 360 'priority' => 10, 361 'section' => 'administer', 362 'parent_name' => 'users', 363 ]); 364 $return[] = \ElggMenuItem::factory([ 365 'name' => 'users:admins', 366 'text' => elgg_echo('admin:users:admins'), 367 'href' => 'admin/users/admins', 368 'priority' => 20, 369 'section' => 'administer', 370 'parent_name' => 'users', 371 ]); 372 $return[] = \ElggMenuItem::factory([ 373 'name' => 'users:newest', 374 'text' => elgg_echo('admin:users:newest'), 375 'href' => 'admin/users/newest', 376 'priority' => 30, 377 'section' => 'administer', 378 'parent_name' => 'users', 379 ]); 380 $return[] = \ElggMenuItem::factory([ 381 'name' => 'users:add', 382 'text' => elgg_echo('admin:users:add'), 383 'href' => 'admin/users/add', 384 'priority' => 40, 385 'section' => 'administer', 386 'parent_name' => 'users', 387 ]); 388 389 $return[] = \ElggMenuItem::factory([ 390 'name' => 'users:unvalidated', 391 'text' => elgg_echo('admin:users:unvalidated'), 392 'href' => 'admin/users/unvalidated', 393 'priority' => 50, 394 'section' => 'administer', 395 'parent_name' => 'users', 396 ]); 397 $return[] = \ElggMenuItem::factory([ 398 'name' => 'upgrades', 399 'href' => 'admin/upgrades', 400 'text' => elgg_echo('admin:upgrades'), 401 'priority' => 600, 402 'section' => 'administer', 403 ]); 404 405 $return[] = \ElggMenuItem::factory([ 406 'name' => 'administer_utilities', 407 'text' => elgg_echo('admin:administer_utilities'), 408 'priority' => 50, 409 'section' => 'administer', 410 ]); 411 412 // configure 413 $return[] = \ElggMenuItem::factory([ 414 'name' => 'settings:basic', 415 'href' => 'admin/site_settings', 416 'text' => elgg_echo('admin:site_settings'), 417 'priority' => 10, 418 'section' => 'configure', 419 ]); 420 $return[] = \ElggMenuItem::factory([ 421 'name' => 'security', 422 'href' => 'admin/security', 423 'text' => elgg_echo('admin:security'), 424 'priority' => 30, 425 'section' => 'configure', 426 ]); 427 428 $return[] = \ElggMenuItem::factory([ 429 'name' => 'configure_utilities', 430 'text' => elgg_echo('admin:configure_utilities'), 431 'priority' => 600, 432 'section' => 'configure', 433 ]); 434 $return[] = \ElggMenuItem::factory([ 435 'name' => 'configure_utilities:maintenance', 436 'text' => elgg_echo('admin:configure_utilities:maintenance'), 437 'href' => 'admin/configure_utilities/maintenance', 438 'section' => 'configure', 439 'parent_name' => 'configure_utilities', 440 ]); 441 $return[] = \ElggMenuItem::factory([ 442 'name' => 'configure_utilities:menu_items', 443 'text' => elgg_echo('admin:configure_utilities:menu_items'), 444 'href' => 'admin/configure_utilities/menu_items', 445 'section' => 'configure', 446 'parent_name' => 'configure_utilities', 447 ]); 448 $return[] = \ElggMenuItem::factory([ 449 'name' => 'configure_utilities:robots', 450 'text' => elgg_echo('admin:configure_utilities:robots'), 451 'href' => 'admin/configure_utilities/robots', 452 'section' => 'configure', 453 'parent_name' => 'configure_utilities', 454 ]); 455 456 // information 457 $return[] = \ElggMenuItem::factory([ 458 'name' => 'information:performance', 459 'href' => 'admin/performance', 460 'text' => elgg_echo('admin:performance'), 461 'section' => 'information', 462 'priority' => 70, 463 ]); 464 $return[] = \ElggMenuItem::factory([ 465 'name' => 'information:security', 466 'href' => 'admin/security/information', 467 'text' => elgg_echo('admin:security'), 468 'section' => 'information', 469 'priority' => 60, 470 ]); 471 $return[] = \ElggMenuItem::factory([ 472 'name' => 'statistics', 473 'href' => 'admin/statistics', 474 'text' => elgg_echo('admin:statistics'), 475 'section' => 'information', 476 'priority' => 80, 477 ]); 478 $return[] = \ElggMenuItem::factory([ 479 'name' => 'server', 480 'href' => 'admin/server', 481 'text' => elgg_echo('admin:server'), 482 'section' => 'information', 483 'priority' => 50, 484 ]); 485 486 return $return; 487} 488 489/** 490 * Register plugin settings menu items for the admin page menu 491 * 492 * @note Plugin settings are alphabetically sorted in the submenu 493 * 494 * @param \Elgg\Hook $hook 'register' 'menu:page' 495 * @return array 496 * 497 * @internal 498 * @since 3.0 499 */ 500function _elgg_admin_page_menu_plugin_settings(\Elgg\Hook $hook) { 501 if (!elgg_in_context('admin') || !elgg_is_admin_logged_in()) { 502 return; 503 } 504 505 // plugin settings 506 $active_plugins = elgg_get_plugins('active'); 507 if (empty($active_plugins)) { 508 // nothing added because no items 509 return; 510 } 511 512 $plugins_with_settings = []; 513 514 foreach ($active_plugins as $plugin) { 515 $plugin_id = $plugin->getID(); 516 517 if (!elgg_view_exists("plugins/{$plugin_id}/settings") ) { 518 continue; 519 } 520 $plugin_name = $plugin->getDisplayName(); 521 $plugins_with_settings[$plugin_name] = [ 522 'name' => $plugin_id, 523 'href' => "admin/plugin_settings/$plugin_id", 524 'text' => $plugin_name, 525 'parent_name' => 'plugin_settings', 526 'section' => 'configure', 527 ]; 528 } 529 530 if (empty($plugins_with_settings)) { 531 return; 532 } 533 534 $return = $hook->getValue(); 535 536 $return[] = \ElggMenuItem::factory([ 537 'name' => 'plugin_settings', 538 'text' => elgg_echo('admin:plugin_settings'), 539 'section' => 'configure', 540 ]); 541 542 ksort($plugins_with_settings); 543 $priority = 0; 544 foreach ($plugins_with_settings as $plugin_item) { 545 $priority += 10; 546 $plugin_item['priority'] = $priority; 547 $return[] = \ElggMenuItem::factory($plugin_item); 548 } 549 550 return $return; 551} 552 553/** 554 * Register menu items to the bulk actions for unvalidated users 555 * 556 * @elgg_plugin_hook register menu:user:unvalidated:bulk 557 * 558 * @param \Elgg\Hook $hook 'register' 'menu:user:unvalidated:bulk' 559 * 560 * @return void|ElggMenuItem[] 561 * 562 * @since 3.0 563 * @internal 564 */ 565function _elgg_admin_user_unvalidated_bulk_menu(\Elgg\Hook $hook) { 566 567 if (!elgg_is_admin_logged_in()) { 568 return; 569 } 570 571 $return = $hook->getValue(); 572 573 $return[] = ElggMenuItem::factory([ 574 'name' => 'select_all', 575 'text' => elgg_view('input/checkbox', [ 576 'name' => 'select_all', 577 'label' => elgg_echo('all'), 578 'id' => 'admin-users-unvalidated-bulk-select', 579 ]), 580 'href' => false, 581 'priority' => 100, 582 'deps' => 'admin/users/unvalidated', 583 ]); 584 585 $return[] = ElggMenuItem::factory([ 586 'id' => 'admin-users-unvalidated-bulk-validate', 587 'name' => 'bulk_validate', 588 'text' => elgg_echo('validate'), 589 'href' => 'action/admin/user/bulk/validate', 590 'confirm' => true, 591 'priority' => 400, 592 'section' => 'right', 593 'deps' => 'admin/users/unvalidated', 594 ]); 595 596 $return[] = ElggMenuItem::factory([ 597 'id' => 'admin-users-unvalidated-bulk-delete', 598 'name' => 'bulk_delete', 599 'text' => elgg_echo('delete'), 600 'href' => 'action/admin/user/bulk/delete', 601 'confirm' => elgg_echo('deleteconfirm:plural'), 602 'priority' => 500, 603 'section' => 'right', 604 'deps' => 'admin/users/unvalidated', 605 ]); 606 607 return $return; 608} 609 610/** 611 * Handle admin pages. Expects corresponding views as admin/section/subsection 612 * 613 * @param array $page Array of pages 614 * 615 * @return bool 616 * @internal 617 */ 618function _elgg_admin_page_handler($page) { 619 elgg_admin_gatekeeper(); 620 elgg_set_context('admin'); 621 622 elgg_unregister_external_file('css', 'elgg'); 623 elgg_require_js('elgg/admin'); 624 625 // default to dashboard 626 if (!isset($page[0]) || empty($page[0])) { 627 $page = ['dashboard']; 628 } 629 630 // was going to fix this in the page_handler() function but 631 // it's commented to explicitly return a string if there's a trailing / 632 if (empty($page[count($page) - 1])) { 633 array_pop($page); 634 } 635 636 $vars = ['page' => $page]; 637 638 // special page for plugin settings since we create the form for them 639 if ($page[0] == 'plugin_settings') { 640 if (isset($page[1]) && (elgg_view_exists("plugins/{$page[1]}/settings"))) { 641 $view = 'admin/plugin_settings'; 642 $plugin = elgg_get_plugin_from_id($page[1]); 643 $vars['plugin'] = $plugin; // required for plugin settings backward compatibility 644 $vars['entity'] = $plugin; 645 646 $title = elgg_echo("admin:{$page[0]}") . ': ' . $plugin->getDisplayName(); 647 } else { 648 throw new \Elgg\PageNotFoundException(); 649 } 650 } else { 651 $view = 'admin/' . implode('/', $page); 652 $title = elgg_echo("admin:{$page[0]}"); 653 if (count($page) > 1) { 654 $title .= ' : ' . elgg_echo('admin:' . implode(':', $page)); 655 } 656 } 657 658 // gets content and prevents direct access to 'components' views 659 if ($page[0] == 'components' || !($content = elgg_view($view, $vars))) { 660 throw new \Elgg\PageNotFoundException(); 661 } 662 663 $body = elgg_view_layout('admin', ['content' => $content, 'title' => $title]); 664 echo elgg_view_page($title, $body, 'admin'); 665 return true; 666} 667 668/** 669 * When in maintenance mode, should the given URL be handled normally? 670 * 671 * @param string $current_url Current page URL 672 * @return bool 673 * 674 * @internal 675 */ 676function _elgg_admin_maintenance_allow_url($current_url) { 677 $site_path = preg_replace('~^https?~', '', elgg_get_site_url()); 678 $current_path = preg_replace('~^https?~', '', $current_url); 679 if (0 === elgg_strpos($current_path, $site_path)) { 680 $current_path = ($current_path === $site_path) ? '' : elgg_substr($current_path, elgg_strlen($site_path)); 681 } else { 682 $current_path = false; 683 } 684 685 // allow plugins to control access for specific URLs/paths 686 $params = [ 687 'current_path' => $current_path, 688 'current_url' => $current_url, 689 ]; 690 return (bool) elgg_trigger_plugin_hook('maintenance:allow', 'url', $params, false); 691} 692 693/** 694 * Handle requests when in maintenance mode 695 * 696 * @param \Elgg\Hook $hook 'route', 'all' 697 * 698 * @return void|false 699 * 700 * @internal 701 */ 702function _elgg_admin_maintenance_handler(\Elgg\Hook $hook) { 703 if (elgg_is_admin_logged_in()) { 704 return; 705 } 706 707 $info = $hook->getValue(); 708 709 if ($info['identifier'] == 'action' && $info['segments'][0] == 'login') { 710 return; 711 } 712 713 if (_elgg_admin_maintenance_allow_url(current_page_url())) { 714 return; 715 } 716 717 elgg_unregister_plugin_hook_handler('register', 'menu:login', '_elgg_login_menu_setup'); 718 719 echo elgg_view_resource('maintenance'); 720 721 return false; 722} 723 724/** 725 * Prevent non-admins from using actions 726 * 727 * @param \Elgg\Hook $hook 'action', 'all' 728 * 729 * @return bool 730 * @internal 731 */ 732function _elgg_admin_maintenance_action_check(\Elgg\Hook $hook) { 733 if (elgg_is_admin_logged_in()) { 734 return true; 735 } 736 737 if ($hook->getType() == 'login') { 738 $username = get_input('username'); 739 740 $user = get_user_by_username($username); 741 742 if (!$user) { 743 $users = get_user_by_email($username); 744 if (!empty($users)) { 745 $user = $users[0]; 746 } 747 } 748 749 if ($user && $user->isAdmin()) { 750 return true; 751 } 752 } 753 754 if (_elgg_admin_maintenance_allow_url(current_page_url())) { 755 return true; 756 } 757 758 register_error(elgg_echo('actionunauthorized')); 759 760 return false; 761} 762 763/** 764 * Adds default admin widgets to the admin dashboard. 765 * 766 * @param \Elgg\Event $event 'make_admin', 'user' 767 * 768 * @return void 769 * @internal 770 */ 771function _elgg_add_admin_widgets(\Elgg\Event $event) { 772 $user = $event->getObject(); 773 774 elgg_call(ELGG_IGNORE_ACCESS, function() use ($user) { 775 // check if the user already has widgets 776 if (elgg_get_widgets($user->guid, 'admin')) { 777 return; 778 } 779 780 // In the form column => array of handlers in order, top to bottom 781 $adminWidgets = [ 782 1 => ['control_panel', 'admin_welcome'], 783 2 => ['online_users', 'new_users', 'content_stats'], 784 ]; 785 786 foreach ($adminWidgets as $column => $handlers) { 787 foreach ($handlers as $position => $handler) { 788 $guid = elgg_create_widget($user->getGUID(), $handler, 'admin'); 789 if ($guid !== false) { 790 $widget = get_entity($guid); 791 /* @var \ElggWidget $widget */ 792 $widget->move($column, $position); 793 } 794 } 795 } 796 }); 797} 798 799/** 800 * Add the current site admins to the subscribers when making/removing an admin user 801 * 802 * @param \Elgg\Hook $hook 'get', 'subscribers' 803 * 804 * @return void|array 805 */ 806function _elgg_admin_get_admin_subscribers_admin_action(\Elgg\Hook $hook) { 807 808 if (!_elgg_config()->security_notify_admins) { 809 return; 810 } 811 812 $event = $hook->getParam('event'); 813 if (!$event instanceof \Elgg\Notifications\SubscriptionNotificationEvent) { 814 return; 815 } 816 817 if (!in_array($event->getAction(), ['make_admin', 'remove_admin'])) { 818 return; 819 } 820 821 $user = $event->getObject(); 822 if (!$user instanceof \ElggUser) { 823 return; 824 } 825 826 /* @var $admin_batch \Elgg\BatchResult */ 827 $admin_batch = elgg_get_admins([ 828 'limit' => false, 829 'wheres' => [ 830 function (QueryBuilder $qb, $main_alias) use ($user) { 831 return $qb->compare("{$main_alias}.guid", '!=', $user->guid, ELGG_VALUE_GUID); 832 }, 833 ], 834 'batch' => true, 835 ]); 836 837 $return_value = $hook->getValue(); 838 839 /* @var $admin \ElggUser */ 840 foreach ($admin_batch as $admin) { 841 $return_value[$admin->guid] = ['email']; 842 } 843 844 return $return_value; 845} 846 847/** 848 * Prepare the notification content for site admins about making a site admin 849 * 850 * @param \Elgg\Hook $hook 'prepare', 'notification:make_admin:user:' 851 * 852 * @return void|\Elgg\Notifications\Notification 853 */ 854function _elgg_admin_prepare_admin_notification_make_admin(\Elgg\Hook $hook) { 855 856 $return_value = $hook->getValue(); 857 if (!$return_value instanceof \Elgg\Notifications\Notification) { 858 return; 859 } 860 861 $recipient = $hook->getParam('recipient'); 862 $object = $hook->getParam('object'); 863 $actor = $hook->getParam('sender'); 864 $language = $hook->getParam('language'); 865 866 if (!($recipient instanceof ElggUser) || !($object instanceof ElggUser) || !($actor instanceof ElggUser)) { 867 return; 868 } 869 870 if ($recipient->getGUID() === $object->getGUID()) { 871 // recipient is the user being acted on, this is handled elsewhere 872 return; 873 } 874 875 $site = elgg_get_site_entity(); 876 877 $return_value->subject = elgg_echo('admin:notification:make_admin:admin:subject', [$site->getDisplayName()], $language); 878 $return_value->body = elgg_echo('admin:notification:make_admin:admin:body', [ 879 $recipient->getDisplayName(), 880 $actor->getDisplayName(), 881 $object->getDisplayName(), 882 $site->getDisplayName(), 883 $object->getURL(), 884 $site->getURL(), 885 ], $language); 886 887 $return_value->url = elgg_normalize_url('admin/users/admins'); 888 889 return $return_value; 890} 891 892/** 893 * Prepare the notification content for site admins about removing a site admin 894 * 895 * @param \Elgg\Hook $hook 'prepare', 'notification:remove_admin:user:user' 896 * 897 * @return void|\Elgg\Notifications\Notification 898 */ 899function _elgg_admin_prepare_admin_notification_remove_admin(\Elgg\Hook $hook) { 900 901 $return_value = $hook->getValue(); 902 if (!$return_value instanceof \Elgg\Notifications\Notification) { 903 return; 904 } 905 906 $recipient = $hook->getParam('recipient'); 907 $object = $hook->getParam('object'); 908 $actor = $hook->getParam('sender'); 909 $language = $hook->getParam('language'); 910 911 if (!($recipient instanceof ElggUser) || !($object instanceof ElggUser) || !($actor instanceof ElggUser)) { 912 return; 913 } 914 915 if ($recipient->getGUID() === $object->getGUID()) { 916 // recipient is the user being acted on, this is handled elsewhere 917 return; 918 } 919 920 $site = elgg_get_site_entity(); 921 922 $return_value->subject = elgg_echo('admin:notification:remove_admin:admin:subject', [$site->getDisplayName()], $language); 923 $return_value->body = elgg_echo('admin:notification:remove_admin:admin:body', [ 924 $recipient->getDisplayName(), 925 $actor->getDisplayName(), 926 $object->getDisplayName(), 927 $site->getDisplayName(), 928 $object->getURL(), 929 $site->getURL(), 930 ], $language); 931 932 $return_value->url = elgg_normalize_url('admin/users/admins'); 933 934 return $return_value; 935} 936 937/** 938 * Add the user to the subscribers when making/removing the admin role 939 * 940 * @param \Elgg\Hook $hook 'get', 'subscribers' 941 * 942 * @return void|array 943 */ 944function _elgg_admin_get_user_subscriber_admin_action(\Elgg\Hook $hook) { 945 946 if (!_elgg_config()->security_notify_user_admin) { 947 return; 948 } 949 950 $event = $hook->getParam('event'); 951 if (!$event instanceof \Elgg\Notifications\SubscriptionNotificationEvent) { 952 return; 953 } 954 955 if (!in_array($event->getAction(), ['make_admin', 'remove_admin'])) { 956 return; 957 } 958 959 $user = $event->getObject(); 960 if (!$user instanceof \ElggUser) { 961 return; 962 } 963 964 $return_value = $hook->getValue(); 965 966 $return_value[$user->guid] = ['email']; 967 968 return $return_value; 969} 970 971/** 972 * Prepare the notification content for the user being made as a site admins 973 * 974 * @param \Elgg\Hook $hook 'prepare', 'notification:make_admin:user:user' 975 * 976 * @return void|\Elgg\Notifications\Notification 977 */ 978function _elgg_admin_prepare_user_notification_make_admin(\Elgg\Hook $hook) { 979 980 $return_value = $hook->getValue(); 981 if (!$return_value instanceof \Elgg\Notifications\Notification) { 982 return; 983 } 984 985 $recipient = $hook->getParam('recipient'); 986 $object = $hook->getParam('object'); 987 $actor = $hook->getParam('sender'); 988 $language = $hook->getParam('language'); 989 990 if (!($recipient instanceof ElggUser) || !($object instanceof ElggUser) || !($actor instanceof ElggUser)) { 991 return; 992 } 993 994 if ($recipient->guid !== $object->guid) { 995 // recipient is some other user, this is handled elsewhere 996 return; 997 } 998 999 $site = elgg_get_site_entity(); 1000 1001 $return_value->subject = elgg_echo('admin:notification:make_admin:user:subject', [$site->getDisplayName()], $language); 1002 $return_value->body = elgg_echo('admin:notification:make_admin:user:body', [ 1003 $recipient->getDisplayName(), 1004 $actor->getDisplayName(), 1005 $site->getDisplayName(), 1006 $site->getURL(), 1007 ], $language); 1008 1009 $return_value->url = elgg_normalize_url('admin'); 1010 1011 return $return_value; 1012} 1013 1014/** 1015 * Prepare the notification content for the user being removed as a site admins 1016 * 1017 * @param \Elgg\Hook $hook 'prepare', 'notification:remove_admin:user:user' 1018 * 1019 * @return void|\Elgg\Notifications\Notification 1020 */ 1021function _elgg_admin_prepare_user_notification_remove_admin(\Elgg\Hook $hook) { 1022 1023 $return_value = $hook->getValue(); 1024 if (!$return_value instanceof \Elgg\Notifications\Notification) { 1025 return; 1026 } 1027 1028 $recipient = $hook->getParam('recipient'); 1029 $object = $hook->getParam('object'); 1030 $actor = $hook->getParam('sender'); 1031 $language = $hook->getParam('language'); 1032 1033 if (!($recipient instanceof ElggUser) || !($object instanceof ElggUser) || !($actor instanceof ElggUser)) { 1034 return; 1035 } 1036 1037 if ($recipient->getGUID() !== $object->getGUID()) { 1038 // recipient is some other user, this is handled elsewhere 1039 return; 1040 } 1041 1042 $site = elgg_get_site_entity(); 1043 1044 $return_value->subject = elgg_echo('admin:notification:remove_admin:user:subject', [$site->getDisplayName()], $language); 1045 $return_value->body = elgg_echo('admin:notification:remove_admin:user:body', [ 1046 $recipient->getDisplayName(), 1047 $actor->getDisplayName(), 1048 $site->getDisplayName(), 1049 $site->getURL(), 1050 ], $language); 1051 1052 $return_value->url = ''; 1053 1054 return $return_value; 1055} 1056 1057/** 1058 * Add menu items to the filter menu on the admin upgrades page 1059 * 1060 * @param \Elgg\Hook $hook 'register', 'menu:filter:admin/upgrades' 1061 * 1062 * @return MenuItems 1063 * @internal 1064 */ 1065function _elgg_admin_upgrades_menu(\Elgg\Hook $hook) { 1066 1067 $result = $hook->getValue(); 1068 1069 $result[] = ElggMenuItem::factory([ 1070 'name' => 'pending', 1071 'text' => elgg_echo('admin:upgrades:menu:pending'), 1072 'href' => 'admin/upgrades', 1073 'priority' => 100, 1074 ]); 1075 1076 $result[] = ElggMenuItem::factory([ 1077 'name' => 'completed', 1078 'text' => elgg_echo('admin:upgrades:menu:completed'), 1079 'href' => 'admin/upgrades/finished', 1080 'priority' => 200, 1081 ]); 1082 1083 $result[] = ElggMenuItem::factory([ 1084 'name' => 'db', 1085 'text' => elgg_echo('admin:upgrades:menu:db'), 1086 'href' => 'admin/upgrades/db', 1087 'priority' => 300, 1088 ]); 1089 1090 return $result; 1091} 1092 1093/** 1094 * Check if new users need to be validated by an administrator 1095 * 1096 * @param \Elgg\Hook $hook 'register', 'user' 1097 * 1098 * @return void 1099 * @internal 1100 * @since 3.2 1101 */ 1102function _elgg_admin_check_admin_validation(\Elgg\Hook $hook) { 1103 1104 if (!(bool) elgg_get_config('require_admin_validation')) { 1105 return; 1106 } 1107 1108 $user = $hook->getUserParam(); 1109 if (!$user instanceof ElggUser) { 1110 return; 1111 } 1112 1113 elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($user) { 1114 1115 if ($user->isEnabled()) { 1116 // disable the user until validation 1117 $user->disable('admin_validation_required', false); 1118 } 1119 1120 // set validation status 1121 $user->setValidationStatus(false); 1122 1123 // store a flag in session so we can forward the user correctly 1124 $session = elgg_get_session(); 1125 $session->set('admin_validation', true); 1126 1127 if (elgg_get_config('admin_validation_notification') === 'direct') { 1128 _elgg_admin_notify_admins_pending_user_validation(); 1129 } 1130 }); 1131} 1132 1133/** 1134 * Prevent unvalidated users from logging in 1135 * 1136 * @param \Elgg\Event $event 'login:before', 'user' 1137 * 1138 * @return void 1139 * @throws LoginException 1140 * @internal 1141 * @since 3.2 1142 */ 1143function _elgg_admin_user_validation_login_attempt(\Elgg\Event $event) { 1144 1145 if (!(bool) elgg_get_config('require_admin_validation')) { 1146 return; 1147 } 1148 1149 $user = $event->getObject(); 1150 if (!$user instanceof ElggUser) { 1151 return; 1152 } 1153 1154 elgg_call(ELGG_SHOW_DISABLED_ENTITIES, function() use ($user) { 1155 if ($user->isEnabled() && $user->isValidated() !== false) { 1156 return; 1157 } 1158 1159 throw new LoginException(elgg_echo('LoginException:AdminValidationPending')); 1160 }); 1161} 1162 1163/** 1164 * Send a notification to all admins that there are pending user validations 1165 * 1166 * @return void 1167 * @internal 1168 * @since 3.2 1169 */ 1170function _elgg_admin_notify_admins_pending_user_validation() { 1171 1172 if (empty(elgg_get_config('admin_validation_notification'))) { 1173 return; 1174 } 1175 1176 $unvalidated_count = elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() { 1177 return elgg_count_entities([ 1178 'type' => 'user', 1179 'metadata_name_value_pairs' => [ 1180 'validated' => 0, 1181 ], 1182 ]); 1183 }); 1184 if (empty($unvalidated_count)) { 1185 // shouldn't be able to get here because this function is triggered when a user is marked as unvalidated 1186 return; 1187 } 1188 1189 $site = elgg_get_site_entity(); 1190 $admins = elgg_get_admins([ 1191 'limit' => false, 1192 'batch' => true, 1193 ]); 1194 1195 $url = elgg_normalize_url('admin/users/unvalidated'); 1196 1197 /* @var $admin ElggUser */ 1198 foreach ($admins as $admin) { 1199 $user_setting = $admin->getPrivateSetting('admin_validation_notification'); 1200 if (isset($user_setting) && !(bool) $user_setting) { 1201 continue; 1202 } 1203 1204 $subject = elgg_echo('admin:notification:unvalidated_users:subject', [$site->getDisplayName()], $admin->getLanguage()); 1205 $body = elgg_echo('admin:notification:unvalidated_users:body', [ 1206 $admin->getDisplayName(), 1207 $unvalidated_count, 1208 $site->getDisplayName(), 1209 $url, 1210 ], $admin->getLanguage()); 1211 1212 $params = [ 1213 'action' => 'admin:unvalidated', 1214 'object' => $admin, 1215 ]; 1216 notify_user($admin->guid, $site->guid, $subject, $body, $params, ['email']); 1217 } 1218} 1219 1220/** 1221 * Save a setting related to admin approval of new users 1222 * 1223 * @param \Elgg\Hook $hook 'usersettings:save', 'user' 1224 * 1225 * @return void 1226 * @internal 1227 * @since 3.2 1228 */ 1229function _elgg_admin_save_notification_setting(\Elgg\Hook $hook) { 1230 1231 $user = $hook->getUserParam(); 1232 if (!$user instanceof ElggUser || !$user->isAdmin()) { 1233 return; 1234 } 1235 1236 $request = $hook->getParam('request'); 1237 if (!$request instanceof \Elgg\Request) { 1238 return; 1239 } 1240 1241 $value = (bool) $request->getParam('admin_validation_notification', true); 1242 $user->setPrivateSetting('admin_validation_notification', $value); 1243} 1244 1245/** 1246 * Set the correct forward url after user registration 1247 * 1248 * @param \Elgg\Hook $hook 'response', 'action:register' 1249 * 1250 * @return void|ResponseBuilder 1251 * @internal 1252 * @since 3.2 1253 */ 1254function _elgg_admin_set_registration_forward_url(\Elgg\Hook $hook) { 1255 1256 $response = $hook->getValue(); 1257 if (!$response instanceof ResponseBuilder) { 1258 return; 1259 } 1260 1261 $session = elgg_get_session(); 1262 if (!$session->get('admin_validation')) { 1263 return; 1264 } 1265 1266 // if other plugins already have set forwarding, don't do anything 1267 if (!empty($response->getForwardURL()) && $response->getForwardURL() !== REFERER) { 1268 return; 1269 } 1270 1271 $response->setForwardURL(elgg_generate_url('account:validation:pending')); 1272 1273 return $response; 1274} 1275 1276/** 1277 * Notify the user that their account is approved 1278 * 1279 * @param \Elgg\Event $event 'validate:after', 'user' 1280 * 1281 * @return void 1282 * @internal 1283 * @since 3.2 1284 */ 1285function _elgg_admin_user_validation_notification(\Elgg\Event $event) { 1286 1287 if (!(bool) elgg_get_config('require_admin_validation')) { 1288 return; 1289 } 1290 1291 $user = $event->getObject(); 1292 if (!$user instanceof ElggUser) { 1293 return; 1294 } 1295 1296 $site = elgg_get_site_entity(); 1297 1298 $subject = elgg_echo('account:notification:validation:subject', [$site->getDisplayName()], $user->getLanguage()); 1299 $body = elgg_echo('account:notification:validation:body', [ 1300 $user->getDisplayName(), 1301 $site->getDisplayName(), 1302 $site->getURL(), 1303 ], $user->getLanguage()); 1304 1305 $params = [ 1306 'action' => 'account:validated', 1307 'object' => $user, 1308 ]; 1309 1310 notify_user($user->guid, $site->guid, $subject, $body, $params, ['email']); 1311} 1312 1313/** 1314 * @see \Elgg\Application::loadCore Do not do work here. Just register for events. 1315 */ 1316return function(\Elgg\EventsService $events) { 1317 $events->registerHandler('init', 'system', '_elgg_admin_init'); 1318}; 1319