From 36ef345eb6425106f061fb866d9fa66d051e16df Mon Sep 17 00:00:00 2001 From: brettp Date: Mon, 5 Apr 2010 16:08:42 +0000 Subject: Merged 5530:5604 from 1.7 to trunk. git-svn-id: http://code.elgg.org/elgg/trunk@5622 36083f99-b078-4883-b0ff-0f9b5a30f544 --- engine/lib/actions.php | 4 +- engine/lib/annotations.php | 292 +++++-------------------------------- engine/lib/database.php | 3 +- engine/lib/elgglib.php | 74 ++-------- engine/lib/entities.php | 2 +- engine/lib/group.php | 1 + engine/lib/metadata.php | 133 +++++++++++------ engine/lib/notification.php | 18 +++ engine/lib/river2.php | 4 +- engine/lib/sessions.php | 83 +++++------ engine/lib/upgrades/2010033101.php | 65 +++++++++ engine/lib/upgrades/2010040201.php | 40 +++++ engine/lib/users.php | 153 ++++++++++++++++++- engine/lib/widgets.php | 22 ++- 14 files changed, 488 insertions(+), 406 deletions(-) create mode 100644 engine/lib/upgrades/2010033101.php create mode 100644 engine/lib/upgrades/2010040201.php (limited to 'engine/lib') diff --git a/engine/lib/actions.php b/engine/lib/actions.php index 25ef411f6..7e8e43f40 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -30,11 +30,13 @@ function action($action, $forwarder = "") { // Installation cannot use tokens because it requires site secret to be // working. (#1462) // Login and logout are for convenience. + // file/download (see #2010) $exceptions = array( 'systemsettings/install', 'admin/plugins/disable', 'logout', - 'login' + 'login', + 'file/download', ); if (!in_array($action, $exceptions)) { diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index c545682d5..6fdb69dc0 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -409,273 +409,61 @@ $value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $time /** + * Returns entities based upon annotations. Accepts the same values as + * elgg_get_entities_from_metadata() but uses the annotations table. * - * @todo Add support for arrays of names and values + * @see elgg_get_entities + * @see elgg_get_entities_from_metadata + * @param array $options Array in format: * - * @param $options - * @return unknown_type + * annotation_names => NULL|ARR annotations names + * + * annotation_values => NULL|ARR annotations values + * + * annotation_name_value_pairs => NULL|ARR (name = 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries. + * Currently if multiple values are sent via an array (value => array('value1', 'value2') the pair's operand will be forced to "IN". + * + * annotation_name_value_pairs_operator => NULL|STR The operator to use for combining (name = value) OPERATOR (name = value); default AND + * + * annotation_case_sensitive => BOOL Overall Case sensitive + * + * order_by_annotation => NULL|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC, 'as' => text|integer), + * Also supports array('name' => 'annotation_text1') + * + * annotation_owner_guids => NULL|ARR guids for annotaiton owners + * + * @return array */ function elgg_get_entities_from_annotations(array $options = array()) { $defaults = array( - 'annotation_names' => NULL, - 'annotation_name' => NULL, - 'annotation_values' => NULL, - 'annotation_value' => NULL, - 'annotation_name_value_pair' => NULL, - 'annotation_name_value_pairs' => NULL, - 'annotation_name_value_pairs_operator' => 'AND', - 'annotation_case_sensitive' => TRUE, - 'order_by' => 'maxtime desc', - 'group_by' => 'a.entity_guid' - ); - - $options = array_merge($defaults, $options); - - $singulars = array('annotation_name', 'annotation_value', 'annotation_name_value_pair'); - $options = elgg_normalise_plural_options_array($options, $singulars); - - $clauses = elgg_get_entity_annotation_where_sql('e', $options['annotation_names'], $options['annotation_values'], - $options['annotation_name_value_pairs'], $options['annotation_name_value_pairs_operator'], $options['annotation_case_sensitive']); - - if ($clauses) { - // merge wheres to pass to get_entities() - if (isset($options['wheres']) && !is_array($options['wheres'])) { - $options['wheres'] = array($options['wheres']); - } elseif (!isset($options['wheres'])) { - $options['wheres'] = array(); - } - - $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); - - // merge joins to pass to get_entities() - if (isset($options['joins']) && !is_array($options['joins'])) { - $options['joins'] = array($options['joins']); - } elseif (!isset($options['joins'])) { - $options['joins'] = array(); - } - - $options['joins'] = array_merge($options['joins'], $clauses['joins']); - - // merge selects to pass to get_entities() - if (isset($options['selects']) && !is_array($options['selects'])) { - $options['selects'] = array($options['selects']); - } elseif (!isset($options['selects'])) { - $options['selects'] = array(); - } - - $options['selects'] = array_merge($options['selects'], $clauses['selects']); - - /* @todo overwrites the current order and group bys - if ($clauses['order_by']) { - $options['order_by'] = $clauses['order_by']; - } - if ($clauses['group_by']) { - $options['group_by'] = $clauses['group_by']; - } - */ - } - - return elgg_get_entities($options); -} + 'annotation_names' => ELGG_ENTITIES_ANY_VALUE, + 'annotation_values' => ELGG_ENTITIES_ANY_VALUE, + 'annotation_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, -/** - * Returns annotation name and value SQL where for entities. - * nb: $names and $values are not paired. Use $pairs for this. - * Pairs default to '=' operand. - * - * @param $prefix - * @param ARR|NULL $names - * @param ARR|NULL $values - * @param ARR|NULL $pairs array of names / values / operands - * @param AND|OR $pair_operator Operator to use to join the where clauses for pairs - * @param BOOL $case_sensitive - * @return FALSE|array False on fail, array('joins', 'wheres') - */ -function elgg_get_entity_annotation_where_sql($table, $names = NULL, $values = NULL, $pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE) { - global $CONFIG; - - // short circuit if nothing requested - // 0 is a valid (if not ill-conceived) annotation name. - // 0 is also a valid annotation value for FALSE, NULL, or 0 - if ((!$names && $names !== 0) - && (!$values && $values !== 0) - && (!$pairs && $pairs !== 0)) { - return ''; - } + 'annotation_name_value_pairs_operator' => 'AND', + 'annotation_case_sensitive' => TRUE, + 'order_by_annotation' => array(), - // binary forces byte-to-byte comparision of strings, making - // it case- and diacritical-mark- sensitive. - // only supported on values. - $binary = ($case_sensitive) ? ' BINARY ' : ''; + 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE, - $access = get_access_sql_suffix('a'); - - $return = array ( - 'joins' => array (), - 'wheres' => array(), - 'selects' => array() + 'order_by' => 'maxtime desc', + 'group_by' => 'a.entity_guid' ); - $wheres = array(); - - // get names wheres and joins - $names_where = ''; - if ($names !== NULL) { - $return['joins'][] = "JOIN {$CONFIG->dbprefix}annotations a on {$table}.guid = a.entity_guid"; - if (!is_array($names)) { - $names = array($names); - } - - $sanitised_names = array(); - foreach ($names as $name) { - // normalise to 0. - if (!$name) { - $name = '0'; - } - $sanitised_names[] = "'$name'"; - } - - if ($names_str = implode(',', $sanitised_names)) { - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn on a.name_id = msn.id"; - $names_where = "(msn.string IN ($names_str))"; - } - } - - // get values wheres and joins - $values_where = ''; - if ($values !== NULL) { - $return['joins'][] = "JOIN {$CONFIG->dbprefix}annotations a on {$table}.guid = a.entity_guid"; - - if (!is_array($values)) { - $values = array($values); - } - - $sanitised_values = array(); - foreach ($values as $value) { - // normalize to 0 - if (!$value) { - $value = 0; - } - $sanitised_values[] = "'$value'"; - } - - if ($values_str = implode(',', $sanitised_values)) { - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv on a.value_id = msv.id"; - $values_where = "({$binary}msv.string IN ($values_str))"; - } - } - - if ($names_where && $values_where) { - $wheres[] = "($names_where AND $values_where AND $access)"; - } elseif ($names_where) { - $wheres[] = "($names_where AND $access)"; - } elseif ($values_where) { - $wheres[] = "($values_where AND $access)"; - } - - // add pairs - // pairs must be in arrays. - if (is_array($pairs)) { - $array = array( - 'name' => 'test', - 'value' => 5 - ); - - $array = array('test' => 5); - - // check if this is an array of pairs or just a single pair. - if (isset($pairs['name']) || isset($pairs['value'])) { - $pairs = array($pairs); - } - - $pair_wheres = array(); - - // @todo when the pairs are > 3 should probably split the query up to - // denormalize the strings table. - $i = 1; - foreach ($pairs as $index => $pair) { - // @todo move this elsewhere? - // support shortcut 'n' => 'v' method. - if (!is_array($pair)) { - $pair = array( - 'name' => $index, - 'value' => $pair - ); - } - - // @todo The multiple joins are only needed when the operator is AND - $return['joins'][] = "JOIN {$CONFIG->dbprefix}annotations a{$i} on {$table}.guid = a{$i}.entity_guid"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on a{$i}.name_id = msn{$i}.id"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on a{$i}.value_id = msv{$i}.id"; - - // must have at least a name and value - if (!isset($pair['name']) || !isset($pair['value'])) { - // @todo should probably return false. - continue; - } - - // case sensitivity can be specified per pair. - // default to higher level setting. - if (isset($pair['case_sensitive'])) { - $pair_binary = ($pair['case_sensitive']) ? ' BINARY ' : ''; - } else { - $pair_binary = $binary; - } - - if (isset($pair['operand'])) { - $operand = sanitise_string($pair['operand']); - } else { - $operand = ' = '; - } - - // if the value is an int, don't quote it because str '15' < str '5' - // if the operand is IN don't quote it because quoting should be done already. - //$value = trim(strtolower($operand)) == 'in' ? $pair['value'] : "'{$pair['value']}'"; - if (trim(strtolower($operand)) == 'in' || sanitise_int($pair['value'])) { - $value = $pair['value']; - } else { - $value = "'{$pair['value']}'"; - } - - $access = get_access_sql_suffix("a{$i}"); - $pair_wheres[] = "(msn{$i}.string = '{$pair['name']}' AND {$pair_binary}msv{$i}.string $operand $value AND $access)"; - $i++; - } + $options = array_merge($defaults, $options); - if ($where = implode (" $pair_operator ", $pair_wheres)) { - $wheres[] = "($where)"; - } + if (!$options = elgg_entities_get_metastrings_options('annotation', $options)) { + return FALSE; } - if ($where = implode(' OR ', $wheres)) { - $return['selects'][] = "max(a.time_created) as maxtime"; - $return['wheres'][] = "($where)"; - $return['group_by'] = 'a.entity_guid'; - $return['order_by'] = 'maxtime asc'; - } + // special sorting for annotations + //@todo overrides other sorting + $options['selects'][] = "max(n_table.time_created) as maxtime"; + $options['group_by'] = 'n_table.entity_guid'; - return $return; + return elgg_get_entities($options); } -/** - * Return a list of entities which are annotated with a specific annotation. - * These can be ordered by when the annotation was created/updated. - * - * @param string $entity_type Type of entity. - * @param string $entity_subtype Subtype of entity. - * @param string $name Name of annotation. - * @param string $value Value of annotation. - * @param int $owner_guid Owner. - * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object' - * @param int $limit Maximum number of results to return. - * @param int $offset Place to start. - * @param string $order_by How to order results. - * @param boolean $count Whether to count entities rather than return them - * @param int $timelower The earliest time the annotation can have been created. Default: all - * @param int $timeupper The latest time the annotation can have been created. Default: all - */ - - /** * @deprecated 1.7 Use elgg_get_entities_from_annotations() * @param $entity_type @@ -714,7 +502,7 @@ $timelower = 0, $timeupper = 0) { } if ($owner_guid) { - $options['owner_guid'] = $owner_guid; + $options['annotation_owner_guid'] = $owner_guid; } if ($group_guid) { diff --git a/engine/lib/database.php b/engine/lib/database.php index ec703992d..58685bb82 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -98,7 +98,8 @@ function setup_db_connections() { function db_profiling_shutdown_hook() { global $dbcalls; - elgg_log("DB Queries for this page: $dbcalls", 'DEBUG'); + // demoted to NOTICE as it corrupts javasript at DEBUG + elgg_log("DB Queries for this page: $dbcalls", 'NOTICE'); } /** diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index f106e4ded..9587bf1e4 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -14,10 +14,10 @@ */ /** - * Adds messages to the session so they'll be carried over, and forwards the browser. + * Forwards the browser. * Returns false if headers have already been sent and the browser cannot be moved. * - * @param string $location URL to forward to browser to + * @param string $location URL to forward to browser to. Can be relative path. * @return nothing|false */ function forward($location = "") { @@ -25,10 +25,6 @@ function forward($location = "") { if (!headers_sent()) { $current_page = current_page_url(); - // What is this meant to do? - //if (strpos($current_page, $CONFIG->wwwroot . "action") ===false) - - $_SESSION['msg'] = array_merge($_SESSION['msg'], system_messages()); if ((substr_count($location, 'http://') == 0) && (substr_count($location, 'https://') == 0)) { $location = $CONFIG->url . $location; } @@ -1255,51 +1251,7 @@ function page_draw($title, $body, $sidebar = "") { * @return string The friendly time */ function friendly_time($time) { - $diff = time() - ((int) $time); - - $minute = 60; - $hour = $minute * 60; - $day = $hour * 24; - - if ($diff < $minute) { - $friendly_time = elgg_echo("friendlytime:justnow"); - } else if ($diff < $hour) { - $diff = round($diff / $minute); - if ($diff == 0) { - $diff = 1; - } - - if ($diff > 1) { - $friendly_time = sprintf(elgg_echo("friendlytime:minutes"), $diff); - } else { - $friendly_time = sprintf(elgg_echo("friendlytime:minutes:singular"), $diff); - } - } else if ($diff < $day) { - $diff = round($diff / $hour); - if ($diff == 0) { - $diff = 1; - } - - if ($diff > 1) { - $friendly_time = sprintf(elgg_echo("friendlytime:hours"), $diff); - } else { - $friendly_time = sprintf(elgg_echo("friendlytime:hours:singular"), $diff); - } - } else { - $diff = round($diff / $day); - if ($diff == 0) { - $diff = 1; - } - - if ($diff > 1) { - $friendly_time = sprintf(elgg_echo("friendlytime:days"), $diff); - } else { - $friendly_time = sprintf(elgg_echo("friendlytime:days:singular"), $diff); - } - } - - $timestamp = htmlentities(date(elgg_echo('friendlytime:date_format'), $time)); - return "$friendly_time"; + return elgg_view('output/friendlytime', array('time' => $time)); } /** @@ -1309,12 +1261,7 @@ function friendly_time($time) { * @return string The optimised title */ function friendly_title($title) { - $title = trim($title); - $title = strtolower($title); - $title = preg_replace("/[^\w ]/","",$title); - $title = str_replace(" ","-",$title); - $title = str_replace("--","-",$title); - return $title; + return elgg_view('output/friendlytitle', array('title' => $title)); } /** @@ -1990,7 +1937,8 @@ function elgg_log($message, $level='NOTICE') { * @return void */ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') { - + global $CONFIG; + // plugin can return false to stop the default logging method $params = array('level' => $level, 'msg' => $value, @@ -1999,6 +1947,13 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') { return; } + // Do not want to write to screen before page creation has started. + // This is not fool-proof but probably fixes 95% of the cases when logging + // results in data sent to the browser before the page is begun. + if (!isset($CONFIG->pagesetupdone)) { + $to_screen = FALSE; + } + if ($to_screen == TRUE) { echo '
';
 		print_r($value);
@@ -2932,7 +2887,8 @@ function __elgg_shutdown_hook() {
 	trigger_elgg_event('shutdown', 'system');
 
 	$time = (float)(microtime(TRUE) - $START_MICROTIME);
-	elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'DEBUG');
+	// demoted to NOTICE from DEBUG so javascript is not corrupted
+	elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'NOTICE');
 }
 
 /**
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 3d16e1b3d..987328adc 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -2863,7 +2863,7 @@ function can_edit_entity($entity_guid, $user_guid = 0) {
 				$return = true;
 			}
 			if ($container_entity = get_entity($entity->container_guid)) {
-				if ($container_entity->canEdit()) {
+				if ($container_entity->canEdit($user->getGUID())) {
 					$return = true;
 				}
 			}
diff --git a/engine/lib/group.php b/engine/lib/group.php
index 362f45402..68829dafb 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -842,6 +842,7 @@ function group_gatekeeper($forward = true) {
 	}
 
 	if ($forward && $allowed == false) {
+		register_error(elgg_echo('membershiprequired'));
 		forward($url);
 		exit;
 	}
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index 5c248e0f6..bab919ca2 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -532,8 +532,6 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en
 	return get_data($query, "row_to_elggmetadata");
 }
 
-
-
 /**
  * Returns entities based upon metadata.  Also accepts all
  * options available to elgg_get_entities().  Supports
@@ -547,6 +545,7 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en
  * When in doubt, use name_value_pairs.
  *
  * @see elgg_get_entities
+ * @see elgg_get_entities_from_annotations
  * @param array $options Array in format:
  *
  * 	metadata_names => NULL|ARR metadata names
@@ -560,30 +559,59 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en
  *
  * 	metadata_case_sensitive => BOOL Overall Case sensitive
  *
- * 	order_by_metadata => NULL|ARR (array('name' => 'metadata_text1', 'direction' => ASC|DESC, 'as' => text|integer),
- * 	Also supports array('name' => 'metadata_text1')
+ *  order_by_metadata => NULL|ARR (array('name' => 'metadata_text1', 'direction' => ASC|DESC, 'as' => text|integer),
+ *  Also supports array('name' => 'metadata_text1')
+ *
+ *  metadata_owner_guids => NULL|ARR guids for metadata owners
  *
  * @return array
  */
 function elgg_get_entities_from_metadata(array $options = array()) {
 	$defaults = array(
-		'metadata_names'			=>	ELGG_ENTITIES_ANY_VALUE,
-		'metadata_values'			=>	ELGG_ENTITIES_ANY_VALUE,
-		'metadata_name_value_pairs'	=>	ELGG_ENTITIES_ANY_VALUE,
+		'metadata_names'					=>	ELGG_ENTITIES_ANY_VALUE,
+		'metadata_values'					=>	ELGG_ENTITIES_ANY_VALUE,
+		'metadata_name_value_pairs'			=>	ELGG_ENTITIES_ANY_VALUE,
 
-		'metadata_name_value_pairs_operator' => 'AND',
-		'metadata_case_sensitive' => TRUE,
-		'order_by_metadata' => array(),
+		'metadata_name_value_pairs_operator'=>	'AND',
+		'metadata_case_sensitive' 			=>	TRUE,
+		'order_by_metadata'					=>	array(),
+
+		'metadata_owner_guids'				=>	ELGG_ENTITIES_ANY_VALUE,
 	);
 
 	$options = array_merge($defaults, $options);
 
-	$singulars = array('metadata_name', 'metadata_value', 'metadata_name_value_pair');
+	if (!$options = elgg_entities_get_metastrings_options('metadata', $options)) {
+		return FALSE;
+	}
+
+	return elgg_get_entities($options);
+}
+
+/**
+ * Returns options to pass to elgg_get_entities() for metastrings operations.
+ *
+ * @param string $type Metastring type: annotations or metadata
+ * @param array $options Options
+ *
+ * @return array
+ */
+function elgg_entities_get_metastrings_options($type, $options) {
+	$valid_types = array('metadata', 'annotation');
+	if (!in_array($type, $valid_types)) {
+		return FALSE;
+	}
+
+	// the options for annotations are singular (annotation_name) but the table
+	// is plural (elgg_annotations) so rewrite for the table name.
+	$n_table = ($type == 'annotation') ? 'annotations' : $type;
+
+	$singulars = array("{$type}_name", "{$type}_value", "{$type}_name_value_pair", "{$type}_owner_guid");
 	$options = elgg_normalise_plural_options_array($options, $singulars);
 
-	$clauses = elgg_get_entity_metadata_where_sql('e', $options['metadata_names'], $options['metadata_values'],
-		$options['metadata_name_value_pairs'], $options['metadata_name_value_pairs_operator'], $options['metadata_case_sensitive'],
-		$options['order_by_metadata']);
+	$clauses = elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"], $options["{$type}_values"],
+		$options["{$type}_name_value_pairs"], $options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
+		$options["order_by_{$type}"], $options["{$type}_owner_guids"]);
 
 	if ($clauses) {
 		// merge wheres to pass to get_entities()
@@ -614,15 +642,19 @@ function elgg_get_entities_from_metadata(array $options = array()) {
 		}
 	}
 
-	return elgg_get_entities($options);
+	return $options;
 }
 
 /**
  * Returns metadata name and value SQL where for entities.
- * nb: $names and $values are not paired. Use $pairs for this.
+ * NB: $names and $values are not paired. Use $pairs for this.
  * Pairs default to '=' operand.
  *
- * @param $prefix
+ * This function is reused for annotations because the tables are
+ * exactly the same.
+ *
+ * @param string $e_table Entities table name
+ * @param string $n_table Normalized metastrings table name (Where entities, values, and names are joined. annotations / metadata)
  * @param ARR|NULL $names
  * @param ARR|NULL $values
  * @param ARR|NULL $pairs array of names / values / operands
@@ -631,25 +663,30 @@ function elgg_get_entities_from_metadata(array $options = array()) {
  * @param ARR|NULL $order_by_metadata array of names / direction
  * @return FALSE|array False on fail, array('joins', 'wheres')
  */
-function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NULL, $pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL) {
+function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL, $pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL, $owner_guids = NULL) {
 	global $CONFIG;
 
 	// short circuit if nothing requested
 	// 0 is a valid (if not ill-conceived) metadata name.
 	// 0 is also a valid metadata value for FALSE, NULL, or 0
+	// 0 is also a valid(ish) owner_guid
 	if ((!$names && $names !== 0)
 		&& (!$values && $values !== 0)
 		&& (!$pairs && $pairs !== 0)
+		&& (!$owner_guids && $owner_guids !== 0)
 		&& !isset($order_by_metadata)) {
 		return '';
 	}
 
+	// join counter for incremental joins.
+	$i = 1;
+
 	// binary forces byte-to-byte comparision of strings, making
 	// it case- and diacritical-mark- sensitive.
 	// only supported on values.
 	$binary = ($case_sensitive) ? ' BINARY ' : '';
 
-	$access = get_access_sql_suffix('md');
+	$access = get_access_sql_suffix('n_table');
 
 	$return = array (
 		'joins' => array (),
@@ -657,12 +694,14 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 		'orders' => array()
 	);
 
+	// will always want to join these tables if pulling metastrings.
+	$return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on {$e_table}.guid = n_table.entity_guid";
+
 	$wheres = array();
 
 	// get names wheres and joins
 	$names_where = '';
 	if ($names !== NULL) {
-		$return['joins'][] = "JOIN {$CONFIG->dbprefix}metadata md on {$table}.guid = md.entity_guid";
 		if (!is_array($names)) {
 			$names = array($names);
 		}
@@ -677,7 +716,7 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 		}
 
 		if ($names_str = implode(',', $sanitised_names)) {
-			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn on md.name_id = msn.id";
+			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn on n_table.name_id = msn.id";
 			$names_where = "(msn.string IN ($names_str))";
 		}
 	}
@@ -685,8 +724,6 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 	// get values wheres and joins
 	$values_where = '';
 	if ($values !== NULL) {
-		$return['joins'][] = "JOIN {$CONFIG->dbprefix}metadata md on {$table}.guid = md.entity_guid";
-
 		if (!is_array($values)) {
 			$values = array($values);
 		}
@@ -701,7 +738,7 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 		}
 
 		if ($values_str = implode(',', $sanitised_values)) {
-			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv on md.value_id = msv.id";
+			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv on n_table.value_id = msv.id";
 			$values_where = "({$binary}msv.string IN ($values_str))";
 		}
 	}
@@ -714,8 +751,6 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 		$wheres[] = "($values_where AND $access)";
 	}
 
-	$i = 1;
-
 	// add pairs
 	// pairs must be in arrays.
 	if (is_array($pairs)) {
@@ -739,11 +774,6 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 				);
 			}
 
-			// @todo The multiple joins are only needed when the operator is AND
-			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metadata md{$i} on {$table}.guid = md{$i}.entity_guid";
-			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on md{$i}.name_id = msn{$i}.id";
-			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on md{$i}.value_id = msv{$i}.id";
-
 			// must have at least a name and value
 			if (!isset($pair['name']) || !isset($pair['value'])) {
 				// @todo should probably return false.
@@ -764,6 +794,10 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 				$operand = ' = ';
 			}
 
+			// for comparing
+			$trimmed_operand = trim(strtolower($operand));
+
+			$access = get_access_sql_suffix("n_table{$i}");
 			// if the value is an int, don't quote it because str '15' < str '5'
 			// if the operand is IN don't quote it because quoting should be done already.
 			if (is_numeric($pair['value'])) {
@@ -772,10 +806,10 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 				$values_array = array();
 
 				foreach ($pair['value'] as $pair_value) {
-					if (is_numeric($v)) {
+					if (is_numeric($pair_value)) {
 						$values_array[] = sanitise_string($pair_value);
 					} else {
-						$values_array[] = '\'' . sanitise_string($pair_value) . '\'';
+						$values_array[] = "'" . sanitise_string($pair_value) . "'";
 					}
 				}
 
@@ -786,16 +820,21 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 				// @todo allow support for non IN operands with array of values.
 				// will have to do more silly joins.
 				$operand = 'IN';
-			} else if (trim(strtolower($operand)) == 'in') {
+			} else if ($trimmed_operand == 'in') {
 				$value = "({$pair['value']})";
 			} else {
-				$value = '\'' . sanitise_string($pair['value']) . '\'';
+				$value = "'" . sanitise_string($pair['value']) . "'";
 			}
 
 			$name = sanitise_string($pair['name']);
 
-			$access = get_access_sql_suffix("md{$i}");
+			// @todo The multiple joins are only needed when the operator is AND
+			$return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid";
+			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id";
+			$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id";
+
 			$pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string $operand $value AND $access)";
+
 			$i++;
 		}
 
@@ -804,7 +843,19 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 		}
 	}
 
-	if ($where = implode(' OR ', $wheres)) {
+	// add owner_guids
+	if ($owner_guids) {
+		if (is_array($owner_guids)) {
+			$sanitised = array_map('sanitise_int', $owner_guids);
+			$owner_str = implode(',', $sanitised);
+		} else {
+			$owner_str = sanitise_int($owner_guids);
+		}
+
+		$wheres[] = "(n_table.owner_guid IN ($owner_str))";
+	}
+
+	if ($where = implode(' AND ', $wheres)) {
 		$return['wheres'][] = "($where)";
 	}
 
@@ -821,11 +872,11 @@ function elgg_get_entity_metadata_where_sql($table, $names = NULL, $values = NUL
 				} else {
 					$direction = 'ASC';
 				}
-				$return['joins'][] = "JOIN {$CONFIG->dbprefix}metadata md{$i} on {$table}.guid = md{$i}.entity_guid";
-				$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on md{$i}.name_id = msn{$i}.id";
-				$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on md{$i}.value_id = msv{$i}.id";
+				$return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid";
+				$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id";
+				$return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id";
 
-				$access = get_access_sql_suffix("md{$i}");
+				$access = get_access_sql_suffix("n_table{$i}");
 
 				$return['wheres'][] = "(msn{$i}.string = '$name' AND $access)";
 				if (isset($order_by['as']) && $order_by['as'] == 'integer') {
diff --git a/engine/lib/notification.php b/engine/lib/notification.php
index adc4ebace..024881e0f 100644
--- a/engine/lib/notification.php
+++ b/engine/lib/notification.php
@@ -50,6 +50,19 @@ function register_notification_handler($method, $handler, $params = NULL) {
 	return false;
 }
 
+/**
+ * This function unregisters a handler for a given notification type (eg "email")
+ *
+ * @param string $method The method
+ */
+function unregister_notification_handler($method) {
+	global $NOTIFICATION_HANDLERS;
+
+	if (isset($NOTIFICATION_HANDLERS[$method])) {
+		unset($NOTIFICATION_HANDLERS[$method]);
+	}
+}
+
 /**
  * Notify a user via their preferences.
  *
@@ -101,6 +114,11 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
 			if ($methods) {
 				// Deliver
 				foreach ($methods as $method) {
+
+					if (!isset($NOTIFICATION_HANDLERS[$method])) {
+						continue;
+					}
+
 					// Extract method details from list
 					$details = $NOTIFICATION_HANDLERS[$method];
 					$handler = $details->handler;
diff --git a/engine/lib/river2.php b/engine/lib/river2.php
index 7793ea192..3d826f517 100644
--- a/engine/lib/river2.php
+++ b/engine/lib/river2.php
@@ -21,8 +21,8 @@
  * @return true|false Depending on success
  */
 function add_to_river($view,$action_type,$subject_guid,$object_guid,$access_id = "",$posted = 0, $annotation_id = 0) {
-	// Sanitise variables
-	if (!elgg_view_exists($view)) {
+	// use default viewtype for when called from REST api
+	if (!elgg_view_exists($view, 'default')) {
 		return false;
 	}
 	if (!($subject = get_entity($subject_guid))) {
diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php
index fdc6d1806..f4b1fc69b 100644
--- a/engine/lib/sessions.php
+++ b/engine/lib/sessions.php
@@ -92,17 +92,17 @@ class ElggSession implements ArrayAccess {
 			return true;
 		}
 	}
-	
-	
+
+
 	// Alias functions
 	function get($key) {
 		return $this->offsetGet($key);
 	}
-	
+
 	function set($key, $value) {
 		return $this->offsetSet($key, $value);
 	}
-	
+
 	function del($key) {
 		return $this->offsetUnset($key);
 	}
@@ -166,16 +166,16 @@ function isloggedin() {
  */
 function isadminloggedin() {
 	if (!is_installed()) {
-		return false;
+		return FALSE;
 	}
 
 	$user = get_loggedin_user();
 
-	if ((isloggedin()) && (($user->admin || $user->siteadmin))) {
-		return true;
+	if ((isloggedin()) && $user->isAdmin()) {
+		return TRUE;
 	}
 
-	return false;
+	return FALSE;
 }
 
 /**
@@ -187,40 +187,41 @@ function isadminloggedin() {
  */
 function elgg_is_admin_user($user_guid) {
 	global $CONFIG;
-
-	// cannot use metadata here because of recursion
-
-	// caching is done at the db level so no need to here.
-	$query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as e,
-		{$CONFIG->dbprefix}metastrings as ms1,
-		{$CONFIG->dbprefix}metastrings as ms2,
-		{$CONFIG->dbprefix}metadata as md
-		WHERE (
-			(
-				(ms1.string = 'admin' AND ms2.string = 'yes')
-				OR (ms1.string = 'admin' AND ms2.string = '1')
-			)
-			AND md.name_id = ms1.id	AND md.value_id = ms2.id
-			AND e.guid = md.entity_guid
-			AND e.guid = {$user_guid}
-			AND e.banned = 'no'
+	// cannot use magic metadata here because of recursion
+
+	// must support the old way of getting admin from metadata
+	// in order to run the upgrade to move it into the users table.
+	$version = (int) datalist_get('version');
+
+	if ($version < 2010040201) {
+		$admin = get_metastring_id('admin');
+		$yes = get_metastring_id('yes');
+		$one = get_metastring_id('1');
+
+		$query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as e,
+			{$CONFIG->dbprefix}metadata as md
+			WHERE (
+				md.name_id = '$admin'
+				AND md.value_id IN ('$yes', '$one')
+				AND e.guid = md.entity_guid
+				AND e.guid = {$user_guid}
+				AND e.banned = 'no'
 			)";
-//		OR (
-//			ms1.string = 'admin' AND ms2.string = '1'
-//			AND md.name_id = ms1.id	AND md.value_id = ms2.id
-//			AND e.guid = md.entity_guid
-//			AND e.guid = {$user_guid}
-//			AND e.banned = 'no'
-//			)";
-
+	} else {
+		$query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as e
+			WHERE (
+				e.guid = {$user_guid}
+				AND e.admin = 'yes'
+			)";
+	}
 
 	// normalizing the results from get_data()
 	// See #1242
 	$info = get_data($query);
-	if (!((is_array($info) && count($info) < 1) || $info === false)) {
-		return true;
+	if (!((is_array($info) && count($info) < 1) || $info === FALSE)) {
+		return TRUE;
 	}
-	return false;
+	return FALSE;
 }
 
 /**
@@ -254,7 +255,7 @@ function pam_auth_userpass($credentials = NULL) {
 		if ($user = get_user_by_username($credentials['username'])) {
 
 			// Let admins log in without validating their email, but normal users must have validated their email or been admin created
-			if ((!$user->admin) && (!$user->validated) && (!$user->admin_created)) {
+			if ((!$user->isAdmin()) && (!$user->validated) && (!$user->admin_created)) {
 				return false;
 			}
 
@@ -335,7 +336,7 @@ function reset_login_failure_count($user_guid) {
  * @return bool on exceeded limit.
  */
 function check_rate_limit_exceeded($user_guid) {
-	// 5 failures in 5 minutes causes temporary block on logins	
+	// 5 failures in 5 minutes causes temporary block on logins
 	$limit = 5;
 	$user_guid = (int)$user_guid;
 	$user = get_entity($user_guid);
@@ -434,7 +435,7 @@ function login(ElggUser $user, $persistent = false) {
 function logout() {
 	global $CONFIG;
 
-	if (isset($_SESSION['user'])) {	
+	if (isset($_SESSION['user'])) {
 		if (!trigger_elgg_event('logout','user',$_SESSION['user'])) {
 			return false;
 		}
@@ -532,7 +533,7 @@ function session_init($event, $object_type, $object) {
 		unset($_SESSION['id']);
 		unset($_SESSION['guid']);
 		unset($_SESSION['code']);
-		
+
 		// is there a remember me cookie
 		if (isset($_COOKIE['elggperm'])) {
 			// we have a cookie, so try to log the user in
@@ -545,7 +546,7 @@ function session_init($event, $object_type, $object) {
 				$_SESSION['guid'] = $_SESSION['id'];
 				$_SESSION['code'] = $_COOKIE['elggperm'];
 			}
-		} 
+		}
 	} else {
 		// we have a session and we have already checked the fingerprint
 		// reload the user object from database in case it has changed during the session
diff --git a/engine/lib/upgrades/2010033101.php b/engine/lib/upgrades/2010033101.php
new file mode 100644
index 000000000..b137e0285
--- /dev/null
+++ b/engine/lib/upgrades/2010033101.php
@@ -0,0 +1,65 @@
+dbhost, $CONFIG->dbuser, $CONFIG->dbpass, TRUE);
+	mysql_select_db($CONFIG->dbname, $link);
+
+	$q = "SHOW VARIABLES LIKE 'character_set_client'";
+	$r = mysql_query($q);
+	$client = mysql_fetch_assoc($r);
+
+	$q = "SHOW VARIABLES LIKE 'character_set_connection'";
+	$r = mysql_query($q);
+	$connection = mysql_fetch_assoc($r);
+
+	// only run upgrade if not already talking utf8.
+	if ($client['Value'] != 'utf8' && $connection['Value'] != 'utf8') {
+		$qs = array();
+		$qs[] = "SET NAMES utf8";
+
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}metastrings DISABLE KEYS";
+		$qs[] = "REPLACE INTO {$CONFIG->dbprefix}metastrings (id, string)
+			SELECT id, unhex(hex(convert(string using latin1)))
+			FROM {$CONFIG->dbprefix}metastrings";
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}metastrings ENABLE KEYS";
+
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}groups_entity DISABLE KEYS";
+		$qs[] = "REPLACE INTO {$CONFIG->dbprefix}groups_entity (guid, name, description)
+			SELECT guid, unhex(hex(convert(name using latin1))), unhex(hex(convert(description using latin1)))
+			FROM {$CONFIG->dbprefix}groups_entity";
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}groups_entity ENABLE KEYS";
+
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}objects_entity DISABLE KEYS";
+		$qs[] = "REPLACE INTO {$CONFIG->dbprefix}objects_entity (guid, title, description)
+			SELECT guid, unhex(hex(convert(title using latin1))), unhex(hex(convert(description using latin1)))
+			FROM {$CONFIG->dbprefix}objects_entity";
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}objects_entity ENABLE KEYS";
+
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity DISABLE KEYS";
+		$qs[] = "REPLACE INTO {$CONFIG->dbprefix}users_entity (guid, name, username, password, salt, email, language, code,
+			banned, last_action, prev_last_action, last_login, prev_last_login)
+				SELECT guid, unhex(hex(convert(name using latin1))), username, password, salt, email, language, code,
+					banned, last_action, prev_last_action, last_login, prev_last_login
+				FROM {$CONFIG->dbprefix}users_entity";
+		$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity ENABLE KEYS";
+
+		foreach ($qs as $q) {
+			if (!update_data($q)) {
+				throw new Exception('Couldn\'t execute upgrade query: ' . $q);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/engine/lib/upgrades/2010040201.php b/engine/lib/upgrades/2010040201.php
new file mode 100644
index 000000000..22eee15f8
--- /dev/null
+++ b/engine/lib/upgrades/2010040201.php
@@ -0,0 +1,40 @@
+dbprefix}users_entity DISABLE KEYS";
+
+$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity
+	ADD admin ENUM('yes', 'no') NOT NULL DEFAULT 'no' AFTER `banned`";
+
+$qs[] = "UPDATE {$CONFIG->dbprefix}users_entity SET admin = 'yes' where guid IN (select x.guid FROM(
+SELECT * FROM {$CONFIG->dbprefix}users_entity as e,
+	{$CONFIG->dbprefix}metadata as md
+	WHERE (
+		md.name_id IN ('$admin', '$siteadmin')
+		AND md.value_id IN ('$yes', '$one')
+		AND e.guid = md.entity_guid
+		AND e.banned = 'no'
+	)) as x)";
+
+$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity ADD KEY admin (admin)";
+
+$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity ENABLE KEYS";
+
+$qs[] = "DELETE FROM {$CONFIG->dbprefix}metadata
+	WHERE (
+		name_id IN ('$admin', '$siteadmin')
+		AND value_id IN ('$yes', '$one')
+	)";
+
+foreach ($qs as $q) {
+	update_data($q);
+}
\ No newline at end of file
diff --git a/engine/lib/users.php b/engine/lib/users.php
index 45c281d23..778b072a1 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -43,6 +43,7 @@ class ElggUser extends ElggEntity
 		$this->attributes['language'] = "";
 		$this->attributes['code'] = "";
 		$this->attributes['banned'] = "no";
+		$this->attributes['admin'] = 'no';
 		$this->attributes['tables_split'] = 2;
 	}
 
@@ -199,6 +200,46 @@ class ElggUser extends ElggEntity
 		return $this->banned == 'yes';
 	}
 
+	/**
+	 * Is this user admin?
+	 *
+	 * @return bool
+	 */
+	public function isAdmin() {
+
+		// for backward compatibility we need to pull this directly
+		// from the attributes instead of using the magic methods.
+		// this can be removed in 1.9
+		// return $this->admin == 'yes';
+		return $this->attributes['admin'] == 'yes';
+	}
+
+	/**
+	 * Make the user an admin
+	 *
+	 * @return bool
+	 */
+	public function makeAdmin() {
+		if (make_user_admin($this->guid)) {
+			$this->attributes['admin'] = 'yes';
+			return TRUE;
+		}
+		return FALSE;
+	}
+
+	/**
+	 * Remove the admin flag for user
+	 *
+	 * @return bool
+	 */
+	public function removeAdmin() {
+		if (remove_user_admin($this->guid)) {
+			$this->attributes['admin'] = 'no';
+			return TRUE;
+		}
+		return FALSE;
+	}
+
 	/**
 	 * Get sites that this user is a member of
 	 *
@@ -375,6 +416,30 @@ class ElggUser extends ElggEntity
 			'language',
 		));
 	}
+
+	// backward compatibility with admin flag
+	// remove for 1.9
+	public function __set($name, $value) {
+		if ($name == 'admin' || $name == 'siteadmin') {
+			elgg_deprecated_notice('The admin/siteadmin metadata are not longer used.  Use ElggUser->makeAdmin() and ElggUser->removeAdmin().', '1.7.1');
+
+			if ($value == 'yes' || $value == '1') {
+				$this->makeAdmin();
+			} else {
+				$this->removeAdmin();
+			}
+		}
+		return parent::__set($name, $value);
+	}
+
+	public function __get($name) {
+		if ($name == 'admin' || $name == 'siteadmin') {
+			elgg_deprecated_notice('The admin/siteadmin metadata are not longer used.  Use ElggUser->isAdmin().', '1.7.1');
+			return $this->isAdmin();
+		}
+
+		return parent::__get($name);
+	}
 }
 
 /**
@@ -501,9 +566,11 @@ function ban_user($user_guid, $reason = "") {
 			// Set ban flag
 			return update_data("UPDATE {$CONFIG->dbprefix}users_entity set banned='yes' where guid=$user_guid");
 		}
+
+		return FALSE;
 	}
 
-	return false;
+	return FALSE;
 }
 
 /**
@@ -534,9 +601,81 @@ function unban_user($user_guid) {
 
 			return update_data("UPDATE {$CONFIG->dbprefix}users_entity set banned='no' where guid=$user_guid");
 		}
+
+		return FALSE;
 	}
 
-	return false;
+	return FALSE;
+}
+
+/**
+ * Makes user $guid an admin.
+ *
+ * @param int $guid
+ * @return bool
+ */
+function make_user_admin($user_guid) {
+	global $CONFIG;
+
+	$user = get_entity((int)$user_guid);
+
+	if (($user) && ($user instanceof ElggUser) && ($user->canEdit())) {
+		if (trigger_elgg_event('make_admin', 'user', $user)) {
+
+			// invalidate memcache for this user
+			static $newentity_cache;
+			if ((!$newentity_cache) && (is_memcache_available())) {
+				$newentity_cache = new ElggMemcache('new_entity_cache');
+			}
+
+			if ($newentity_cache) {
+				$newentity_cache->delete($user_guid);
+			}
+
+			$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='yes' where guid=$user_guid");
+			invalidate_cache_for_entity($user_guid);
+			return $r;
+		}
+
+		return FALSE;
+	}
+
+	return FALSE;
+}
+
+/**
+ * Removes user $guid's admin flag.
+ *
+ * @param int $guid
+ * @return bool
+ */
+function remove_user_admin($user_guid) {
+	global $CONFIG;
+
+	$user = get_entity((int)$user_guid);
+
+	if (($user) && ($user instanceof ElggUser) && ($user->canEdit())) {
+		if (trigger_elgg_event('remove_admin', 'user', $user)) {
+
+			// invalidate memcache for this user
+			static $newentity_cache;
+			if ((!$newentity_cache) && (is_memcache_available())) {
+				$newentity_cache = new ElggMemcache('new_entity_cache');
+			}
+
+			if ($newentity_cache) {
+				$newentity_cache->delete($user_guid);
+			}
+
+			$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='no' where guid=$user_guid");
+			invalidate_cache_for_entity($user_guid);
+			return $r;
+		}
+
+		return FALSE;
+	}
+
+	return FALSE;
 }
 
 /**
@@ -1398,10 +1537,6 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
 
 	access_show_hidden_entities($access_status);
 
-	// Check to see if we've registered the first admin yet.
-	// If not, this is the first admin user!
-	$have_admin = datalist_get('admin_registered');
-
 	// Otherwise ...
 	$user = new ElggUser();
 	$user->username = $username;
@@ -1428,9 +1563,13 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
 		}
 	}
 
+	// Check to see if we've registered the first admin yet.
+	// If not, this is the first admin user!
+	$have_admin = datalist_get('admin_registered');
 	global $registering_admin;
+
 	if (!$have_admin) {
-		$user->admin = true;
+		$user->makeAdmin();
 		set_user_validation_status($user->getGUID(), TRUE, 'first_run');
 		datalist_set('admin_registered', 1);
 		$registering_admin = true;
diff --git a/engine/lib/widgets.php b/engine/lib/widgets.php
index a450d6223..7884f263a 100644
--- a/engine/lib/widgets.php
+++ b/engine/lib/widgets.php
@@ -254,7 +254,6 @@ function add_widget($user_guid, $handler, $context, $order = 0, $column = 1, $ac
  * @param string $position A comma-separated list of positions on the page (side or main) where this widget is allowed (default: "side,main")
  * @return true|false Depending on success
  */
-
 function add_widget_type($handler, $name, $description, $context = "all", $multiple = false, $positions = "side,main") {
 	if (!empty($handler) && !empty($name)) {
 		global $CONFIG;
@@ -282,6 +281,27 @@ function add_widget_type($handler, $name, $description, $context = "all", $multi
 	return false;
 }
 
+/**
+ * Remove a widget type
+ *
+ * @param string $handler The identifier for the widget handler
+ */
+function remove_widget_type($handler) {
+	global $CONFIG;
+
+	if (!isset($CONFIG->widgets)) {
+		return;
+	}
+
+	if (!isset($CONFIG->widgets->handlers)) {
+		return;
+	}
+
+	if (isset($CONFIG->widgets->handlers[$handler])) {
+		unset($CONFIG->widgets->handlers[$handler]);
+	}
+}
+
 /**
  * Determines whether or not widgets with the specified handler have been defined
  *
-- 
cgit v1.2.3