diff options
Diffstat (limited to 'engine')
| -rw-r--r-- | engine/lib/actions.php | 4 | ||||
| -rw-r--r-- | engine/lib/annotations.php | 292 | ||||
| -rw-r--r-- | engine/lib/database.php | 3 | ||||
| -rw-r--r-- | engine/lib/elgglib.php | 74 | ||||
| -rw-r--r-- | engine/lib/entities.php | 2 | ||||
| -rw-r--r-- | engine/lib/group.php | 1 | ||||
| -rw-r--r-- | engine/lib/metadata.php | 133 | ||||
| -rw-r--r-- | engine/lib/notification.php | 18 | ||||
| -rw-r--r-- | engine/lib/river2.php | 4 | ||||
| -rw-r--r-- | engine/lib/sessions.php | 83 | ||||
| -rw-r--r-- | engine/lib/upgrades/2010033101.php | 65 | ||||
| -rw-r--r-- | engine/lib/upgrades/2010040201.php | 40 | ||||
| -rw-r--r-- | engine/lib/users.php | 153 | ||||
| -rw-r--r-- | engine/lib/widgets.php | 22 | ||||
| -rw-r--r-- | engine/schema/upgrades/2009100701.sql | 29 | ||||
| -rw-r--r-- | engine/tests/api/entity_getter_functions.php | 311 | ||||
| -rw-r--r-- | engine/tests/objects/users.php | 131 | 
17 files changed, 909 insertions, 456 deletions
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,274 +409,62 @@ $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   * @param $entity_subtype @@ -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 "<acronym title=\"$timestamp\">$friendly_time</acronym>"; +	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 '<pre>';  		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 @@ -51,6 +51,19 @@ function register_notification_handler($method, $handler, $params = NULL) {  }  /** + * 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.   *   * @param mixed $to Either a guid or an array of guid's to notify. @@ -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 @@ +<?php +/* + * Conditional upgrade for UTF8 as described in http://trac.elgg.org/ticket/1928 + */ + +// get_version() returns the code version. +// we want the DB version. +$dbversion = (int) datalist_get('version'); + +// 2009100701 was the utf8 upgrade for 1.7. +// if we've already upgraded, don't try again. +if ($dbversion < 2009100701) { +	// if the default client connection is utf8 there is no reason +	// to run this upgrade because the strings are already stored correctly. + +	// start a new link to the DB to see what its defaults are. +	$link = mysql_connect($CONFIG->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 @@ +<?php +/** + * Pull admin metadata setting into users_entity table column + */ + +$siteadmin = get_metastring_id('siteadmin'); +$admin = get_metastring_id('admin'); +$yes = get_metastring_id('yes'); +$one = get_metastring_id('1'); + +$qs = array(); + +$qs[] = "ALTER TABLE {$CONFIG->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;  	} @@ -200,6 +201,46 @@ class ElggUser extends ElggEntity  	}  	/** +	 * 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  	 *  	 * @param string $subtype Optionally, the subtype of result we want to limit to @@ -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; @@ -283,6 +282,27 @@ function add_widget_type($handler, $name, $description, $context = "all", $multi  }  /** + * 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   *   * @param string $handler The widget handler identifying string diff --git a/engine/schema/upgrades/2009100701.sql b/engine/schema/upgrades/2009100701.sql index 0c89441d4..dbf52b4da 100644 --- a/engine/schema/upgrades/2009100701.sql +++ b/engine/schema/upgrades/2009100701.sql @@ -1,27 +1,2 @@ -SET NAMES utf8; - -ALTER TABLE `prefix_metastrings` DISABLE KEYS; -REPLACE INTO `prefix_metastrings` (id, string) -	SELECT id, unhex(hex(convert(string using latin1))) -	FROM `prefix_metastrings`; -ALTER TABLE `prefix_metastrings` ENABLE KEYS; - -ALTER TABLE `prefix_groups_entity` DISABLE KEYS; -REPLACE INTO `prefix_groups_entity` (guid, name, description) -	SELECT guid, unhex(hex(convert(name using latin1))), unhex(hex(convert(description using latin1))) -	FROM `prefix_groups_entity`; -ALTER TABLE `prefix_groups_entity` ENABLE KEYS; - -ALTER TABLE `prefix_objects_entity` DISABLE KEYS; -REPLACE INTO `prefix_objects_entity` (guid, title, description) -	SELECT guid, unhex(hex(convert(title using latin1))), unhex(hex(convert(description using latin1))) -	FROM `prefix_objects_entity`; -ALTER TABLE `prefix_objects_entity` ENABLE KEYS; - -ALTER TABLE `prefix_users_entity` DISABLE KEYS; -REPLACE INTO `prefix_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 `prefix_users_entity`; -ALTER TABLE `prefix_users_entity` ENABLE KEYS; +-- Previously was the UTF8 migration that is now in code at 2010033101. +-- Keeping this file to force an overwrite and to avoid confusion with missing migrations. diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php index 49fd4ec0d..1d7261c0d 100644 --- a/engine/tests/api/entity_getter_functions.php +++ b/engine/tests/api/entity_getter_functions.php @@ -1365,6 +1365,262 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {  		}  	} +	function testElggApiGettersEntityMetadataNVPValidNValidVEqualsTriple() { +		$subtypes = $this->getRandomValidSubtypes(array('object'), 1); +		$subtype = $subtypes[0]; +		$md_name = 'test_metadata_name_' . rand(); +		$md_value = 'test_metadata_value_' . rand(); + +		$md_name2 = 'test_metadata_name_' . rand(); +		$md_value2 = 'test_metadata_value_' . rand(); + +		$md_name3 = 'test_metadata_name_' . rand(); +		$md_value3 = 'test_metadata_value_' . rand(); + +		$guids = array(); + +		// our target +		$valid = new ElggObject(); +		$valid->subtype = $subtype; +		$valid->$md_name = $md_value; +		$valid->$md_name2 = $md_value2; +		$valid->$md_name3 = $md_value3; +		$valid->save(); +		$guids[] = $valid->getGUID(); + +		// make some bad ones +		$invalid_md_name = 'test_metadata_name_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->$md_name3 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$invalid_md_value = 'test_metadata_value_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->$md_name3 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$md_invalid_names = array(); + +		$options = array( +			'type' => 'object', +			'subtype' => $subtype, +			'metadata_name_value_pairs' => array( +				array( +					'name' => $md_name, +					'value' => $md_value +				), +				array( +					'name' => $md_name2, +					'value' => $md_value2 +				), +				array( +					'name' => $md_name3, +					'value' => $md_value3 +				) +			) +		); + +		$entities = elgg_get_entities_from_metadata($options); + +		$this->assertIsa($entities, 'array'); +		$this->assertEqual(count($entities), 1); + +		foreach ($entities as $entity) { +			$this->assertEqual($entity->getGUID(), $valid->getGUID()); +			$this->assertEqual($entity->$md_name, $md_value); +			$entity->delete(); +		} + +		foreach ($guids as $guid) { +			if ($e = get_entity($guid)) { +				$e->delete(); +			} +		} +	} + +	function testElggApiGettersEntityMetadataNVPValidNValidVEqualsDouble() { +		$subtypes = $this->getRandomValidSubtypes(array('object'), 1); +		$subtype = $subtypes[0]; +		$md_name = 'test_metadata_name_' . rand(); +		$md_value = 'test_metadata_value_' . rand(); + +		$md_name2 = 'test_metadata_name_' . rand(); +		$md_value2 = 'test_metadata_value_' . rand(); + +		$guids = array(); + +		// our target +		$valid = new ElggObject(); +		$valid->subtype = $subtype; +		$valid->$md_name = $md_value; +		$valid->$md_name2 = $md_value2; +		$valid->save(); +		$guids[] = $valid->getGUID(); + +		// make some bad ones +		$invalid_md_name = 'test_metadata_name_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$invalid_md_value = 'test_metadata_value_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$md_invalid_names = array(); + +		$options = array( +			'type' => 'object', +			'subtype' => $subtype, +			'metadata_name_value_pairs' => array( +				array( +					'name' => $md_name, +					'value' => $md_value +				), +				array( +					'name' => $md_name2, +					'value' => $md_value2 +				) +			) +		); + +		$entities = elgg_get_entities_from_metadata($options); + +		$this->assertIsa($entities, 'array'); +		$this->assertEqual(count($entities), 1); + +		foreach ($entities as $entity) { +			$this->assertEqual($entity->getGUID(), $valid->getGUID()); +			$this->assertEqual($entity->$md_name, $md_value); +			$entity->delete(); +		} + +		foreach ($guids as $guid) { +			if ($e = get_entity($guid)) { +				$e->delete(); +			} +		} +	} + +	function testElggApiGettersEntityMetadataNVPValidNValidVEqualsStupid() { +		$subtypes = $this->getRandomValidSubtypes(array('object'), 1); +		$subtype = $subtypes[0]; +		$md_name = 'test_metadata_name_' . rand(); +		$md_value = 'test_metadata_value_' . rand(); + +		$md_name2 = 'test_metadata_name_' . rand(); +		$md_value2 = 'test_metadata_value_' . rand(); + +		$md_name3 = 'test_metadata_name_' . rand(); +		$md_value3 = 'test_metadata_value_' . rand(); + +		$md_name3 = 'test_metadata_name_' . rand(); +		$md_value3 = 'test_metadata_value_' . rand(); + +		$md_name4 = 'test_metadata_name_' . rand(); +		$md_value4 = 'test_metadata_value_' . rand(); + +		$md_name5 = 'test_metadata_name_' . rand(); +		$md_value5 = 'test_metadata_value_' . rand(); + +		$guids = array(); + +		// our target +		$valid = new ElggObject(); +		$valid->subtype = $subtype; +		$valid->$md_name = $md_value; +		$valid->$md_name2 = $md_value2; +		$valid->$md_name3 = $md_value3; +		$valid->$md_name4 = $md_value4; +		$valid->$md_name5 = $md_value5; +		$valid->save(); +		$guids[] = $valid->getGUID(); + +		// make some bad ones +		$invalid_md_name = 'test_metadata_name_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->$md_name3 = $invalid_md_value; +		$e->$md_name4 = $invalid_md_value; +		$e->$md_name5 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$invalid_md_value = 'test_metadata_value_' . rand(); +		$e = new ElggObject(); +		$e->subtype = $subtype; +		$e->$md_name = $invalid_md_value; +		$e->$md_name2 = $invalid_md_value; +		$e->$md_name3 = $invalid_md_value; +		$e->$md_name4 = $invalid_md_value; +		$e->$md_name5 = $invalid_md_value; +		$e->save(); +		$guids[] = $e->getGUID(); + +		$md_invalid_names = array(); + +		$options = array( +			'type' => 'object', +			'subtype' => $subtype, +			'metadata_name_value_pairs' => array( +				array( +					'name' => $md_name, +					'value' => $md_value +				), +				array( +					'name' => $md_name2, +					'value' => $md_value2 +				), +				array( +					'name' => $md_name3, +					'value' => $md_value3 +				), +				array( +					'name' => $md_name4, +					'value' => $md_value4 +				), +				array( +					'name' => $md_name5, +					'value' => $md_value5 +				), +			) +		); + +		$entities = elgg_get_entities_from_metadata($options); + +		$this->assertIsa($entities, 'array'); +		$this->assertEqual(count($entities), 1); + +		foreach ($entities as $entity) { +			$this->assertEqual($entity->getGUID(), $valid->getGUID()); +			$this->assertEqual($entity->$md_name, $md_value); +			$entity->delete(); +		} + +		foreach ($guids as $guid) { +			if ($e = get_entity($guid)) { +				$e->delete(); +			} +		} +	} +  	function testElggApiGettersEntityMetadataNVPValidNInvalidV() {  		$subtypes = $this->getRandomValidSubtypes(array('object'), 1);  		$subtype = $subtypes[0]; @@ -1730,4 +1986,59 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {  			}  		}  	} + +	/** +	 * Annotations +	 */ +	public function testElggApiGettersEntitiesFromAnnotation() { + +		// grab a few different users to annotation +		// there will always be at least 2 here because of the construct. +		$users = elgg_get_entities(array('type' => 'user', 'limit' => 2)); + +		// create some test annotations +		$subtypes = $this->getRandomValidSubtypes(array('object'), 1); +		$subtype = $subtypes[0]; +		$annotation_name = 'test_annotation_name_' . rand(); +		$annotation_value = rand(1000, 9999); +		$annotation_name2 = 'test_annotation_name_' . rand(); +		$annotation_value2 = rand(1000, 9999); +		$guids = array(); + +		// our targets +		$valid = new ElggObject(); +		$valid->subtype = $subtype; +		$valid->save(); +		$guids[] = $valid->getGUID(); +		create_annotation($valid->getGUID(), $annotation_name, $annotation_value, 'integer', $users[0]->getGUID()); + +		$valid2 = new ElggObject(); +		$valid2->subtype = $subtype; +		$valid2->save(); +		$guids[] = $valid2->getGUID(); +		create_annotation($valid2->getGUID(), $annotation_name2, $annotation_value2, 'integer', $users[1]->getGUID()); + +		$options = array( +			'annotation_owner_guid' => $users[0]->getGUID(), +			'annotation_name' => $annotation_name +		); + +		$entities = elgg_get_entities_from_annotations($options); + +		foreach ($entities as $entity) { +			$this->assertTrue(in_array($entity->getGUID(), $guids)); +			$annotations = $entity->getAnnotations($annotation_name); +			$this->assertEqual(count($annotations), 1); + +			$this->assertEqual($annotations[0]->name, $annotation_name); +			$this->assertEqual($annotations[0]->value, $annotation_value); +			$this->assertEqual($annotations[0]->owner_guid, $users[0]->getGUID()); +		} + +		foreach ($guids as $guid) { +			if ($e = get_entity($guid)) { +				$e->delete(); +			} +		} +	}  } diff --git a/engine/tests/objects/users.php b/engine/tests/objects/users.php index c03091a91..d6d73a37b 100644 --- a/engine/tests/objects/users.php +++ b/engine/tests/objects/users.php @@ -14,7 +14,7 @@ class ElggCoreUserTest extends ElggCoreUnitTest {  	 */  	public function __construct() {  		parent::__construct(); -		 +  		// all code should come after here  	} @@ -31,7 +31,7 @@ class ElggCoreUserTest extends ElggCoreUnitTest {  	public function tearDown() {  		// do not allow SimpleTest to interpret Elgg notices as exceptions  		$this->swallowErrors(); -		 +  		unset($this->user);  	} @@ -68,17 +68,18 @@ class ElggCoreUserTest extends ElggCoreUnitTest {  		$attributes['language'] = '';  		$attributes['code'] = '';  		$attributes['banned'] = 'no'; -		 +		$attributes['admin'] = 'no'; +  		$this->assertIdentical($this->user->expose_attributes(), $attributes);  	} -	 +  	public function testElggUserLoad() {  		// new object  		$object = new ElggObject();  		$this->AssertEqual($object->getGUID(), 0);  		$guid = $object->save();  		$this->AssertNotEqual($guid, 0); -		 +  		// fail on wrong type  		try {  			$error = new ElggUserTest($guid); @@ -88,15 +89,15 @@ class ElggCoreUserTest extends ElggCoreUnitTest {  			$message = sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, 'ElggUser');  			$this->assertIdentical($e->getMessage(), $message);  		} -		 +  		// clean up  		$object->delete();  	} -	 +  	public function testElggUserConstructorByGuid() {  		$user = new ElggUser(get_loggedin_userid());  		$this->assertIdentical($user, $_SESSION['user']); -		 +  		// fail with garbage  		try {  			$error = new ElggUserTest(array('invalid')); @@ -107,57 +108,141 @@ class ElggCoreUserTest extends ElggCoreUnitTest {  			$this->assertIdentical($e->getMessage(), $message);  		}  	} -	 +  	public function testElggUserConstructorByDbRow() {  		$row = $this->fetchUser(get_loggedin_userid());  		$user = new ElggUser($row);  		$this->assertIdentical($user, $_SESSION['user']);  	} -	 +  	public function testElggUserConstructorByUsername() {  		$row = $this->fetchUser(get_loggedin_userid());  		$user = new ElggUser($row->username);  		$this->assertIdentical($user, $_SESSION['user']);  	} -		 +  	public function testElggUserSave() {  		// new object  		$this->AssertEqual($this->user->getGUID(), 0);  		$guid = $this->user->save();  		$this->AssertNotEqual($guid, 0); -		 +  		// clean up  		$this->user->delete();  	} -	 +  	public function testElggUserDelete() {  		$guid = $this->user->save(); -		 +  		// delete object  		$this->assertTrue($this->user->delete()); -		 +  		// check GUID not in database  		$this->assertFalse($this->fetchUser($guid));  	} -	 +  	public function testElggUserNameCache() {  		// Trac #1305 -		 +  		// very unlikely a user would have this username  		$name = (string)time();  		$this->user->username = $name; -		 +  		$guid = $this->user->save(); -		 -		$user = get_user_by_username($name);  -		$user->delete();  + +		$user = get_user_by_username($name); +		$user->delete();  		$user = get_user_by_username($name);  		$this->assertFalse($user);  	} -	 + + +	public function testElggUserMakeAdmin() { +		global $CONFIG; + +		// need to save user to have a guid +		$guid = $this->user->save(); + +		$this->assertTrue($this->user->makeAdmin()); + +		$q = "SELECT admin FROM {$CONFIG->dbprefix}users_entity WHERE guid = $guid"; +		$r = mysql_query($q); + +		$admin = mysql_fetch_assoc($r); +		$this->assertEqual($admin['admin'], 'yes'); + +		$this->user->delete(); +	} + +	public function testElggUserRemoveAdmin() { +		global $CONFIG; + +		// need to save user to have a guid +		$guid = $this->user->save(); + +		$this->assertTrue($this->user->removeAdmin()); + +		$q = "SELECT admin FROM {$CONFIG->dbprefix}users_entity WHERE guid = $guid"; +		$r = mysql_query($q); + +		$admin = mysql_fetch_assoc($r); +		$this->assertEqual($admin['admin'], 'no'); + +		$this->user->delete(); +	} + +	public function testElggUserIsAdmin() { +		// need to grab a real user with a guid and everything. +		$guid = $this->user->save(); + +		$this->assertTrue($this->user->makeAdmin()); + +		// this is testing the function, not the SQL. +		// that's been tested above. +		$this->assertTrue($this->user->isAdmin()); + +		$this->user->delete(); +	} + +	public function testElggUserIsNotAdmin() { +		// need to grab a real user with a guid and everything. +		$guid = $this->user->save(); + +		$this->assertTrue($this->user->removeAdmin()); + +		// this is testing the function, not the SQL. +		// that's been tested above. +		$this->assertFalse($this->user->isAdmin()); + +		$this->user->delete(); +	} + +	// remove in 1.9 +	public function testElggUserIsAdminLegacy() { +		$this->user->save(); +		$this->user->makeAdmin(); + +		$this->assertTrue($this->user->admin); +		$this->assertTrue($this->user->siteadmin); + +		$this->user->removeAdmin(); +		$this->user->delete(); +	} + +	public function testElggUserIsNotAdminLegacy() { +		$this->user->save(); +		$this->user->removeAdmin(); + +		$this->assertFalse($this->user->admin); +		$this->assertFalse($this->user->siteadmin); + +		$this->user->removeAdmin(); +		$this->user->delete(); +	} +  	protected function fetchUser($guid) {  		global $CONFIG; -		 +  		return get_data_row("SELECT * FROM {$CONFIG->dbprefix}users_entity WHERE guid = '$guid'");  	}  }  | 
