diff options
Diffstat (limited to 'engine/lib')
-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 |
14 files changed, 488 insertions, 406 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 |