diff options
Diffstat (limited to 'engine/lib/admin.php')
| -rw-r--r-- | engine/lib/admin.php | 663 | 
1 files changed, 663 insertions, 0 deletions
| diff --git a/engine/lib/admin.php b/engine/lib/admin.php new file mode 100644 index 000000000..f36f29668 --- /dev/null +++ b/engine/lib/admin.php @@ -0,0 +1,663 @@ +<?php +/** + * Elgg admin functions. + * + * Admin menu items + * Elgg has a convenience function for adding menu items to the sidebar of the + * admin area. @see elgg_register_admin_menu_item() + * + * Admin pages + * Plugins no not need to provide their own page handler to add a page to the + * admin area. A view placed at admin/<section>/<subsection> can be access + * at http://example.org/admin/<section>/<subsection>. The title of the page + * will be elgg_echo('admin:<section>:<subsection>'). For an example of how to + * add a page to the admin area, see the diagnostics plugin. + * + * Admin notices + * System messages (success and error messages) are used in both the main site + * and the admin area. There is a special presistent message for the admin area + * called an admin notice. It should be used when a plugin requires an + * administrator to take an action. An example is the categories plugin + * requesting that the administrator set site categories after the plugin has + * been activated. @see elgg_add_admin_notice() + * + * + * @package Elgg.Core + * @subpackage Admin + */ + +/** + * Get the admin users  + * + * @param array $options Options array, @see elgg_get_entities() for parameters + * + * @return mixed Array of admin users or false on failure. If a count, returns int. + * @since 1.8.0 + */ +function elgg_get_admins(array $options = array()) { +	global $CONFIG; + +	if (isset($options['joins'])) { +		if (!is_array($options['joins'])) { +			$options['joins'] = array($options['joins']); +		} +		$options['joins'][] = "join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid"; +	} else { +		$options['joins'] = array("join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid"); +	} + +	if (isset($options['wheres'])) { +		if (!is_array($options['wheres'])) { +			$options['wheres'] = array($options['wheres']); +		} +		$options['wheres'][] = "u.admin = 'yes'"; +	} else { +		$options['wheres'][] = "u.admin = 'yes'"; +	} + +	return elgg_get_entities($options); +} + +/** + * Write a persistent message to the admin view. + * Useful to alert the admin to take a certain action. + * The id is a unique ID that can be cleared once the admin + * completes the action. + * + * eg: add_admin_notice('twitter_services_no_api', + * 	'Before your users can use Twitter services on this site, you must set up + * 	the Twitter API key in the <a href="link">Twitter Services Settings</a>'); + * + * @param string $id      A unique ID that your plugin can remember + * @param string $message Body of the message + * + * @return bool + * @since 1.8.0 + */ +function elgg_add_admin_notice($id, $message) { +	if ($id && $message) { +		if (elgg_admin_notice_exists($id)) { +			return false; +		} + +		// need to handle when no one is logged in +		$old_ia = elgg_set_ignore_access(true); + +		$admin_notice = new ElggObject(); +		$admin_notice->subtype = 'admin_notice'; +		// admins can see ACCESS_PRIVATE but no one else can. +		$admin_notice->access_id = ACCESS_PRIVATE; +		$admin_notice->admin_notice_id = $id; +		$admin_notice->description = $message; + +		$result = $admin_notice->save(); + +		elgg_set_ignore_access($old_ia); + +		return (bool)$result; +	} + +	return false; +} + +/** + * Remove an admin notice by ID. + * + * eg In actions/twitter_service/save_settings: + * 	if (is_valid_twitter_api_key()) { + * 		delete_admin_notice('twitter_services_no_api'); + * 	} + * + * @param string $id The unique ID assigned in add_admin_notice() + * + * @return bool + * @since 1.8.0 + */ +function elgg_delete_admin_notice($id) { +	if (!$id) { +		return FALSE; +	} +	$result = TRUE; +	$notices = elgg_get_entities_from_metadata(array( +		'metadata_name' => 'admin_notice_id', +		'metadata_value' => $id +	)); + +	if ($notices) { +		// in case a bad plugin adds many, let it remove them all at once. +		foreach ($notices as $notice) { +			$result = ($result && $notice->delete()); +		} +		return $result; +	} +	return FALSE; +} + +/** + * Get admin notices. An admin must be logged in since the notices are private. + * + * @param int $limit Limit + * + * @return array Array of admin notices + * @since 1.8.0 + */ +function elgg_get_admin_notices($limit = 10) { +	return elgg_get_entities_from_metadata(array( +		'type' => 'object', +		'subtype' => 'admin_notice', +		'limit' => $limit +	)); +} + +/** + * Check if an admin notice is currently active. + * + * @param string $id The unique ID used to register the notice. + * + * @return bool + * @since 1.8.0 + */ +function elgg_admin_notice_exists($id) { +	$old_ia = elgg_set_ignore_access(true); +	$notice = elgg_get_entities_from_metadata(array( +		'type' => 'object', +		'subtype' => 'admin_notice', +		'metadata_name_value_pair' => array('name' => 'admin_notice_id', 'value' => $id) +	)); +	elgg_set_ignore_access($old_ia); + +	return ($notice) ? TRUE : FALSE; +} + +/** + * Add an admin area section or child section. + * This is a wrapper for elgg_register_menu_item(). + * + * Used in conjuction with http://elgg.org/admin/section_id/child_section style + * page handler. See the documentation at the top of this file for more details + * on that. + * + * The text of the menu item is obtained from elgg_echo(admin:$parent_id:$menu_id) + * + * This function handles registering the parent if it has not been registered. + * + * @param string $section   The menu section to add to + * @param string $menu_id   The unique ID of section + * @param string $parent_id If a child section, the parent section id + * @param int    $priority  The menu item priority + * + * @return bool + * @since 1.8.0 + */ +function elgg_register_admin_menu_item($section, $menu_id, $parent_id = NULL, $priority = 100) { + +	// make sure parent is registered +	if ($parent_id && !elgg_is_menu_item_registered('page', $parent_id)) { +		elgg_register_admin_menu_item($section, $parent_id); +	} + +	// in the admin section parents never have links +	if ($parent_id) { +		$href = "admin/$parent_id/$menu_id"; +	} else { +		$href = NULL; +	} + +	$name = $menu_id; +	if ($parent_id) { +		$name = "$parent_id:$name"; +	} + +	return elgg_register_menu_item('page', array( +		'name' => $name, +		'href' => $href, +		'text' => elgg_echo("admin:$name"), +		'context' => 'admin', +		'parent_name' => $parent_id, +		'priority' => $priority, +		'section' => $section +	)); +} + +/** + * Initialize the admin backend. + * @return void + * @access private + */ +function admin_init() { +	elgg_register_action('admin/user/ban', '', 'admin'); +	elgg_register_action('admin/user/unban', '', 'admin'); +	elgg_register_action('admin/user/delete', '', 'admin'); +	elgg_register_action('admin/user/resetpassword', '', 'admin'); +	elgg_register_action('admin/user/makeadmin', '', 'admin'); +	elgg_register_action('admin/user/removeadmin', '', 'admin'); + +	elgg_register_action('admin/site/update_basic', '', 'admin'); +	elgg_register_action('admin/site/update_advanced', '', 'admin'); +	elgg_register_action('admin/site/flush_cache', '', 'admin'); +	elgg_register_action('admin/site/unlock_upgrade', '', 'admin'); +	elgg_register_action('admin/site/regenerate_secret', '', 'admin'); + +	elgg_register_action('admin/menu/save', '', 'admin'); + +	elgg_register_action('admin/delete_admin_notice', '', 'admin'); + +	elgg_register_action('profile/fields/reset', '', 'admin'); +	elgg_register_action('profile/fields/add', '', 'admin'); +	elgg_register_action('profile/fields/edit', '', 'admin'); +	elgg_register_action('profile/fields/delete', '', 'admin'); +	elgg_register_action('profile/fields/reorder', '', 'admin'); + +	elgg_register_simplecache_view('css/admin'); +	elgg_register_simplecache_view('js/admin'); +	$url = elgg_get_simplecache_url('js', 'admin'); +	elgg_register_js('elgg.admin', $url); +	elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js'); + +	// administer +	// dashboard +	elgg_register_menu_item('page', array( +		'name' => 'dashboard', +		'href' => 'admin/dashboard', +		'text' => elgg_echo('admin:dashboard'), +		'context' => 'admin', +		'priority' => 10, +		'section' => 'administer' +	)); +	// statistics +	elgg_register_admin_menu_item('administer', 'statistics', null, 20); +	elgg_register_admin_menu_item('administer', 'overview', 'statistics'); +	elgg_register_admin_menu_item('administer', 'server', 'statistics'); + +	// users +	elgg_register_admin_menu_item('administer', 'users', null, 20); +	elgg_register_admin_menu_item('administer', 'online', 'users', 10); +	elgg_register_admin_menu_item('administer', 'admins', 'users', 20); +	elgg_register_admin_menu_item('administer', 'newest', 'users', 30); +	elgg_register_admin_menu_item('administer', 'add', 'users', 40); + +	// configure +	// plugins +	elgg_register_menu_item('page', array( +		'name' => 'plugins', +		'href' => 'admin/plugins', +		'text' => elgg_echo('admin:plugins'), +		'context' => 'admin', +		'priority' => 75, +		'section' => 'configure' +	)); + +	// settings +	elgg_register_admin_menu_item('configure', 'appearance', null, 50); +	elgg_register_admin_menu_item('configure', 'settings', null, 100); +	elgg_register_admin_menu_item('configure', 'basic', 'settings', 10); +	elgg_register_admin_menu_item('configure', 'advanced', 'settings', 20); +	elgg_register_admin_menu_item('configure', 'advanced/site_secret', 'settings', 25); +	elgg_register_admin_menu_item('configure', 'menu_items', 'appearance', 30); +	elgg_register_admin_menu_item('configure', 'profile_fields', 'appearance', 40); +	// default widgets is added via an event handler elgg_default_widgets_init() in widgets.php +	// because it requires additional setup. + +	// plugin settings are added in elgg_admin_add_plugin_settings_menu() via the admin page handler +	// for performance reasons. + +	// we want plugin settings menu items to be sorted alphabetical +	if (elgg_in_context('admin')) { +		elgg_register_plugin_hook_handler('prepare', 'menu:page', 'elgg_admin_sort_page_menu'); +	} + +	if (elgg_is_admin_logged_in()) { +		elgg_register_menu_item('topbar', array( +			'name' => 'administration', +			'href' => 'admin', +			'text' => elgg_view_icon('settings') . elgg_echo('admin'), +			'priority' => 100, +			'section' => 'alt', +		)); +	} +			 +	// widgets +	$widgets = array('online_users', 'new_users', 'content_stats', 'admin_welcome', 'control_panel'); +	foreach ($widgets as $widget) { +		elgg_register_widget_type( +				$widget, +				elgg_echo("admin:widget:$widget"), +				elgg_echo("admin:widget:$widget:help"), +				'admin' +		); +	} + +	// automatic adding of widgets for admin +	elgg_register_event_handler('make_admin', 'user', 'elgg_add_admin_widgets'); + +	elgg_register_page_handler('admin', 'admin_page_handler'); +	elgg_register_page_handler('admin_plugin_screenshot', 'admin_plugin_screenshot_page_handler'); +	elgg_register_page_handler('admin_plugin_text_file', 'admin_markdown_page_handler'); +} + +/** + * Create the plugin settings page menu. + * + * This is done in a separate function called from the admin + * page handler because of performance concerns. + * + * @return void + * @access private + * @since 1.8.0 + */ +function elgg_admin_add_plugin_settings_menu() { + +	$active_plugins = elgg_get_plugins('active'); +	if (!$active_plugins) { +		// nothing added because no items +		return; +	} + +	foreach ($active_plugins as $plugin) { +		$plugin_id = $plugin->getID(); +		$settings_view_old = 'settings/' . $plugin_id . '/edit'; +		$settings_view_new = 'plugins/' . $plugin_id . '/settings'; +		if (elgg_view_exists($settings_view_new) || elgg_view_exists($settings_view_old)) { +			elgg_register_menu_item('page', array( +				'name' => $plugin_id, +				'href' => "admin/plugin_settings/$plugin_id", +				'text' => $plugin->getManifest()->getName(), +				'parent_name' => 'settings', +				'context' => 'admin', +				'section' => 'configure', +			)); +		} +	} +} + +/** + * Sort the plugin settings menu items + * + * @param string $hook + * @param string $type + * @param array  $return + * @param array  $params + * + * @return void + * @since 1.8.0 + * @access private + */ +function elgg_admin_sort_page_menu($hook, $type, $return, $params) { +	$configure_items = $return['configure']; +	/* @var ElggMenuItem[] $configure_items */ +	foreach ($configure_items as $menu_item) { +		if ($menu_item->getName() == 'settings') { +			$settings = $menu_item; +		} +	} + +	// keep the basic and advanced settings at the top +	/* @var ElggMenuItem $settings */ +	$children = $settings->getChildren(); +	$site_settings = array_splice($children, 0, 2); +	usort($children, array('ElggMenuBuilder', 'compareByText')); +	array_splice($children, 0, 0, $site_settings); +	$settings->setChildren($children); +} + +/** + * Handles any set up required for administration pages + * + * @return void + * @access private + */ +function admin_pagesetup() { +	if (elgg_in_context('admin')) { +		$url = elgg_get_simplecache_url('css', 'admin'); +		elgg_register_css('elgg.admin', $url); +		elgg_load_css('elgg.admin'); +		elgg_unregister_css('elgg'); + +		// setup footer menu +		elgg_register_menu_item('admin_footer', array( +			'name' => 'faq', +			'text' => elgg_echo('admin:footer:faq'), +			'href' => 'http://docs.elgg.org/wiki/Category:Administration_FAQ', +		)); + +		elgg_register_menu_item('admin_footer', array( +			'name' => 'manual', +			'text' => elgg_echo('admin:footer:manual'), +			'href' => 'http://docs.elgg.org/wiki/Administration_Manual', +		)); + +		elgg_register_menu_item('admin_footer', array( +			'name' => 'community_forums', +			'text' => elgg_echo('admin:footer:community_forums'), +			'href' => 'http://community.elgg.org/groups/all/', +		)); + +		elgg_register_menu_item('admin_footer', array( +			'name' => 'blog', +			'text' => elgg_echo('admin:footer:blog'), +			'href' => 'http://blog.elgg.org/', +		)); +	} +} + +/** + * Handle admin pages.  Expects corresponding views as admin/section/subsection + * + * @param array $page Array of pages + * + * @return bool + * @access private + */ +function admin_page_handler($page) { + +	admin_gatekeeper(); +	elgg_admin_add_plugin_settings_menu(); +	elgg_set_context('admin'); + +	elgg_unregister_css('elgg'); +	elgg_load_js('elgg.admin'); +	elgg_load_js('jquery.jeditable'); + +	// default to dashboard +	if (!isset($page[0]) || empty($page[0])) { +		$page = array('dashboard'); +	} + +	// was going to fix this in the page_handler() function but +	// it's commented to explicitly return a string if there's a trailing / +	if (empty($page[count($page) - 1])) { +		array_pop($page); +	} + +	$vars = array('page' => $page); + +	// special page for plugin settings since we create the form for them +	if ($page[0] == 'plugin_settings') { +		if (isset($page[1]) && (elgg_view_exists("settings/{$page[1]}/edit") ||  +			elgg_view_exists("plugins/{$page[1]}/settings"))) { + +			$view = 'admin/plugin_settings'; +			$plugin = elgg_get_plugin_from_id($page[1]); +			$vars['plugin'] = $plugin; + +			$title = elgg_echo("admin:{$page[0]}"); +		} else { +			forward('', '404'); +		} +	} else { +		$view = 'admin/' . implode('/', $page); +		$title = elgg_echo("admin:{$page[0]}"); +		if (count($page) > 1) { +			$title .= ' : ' . elgg_echo('admin:' .  implode(':', $page)); +		} +	} + +	// gets content and prevents direct access to 'components' views +	if ($page[0] == 'components' || !($content = elgg_view($view, $vars))) { +		$title = elgg_echo('admin:unknown_section'); +		$content = elgg_echo('admin:unknown_section'); +	} + +	$body = elgg_view_layout('admin', array('content' => $content, 'title' => $title)); +	echo elgg_view_page($title, $body, 'admin'); +	return true; +} + +/** + * Serves up screenshots for plugins from + * admin_plugin_screenshot/<plugin_id>/<size>/<ss_name>.<ext> + * + * @param array $pages The pages array + * @return bool + * @access private + */ +function admin_plugin_screenshot_page_handler($pages) { +	// only admins can use this for security +	admin_gatekeeper(); + +	$plugin_id = elgg_extract(0, $pages); +	// only thumbnail or full. +	$size = elgg_extract(1, $pages, 'thumbnail'); + +	// the rest of the string is the filename +	$filename_parts = array_slice($pages, 2); +	$filename = implode('/', $filename_parts); +	$filename = sanitise_filepath($filename, false); + +	$plugin = new ElggPlugin($plugin_id); +	if (!$plugin) { +		$file = elgg_get_root_path() . '_graphics/icons/default/medium.png'; +	} else { +		$file = $plugin->getPath() . $filename; +		if (!file_exists($file)) { +			$file = elgg_get_root_path() . '_graphics/icons/default/medium.png'; +		} +	} + +	header("Content-type: image/jpeg"); + +	// resize to 100x100 for thumbnails +	switch ($size) { +		case 'thumbnail': +			echo get_resized_image_from_existing_file($file, 100, 100, true); +			break; + +		case 'full': +		default: +			echo file_get_contents($file); +			break; +	} +	return true; +} + +/** + * Formats and serves out markdown files from plugins. + * + * URLs in format like admin_plugin_text_file/<plugin_id>/filename.ext + * + * The only valid files are: + *	* README.txt + *	* CHANGES.txt + *	* INSTALL.txt + *	* COPYRIGHT.txt + *	* LICENSE.txt + * + * @param array $pages + * @return bool + * @access private + */ +function admin_markdown_page_handler($pages) { +	admin_gatekeeper(); + +	elgg_set_context('admin'); + +	elgg_unregister_css('elgg'); +	elgg_load_js('elgg.admin'); +	elgg_load_js('jquery.jeditable'); +	elgg_load_library('elgg:markdown'); + +	$plugin_id = elgg_extract(0, $pages); +	$plugin = elgg_get_plugin_from_id($plugin_id); +	$filename = elgg_extract(1, $pages); + +	$error = false; +	if (!$plugin) { +		$error = elgg_echo('admin:plugins:markdown:unknown_plugin'); +		$body = elgg_view_layout('admin', array('content' => $error, 'title' => $error)); +		echo elgg_view_page($error, $body, 'admin'); +		return true; +	} + +	$text_files = $plugin->getAvailableTextFiles(); + +	if (!array_key_exists($filename, $text_files)) { +		$error = elgg_echo('admin:plugins:markdown:unknown_file'); +	} + +	$file = $text_files[$filename]; +	$file_contents = file_get_contents($file); + +	if (!$file_contents) { +		$error = elgg_echo('admin:plugins:markdown:unknown_file'); +	} + +	if ($error) { +		$title = $error; +		$body = elgg_view_layout('admin', array('content' => $error, 'title' => $title)); +		echo elgg_view_page($title, $body, 'admin'); +		return true; +	} + +	$title = $plugin->getManifest()->getName() . ": $filename"; +	$text = Markdown($file_contents); + +	$body = elgg_view_layout('admin', array( +		// setting classes here because there's no way to pass classes +		// to the layout +		'content' => '<div class="elgg-markdown">' . $text . '</div>', +		'title' => $title +	)); +	 +	echo elgg_view_page($title, $body, 'admin'); +	return true; +} + +/** + * Adds default admin widgets to the admin dashboard. + * + * @param string $event + * @param string $type + * @param ElggUser $user + * + * @return null|true + * @access private + */ +function elgg_add_admin_widgets($event, $type, $user) { +	elgg_set_ignore_access(true); + +	// check if the user already has widgets +	if (elgg_get_widgets($user->getGUID(), 'admin')) { +		return true; +	} + +	// In the form column => array of handlers in order, top to bottom +	$adminWidgets = array( +		1 => array('control_panel', 'admin_welcome'), +		2 => array('online_users', 'new_users', 'content_stats'), +	); +	 +	foreach ($adminWidgets as $column => $handlers) { +		foreach ($handlers as $position => $handler) { +			$guid = elgg_create_widget($user->getGUID(), $handler, 'admin'); +			if ($guid) { +				$widget = get_entity($guid); +				/* @var ElggWidget $widget */ +				$widget->move($column, $position); +			} +		} +	} +	elgg_set_ignore_access(false); +} + +elgg_register_event_handler('init', 'system', 'admin_init'); +elgg_register_event_handler('pagesetup', 'system', 'admin_pagesetup', 1000); | 
