diff options
Diffstat (limited to 'engine/lib/access.php')
| -rw-r--r-- | engine/lib/access.php | 754 |
1 files changed, 396 insertions, 358 deletions
diff --git a/engine/lib/access.php b/engine/lib/access.php index 3eddd97ac..de0693ea8 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -1,9 +1,9 @@ <?php /** - * Primary function for Elgg's entity and metadata access systems. + * Functions for Elgg's access system for entities, metadata, and annotations. * * Access is generally saved in the database as access_id. This corresponds to - * one of the ACCESS_* constants defined in {@link elgglib.php}, or the ID of an + * one of the ACCESS_* constants defined in {@link elgglib.php} or the ID of an * access collection. * * @package Elgg.Core @@ -12,30 +12,51 @@ */ /** + * Return an ElggCache static variable cache for the access caches + * + * @staticvar ElggStaticVariableCache $access_cache + * @return \ElggStaticVariableCache + * @access private + */ +function _elgg_get_access_cache() { + /** + * A default filestore cache using the dataroot. + */ + static $access_cache; + + if (!$access_cache) { + $access_cache = new ElggStaticVariableCache('access'); + } + + return $access_cache; +} + +/** * Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause. * * @uses get_access_array * - * @return string A list of access collections suitable for injection in an SQL call * @link http://docs.elgg.org/Access * @see get_access_array() * * @param int $user_id User ID; defaults to currently logged in user * @param int $site_id Site ID; defaults to current site - * @param bool $flush If set to true, will refresh the access list from the database + * @param bool $flush If set to true, will refresh the access list from the + * database rather than using this function's cache. * - * @return string + * @return string A list of access collections suitable for using in an SQL call + * @access private */ function get_access_list($user_id = 0, $site_id = 0, $flush = false) { - global $CONFIG, $init_finished, $SESSION; - static $access_list; - - if (!isset($access_list) || !$init_finished) { - $access_list = array(); + global $CONFIG, $init_finished; + $cache = _elgg_get_access_cache(); + + if ($flush) { + $cache->clear(); } if ($user_id == 0) { - $user_id = $SESSION['id']; + $user_id = elgg_get_logged_in_user_guid(); } if (($site_id == 0) && (isset($CONFIG->site_id))) { @@ -44,40 +65,55 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (isset($access_list[$user_id])) { - return $access_list[$user_id]; - } + $hash = $user_id . $site_id . 'get_access_list'; - $access_list[$user_id] = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")"; + if ($cache[$hash]) { + return $cache[$hash]; + } + + $access_array = get_access_array($user_id, $site_id, $flush); + $access = "(" . implode(",", $access_array) . ")"; - return $access_list[$user_id]; + if ($init_finished) { + $cache[$hash] = $access; + } + + return $access; } /** * Returns an array of access IDs a user is permitted to see. * - * Can be overridden with the access:collections:read, user plugin hook. + * Can be overridden with the 'access:collections:read', 'user' plugin hook. + * + * This returns a list of all the collection ids a user owns or belongs + * to plus public and logged in access levels. If the user is an admin, it includes + * the private access level. * - * @param int $user_id User ID; defaults to currently logged in user - * @param int $site_id Site ID; defaults to current site - * @param boolean $flush If set to true, will refresh the access list from the database + * @internal this is only used in core for creating the SQL where clause when + * retrieving content from the database. The friends access level is handled by + * get_access_sql_suffix(). + * + * @see get_write_access_array() for the access levels that a user can write to. + * + * @param int $user_id User ID; defaults to currently logged in user + * @param int $site_id Site ID; defaults to current site + * @param bool $flush If set to true, will refresh the access ids from the + * database rather than using this function's cache. * * @return array An array of access collections ids - * @see get_access_list() */ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { global $CONFIG, $init_finished; - // @todo everything from the db is cached. - // this cache might be redundant. - static $access_array; + $cache = _elgg_get_access_cache(); - if (!isset($access_array) || (!isset($init_finished)) || (!$init_finished)) { - $access_array = array(); + if ($flush) { + $cache->clear(); } if ($user_id == 0) { - $user_id = get_loggedin_userid(); + $user_id = elgg_get_logged_in_user_guid(); } if (($site_id == 0) && (isset($CONFIG->site_guid))) { @@ -87,35 +123,41 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (empty($access_array[$user_id]) || $flush == true) { - $tmp_access_array = array(ACCESS_PUBLIC); + $hash = $user_id . $site_id . 'get_access_array'; + + if ($cache[$hash]) { + $access_array = $cache[$hash]; + } else { + $access_array = array(ACCESS_PUBLIC); // The following can only return sensible data if the user is logged in. - if (isloggedin()) { - $tmp_access_array[] = ACCESS_LOGGED_IN; + if (elgg_is_logged_in()) { + $access_array[] = ACCESS_LOGGED_IN; // Get ACL memberships $query = "SELECT am.access_collection_id" . " FROM {$CONFIG->dbprefix}access_collection_membership am" . " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id" - . " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; + . " WHERE am.user_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)"; - if ($collections = get_data($query)) { + $collections = get_data($query); + if ($collections) { foreach ($collections as $collection) { if (!empty($collection->access_collection_id)) { - $tmp_access_array[] = $collection->access_collection_id; + $access_array[] = (int)$collection->access_collection_id; } } } // Get ACLs owned. $query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag "; - $query .= "WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; + $query .= "WHERE ag.owner_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)"; - if ($collections = get_data($query)) { + $collections = get_data($query); + if ($collections) { foreach ($collections as $collection) { if (!empty($collection->id)) { - $tmp_access_array[] = $collection->id; + $access_array[] = (int)$collection->id; } } } @@ -123,21 +165,21 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { $ignore_access = elgg_check_access_overrides($user_id); if ($ignore_access == true) { - $tmp_access_array[] = ACCESS_PRIVATE; + $access_array[] = ACCESS_PRIVATE; } - - $access_array[$user_id] = $tmp_access_array; - } else { - // No user id logged in so we can only access public info - $tmp_return = $tmp_access_array; } - } else { - $tmp_access_array = $access_array[$user_id]; + if ($init_finished) { + $cache[$hash] = $access_array; + } } - $options = array('user_id' => $user_id, 'site_id' => $site_id); - return trigger_plugin_hook('access:collections:read', 'user', $options, $tmp_access_array); + $options = array( + 'user_id' => $user_id, + 'site_id' => $site_id + ); + + return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $access_array); } /** @@ -157,7 +199,7 @@ function get_default_access(ElggUser $user = null) { return $CONFIG->default_access; } - if (!($user) && (!$user = get_loggedin_user())) { + if (!($user) && (!$user = elgg_get_logged_in_user_entity())) { return $CONFIG->default_access; } @@ -180,11 +222,9 @@ $ENTITY_SHOW_HIDDEN_OVERRIDE = false; /** * Show or hide disabled entities. * - * @access private - * * @param bool $show_hidden Show disabled entities. - * * @return void + * @access private */ function access_show_hidden_entities($show_hidden) { global $ENTITY_SHOW_HIDDEN_OVERRIDE; @@ -194,8 +234,8 @@ function access_show_hidden_entities($show_hidden) { /** * Return current status of showing disabled entities. * - * @access private * @return bool + * @access private */ function access_get_show_hidden_status() { global $ENTITY_SHOW_HIDDEN_OVERRIDE; @@ -203,48 +243,11 @@ function access_get_show_hidden_status() { } /** - * Add annotation restriction - * - * Returns an SQL fragment that is true (or optionally false) if the given user has - * added an annotation with the given name to the given entity. - * - * @todo This is fairly generic so perhaps it could be moved to annotations.php - * - * @param string $annotation_name Name of the annotation - * @param string $entity_guid SQL GUID of entity the annotation is attached to. - * @param string $owner_guid SQL string that evaluates to the GUID of the annotation owner - * @param boolean $exists If true, returns BOOL if the annotation exists - * - * @return string An SQL fragment suitable for inserting into a WHERE clause - * @todo Document and maybe even remove. At least rename to something that makes sense. - */ -function get_annotation_sql($annotation_name, $entity_guid, $owner_guid, $exists) { - global $CONFIG; - - if ($exists) { - $not = ''; - } else { - $not = 'NOT'; - } - - $sql = <<<END -$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a -INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id) -WHERE ms.string = '$annotation_name' -AND a.entity_guid = $entity_guid -AND a.owner_guid = $owner_guid) -END; - return $sql; -} - -/** * Returns the SQL where clause for a table with a access_id and enabled columns. * - * This handles returning where clauses for ACCESS_FRIENDS, and the currently - * unused block and filter lists. - * - * @warning If an admin is logged in or {@link elgg_set_ignore_access()} is true, - * this will return blank. + * This handles returning where clauses for ACCESS_FRIENDS and the currently + * unused block and filter lists in addition to using get_access_list() for + * access collections and the standard access levels. * * @param string $table_prefix Optional table. prefix for the access code. * @param int $owner The guid to check access for. Defaults to logged in user. @@ -260,11 +263,11 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) { $enemies_bit = ""; if ($table_prefix) { - $table_prefix = sanitise_string($table_prefix) . "."; + $table_prefix = sanitise_string($table_prefix) . "."; } if (!isset($owner)) { - $owner = get_loggedin_userid(); + $owner = elgg_get_logged_in_user_guid(); } if (!$owner) { @@ -277,6 +280,7 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) { if ($ignore_access) { $sql = " (1 = 1) "; } else if ($owner != -1) { + // we have an entity's guid and auto check for friend relationships $friends_bit = "{$table_prefix}access_id = " . ACCESS_FRIENDS . " AND {$table_prefix}owner_guid IN ( SELECT guid_one FROM {$CONFIG->dbprefix}entity_relationships @@ -285,14 +289,15 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) { $friends_bit = '(' . $friends_bit . ') OR '; + // @todo untested and unsupported at present if ((isset($CONFIG->user_block_and_filter_enabled)) && ($CONFIG->user_block_and_filter_enabled)) { // check to see if the user is in the entity owner's block list // or if the entity owner is in the user's filter list // if so, disallow access - $enemies_bit = get_annotation_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false); + $enemies_bit = get_access_restriction_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false); $enemies_bit = '(' . $enemies_bit - . ' AND ' . get_annotation_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false) + . ' AND ' . get_access_restriction_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false) . ')'; } } @@ -319,19 +324,59 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) { } /** - * Can $user access $entity. + * Get the where clause for an access restriction based on annotations + * + * Returns an SQL fragment that is true (or optionally false) if the given user has + * added an annotation with the given name to the given entity. + * + * @warning this is a private function for an untested capability and will likely + * be removed from a future version of Elgg. + * + * @param string $annotation_name Name of the annotation + * @param string $entity_guid SQL GUID of entity the annotation is attached to. + * @param string $owner_guid SQL string that evaluates to the GUID of the annotation owner + * @param boolean $exists If true, returns BOOL if the annotation exists + * + * @return string An SQL fragment suitable for inserting into a WHERE clause + * @access private + */ +function get_access_restriction_sql($annotation_name, $entity_guid, $owner_guid, $exists) { + global $CONFIG; + + if ($exists) { + $not = ''; + } else { + $not = 'NOT'; + } + + $sql = <<<END +$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a +INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id) +WHERE ms.string = '$annotation_name' +AND a.entity_guid = $entity_guid +AND a.owner_guid = $owner_guid) +END; + return $sql; +} + +/** + * Can a user access an entity. * * @warning If a logged in user doesn't have access to an entity, the * core engine will not load that entity. * - * @tip This is mostly useful for checking if a 3rd user has access - * to an entity that is currently loaded. + * @tip This is mostly useful for checking if a user other than the logged in + * user has access to an entity that is currently loaded. + * + * @todo This function would be much more useful if we could pass the guid of the + * entity to test access for. We need to be able to tell whether the entity exists + * and whether the user has access to the entity. * * @param ElggEntity $entity The entity to check access for. * @param ElggUser $user Optionally user to check access for. Defaults to - * logged in user (which doesn't make sense). + * logged in user (which is a useless default). * - * @return boolean True if the user can access the entity + * @return bool * @link http://docs.elgg.org/Access */ function has_access_to_entity($entity, $user = null) { @@ -354,23 +399,41 @@ function has_access_to_entity($entity, $user = null) { } /** - * Returns an array of access permissions that the user is allowed to save objects with. - * Permissions are of the form ('id' => 'Description') + * Returns an array of access permissions that the user is allowed to save content with. + * Permissions returned are of the form (id => 'name'). + * + * Example return value in English: + * array( + * 0 => 'Private', + * -2 => 'Friends', + * 1 => 'Logged in users', + * 2 => 'Public', + * 34 => 'My favorite friends', + * ); + * + * Plugin hook of 'access:collections:write', 'user' + * + * @warning this only returns access collections that the user owns plus the + * standard access levels. It does not return access collections that the user + * belongs to such as the access collection for a group. * * @param int $user_id The user's GUID. * @param int $site_id The current site. - * @param bool $flush If this is set to true, this will ignore any cached version + * @param bool $flush If this is set to true, this will ignore a cached access array * * @return array List of access permissions * @link http://docs.elgg.org/Access */ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { - global $CONFIG; - //@todo this is probably not needed since caching happens at the DB level. - static $access_array; + global $CONFIG, $init_finished; + $cache = _elgg_get_access_cache(); + + if ($flush) { + $cache->clear(); + } if ($user_id == 0) { - $user_id = get_loggedin_userid(); + $user_id = elgg_get_logged_in_user_guid(); } if (($site_id == 0) && (isset($CONFIG->site_id))) { @@ -380,34 +443,78 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (empty($access_array[$user_id]) || $flush == true) { + $hash = $user_id . $site_id . 'get_write_access_array'; + + if ($cache[$hash]) { + $access_array = $cache[$hash]; + } else { + // @todo is there such a thing as public write access? + $access_array = array( + ACCESS_PRIVATE => elgg_echo("PRIVATE"), + ACCESS_FRIENDS => elgg_echo("access:friends:label"), + ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"), + ACCESS_PUBLIC => elgg_echo("PUBLIC") + ); + $query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag "; - $query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; - $query .= " AND (ag.owner_guid = {$user_id})"; - $query .= " AND ag.id >= 3"; - - $tmp_access_array = array( - ACCESS_PRIVATE => elgg_echo("PRIVATE"), - ACCESS_FRIENDS => elgg_echo("access:friends:label"), - ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"), - ACCESS_PUBLIC => elgg_echo("PUBLIC") - ); - if ($collections = get_data($query)) { + $query .= " WHERE (ag.site_guid = $site_id OR ag.site_guid = 0)"; + $query .= " AND (ag.owner_guid = $user_id)"; + + $collections = get_data($query); + if ($collections) { foreach ($collections as $collection) { - $tmp_access_array[$collection->id] = $collection->name; + $access_array[$collection->id] = $collection->name; } } - $access_array[$user_id] = $tmp_access_array; + if ($init_finished) { + $cache[$hash] = $access_array; + } + } + + $options = array( + 'user_id' => $user_id, + 'site_id' => $site_id + ); + return elgg_trigger_plugin_hook('access:collections:write', 'user', + $options, $access_array); +} + +/** + * Can the user change this access collection? + * + * Use the plugin hook of 'access:collections:write', 'user' to change this. + * @see get_write_access_array() for details on the hook. + * + * Respects access control disabling for admin users and {@see elgg_set_ignore_access()} + * + * @see get_write_access_array() + * + * @param int $collection_id The collection id + * @param mixed $user_guid The user GUID to check for. Defaults to logged in user. + * @return bool + */ +function can_edit_access_collection($collection_id, $user_guid = null) { + if ($user_guid) { + $user = get_entity((int) $user_guid); } else { - $tmp_access_array = $access_array[$user_id]; + $user = elgg_get_logged_in_user_entity(); + } + + $collection = get_access_collection($collection_id); + + if (!($user instanceof ElggUser) || !$collection) { + return false; } - $options = array('user_id' => $user_id, 'site_id' => $site_id); - $tmp_access_array = trigger_plugin_hook('access:collections:write', 'user', - $options, $tmp_access_array); + $write_access = get_write_access_array($user->getGUID(), 0, true); - return $tmp_access_array; + // don't ignore access when checking users. + if ($user_guid) { + return array_key_exists($collection_id, $write_access); + } else { + return elgg_get_ignore_access() || array_key_exists($collection_id, $write_access); + } } /** @@ -416,6 +523,8 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { * Access colletions allow plugins and users to create granular access * for entities. * + * Triggers plugin hook 'access:collections:addcollection', 'collection' + * * @internal Access collections are stored in the access_collections table. * Memberships to collections are in access_collections_membership. * @@ -423,7 +532,7 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { * @param int $owner_guid The GUID of the owner (default: currently logged in user). * @param int $site_guid The GUID of the site (default: current site). * - * @return int|false Depending on success (the collection ID if successful). + * @return int|false The collection ID if successful and false on failure. * @link http://docs.elgg.org/Access/Collections * @see update_access_collection() * @see delete_access_collection() @@ -437,7 +546,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { } if ($owner_guid == 0) { - $owner_guid = get_loggedin_userid(); + $owner_guid = elgg_get_logged_in_user_guid(); } if (($site_guid == 0) && (isset($CONFIG->site_guid))) { $site_guid = $CONFIG->site_guid; @@ -448,7 +557,8 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { SET name = '{$name}', owner_guid = {$owner_guid}, site_guid = {$site_guid}"; - if (!$id = insert_data($q)) { + $id = insert_data($q); + if (!$id) { return false; } @@ -456,7 +566,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { 'collection_id' => $id ); - if (!trigger_plugin_hook('access:collections:addcollection', 'collection', $params, true)) { + if (!elgg_trigger_plugin_hook('access:collections:addcollection', 'collection', $params, true)) { return false; } @@ -467,7 +577,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { * Updates the membership in an access collection. * * @warning Expects a full list of all members that should - * be part o the access collection + * be part of the access collection * * @note This will run all hooks associated with adding or removing * members to access collections. @@ -475,45 +585,36 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { * @param int $collection_id The ID of the collection. * @param array $members Array of member GUIDs * - * @return true|false Depending on success + * @return bool * @link http://docs.elgg.org/Access/Collections * @see add_user_to_access_collection() * @see remove_user_from_access_collection() */ function update_access_collection($collection_id, $members) { - global $CONFIG; + $acl = get_access_collection($collection_id); - $collection_id = (int) $collection_id; + if (!$acl) { + return false; + } $members = (is_array($members)) ? $members : array(); - $collections = get_write_access_array(); - - if (array_key_exists($collection_id, $collections)) { - $cur_members = get_members_of_access_collection($collection_id, true); - $cur_members = (is_array($cur_members)) ? $cur_members : array(); + $cur_members = get_members_of_access_collection($collection_id, true); + $cur_members = (is_array($cur_members)) ? $cur_members : array(); - $remove_members = array_diff($cur_members, $members); - $add_members = array_diff($members, $cur_members); - - $params = array( - 'collection_id' => $collection_id, - 'members' => $members, - 'add_members' => $add_members, - 'remove_members' => $remove_members - ); + $remove_members = array_diff($cur_members, $members); + $add_members = array_diff($members, $cur_members); - foreach ($add_members as $guid) { - add_user_to_access_collection($guid, $collection_id); - } + $result = true; - foreach ($remove_members as $guid) { - remove_user_from_access_collection($guid, $collection_id); - } + foreach ($add_members as $guid) { + $result = $result && add_user_to_access_collection($guid, $collection_id); + } - return true; + foreach ($remove_members as $guid) { + $result = $result && remove_user_from_access_collection($guid, $collection_id); } - return false; + return $result; } /** @@ -527,27 +628,25 @@ function update_access_collection($collection_id, $members) { * @see update_access_collection() */ function delete_access_collection($collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; - $collections = get_write_access_array(null, null, TRUE); $params = array('collection_id' => $collection_id); - if (!trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) { + if (!elgg_trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) { return false; } - if (array_key_exists($collection_id, $collections)) { - global $CONFIG; - $query = "delete from {$CONFIG->dbprefix}access_collection_membership" - . " where access_collection_id = {$collection_id}"; - delete_data($query); + // Deleting membership doesn't affect result of deleting ACL. + $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership + WHERE access_collection_id = {$collection_id}"; + delete_data($q); - $query = "delete from {$CONFIG->dbprefix}access_collections where id = {$collection_id}"; - delete_data($query); - return true; - } else { - return false; - } + $q = "DELETE FROM {$CONFIG->dbprefix}access_collections + WHERE id = {$collection_id}"; + $result = delete_data($q); + return (bool)$result; } /** @@ -556,9 +655,11 @@ function delete_access_collection($collection_id) { * @note This doesn't return the members of an access collection, * just the database row of the actual collection. * + * @see get_members_of_access_collection() + * * @param int $collection_id The collection ID * - * @return array|false + * @return object|false */ function get_access_collection($collection_id) { global $CONFIG; @@ -573,91 +674,88 @@ function get_access_collection($collection_id) { /** * Adds a user to an access collection. * - * Emits the access:collections:add_user, collection plugin hook. + * Triggers the 'access:collections:add_user', 'collection' plugin hook. * * @param int $user_guid The GUID of the user to add * @param int $collection_id The ID of the collection to add them to * - * @return true|false Depending on success - * @link http://docs.elgg.org/Access/Collections + * @return bool * @see update_access_collection() * @see remove_user_from_access_collection() + * @link http://docs.elgg.org/Access/Collections */ function add_user_to_access_collection($user_guid, $collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; $user_guid = (int) $user_guid; - $collections = get_write_access_array(); + $user = get_user($user_guid); - if (!($collection = get_access_collection($collection_id))) { + $collection = get_access_collection($collection_id); + + if (!($user instanceof Elgguser) || !$collection) { return false; } - if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0) - && $user = get_user($user_guid)) { - global $CONFIG; - - $params = array( - 'collection_id' => $collection_id, - 'user_guid' => $user_guid - ); - - if (!trigger_plugin_hook('access:collections:add_user', 'collection', $params, true)) { - return false; - } - - try { - $query = "insert into {$CONFIG->dbprefix}access_collection_membership" - . " set access_collection_id = {$collection_id}, user_guid = {$user_guid}"; - insert_data($queyr); - } catch (DatabaseException $e) { - // nothing. - } - return true; + $params = array( + 'collection_id' => $collection_id, + 'user_guid' => $user_guid + ); + $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true); + if ($result == false) { + return false; } - return false; + // if someone tries to insert the same data twice, we do a no-op on duplicate key + $q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership + SET access_collection_id = $collection_id, user_guid = $user_guid + ON DUPLICATE KEY UPDATE user_guid = user_guid"; + $result = insert_data($q); + + return $result !== false; } /** * Removes a user from an access collection. * - * Emits the access:collections:remove_user, collection plugin hook. + * Triggers the 'access:collections:remove_user', 'collection' plugin hook. * * @param int $user_guid The user GUID * @param int $collection_id The access collection ID * - * @return true|false Depending on success + * @return bool + * @see update_access_collection() + * @see remove_user_from_access_collection() + * @link http://docs.elgg.org/Access/Collections */ function remove_user_from_access_collection($user_guid, $collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; $user_guid = (int) $user_guid; - $collections = get_write_access_array(); - $user = $user = get_user($user_guid); + $user = get_user($user_guid); - if (!($collection = get_access_collection($collection_id))) { + $collection = get_access_collection($collection_id); + + if (!($user instanceof Elgguser) || !$collection) { return false; } - if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0) && $user) { - global $CONFIG; - $params = array( - 'collection_id' => $collection_id, - 'user_guid' => $user_guid - ); - - if (!trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) { - return false; - } - - delete_data("delete from {$CONFIG->dbprefix}access_collection_membership " - . "where access_collection_id = {$collection_id} and user_guid = {$user_guid}"); - - return true; + $params = array( + 'collection_id' => $collection_id, + 'user_guid' => $user_guid + ); + if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) { + return false; } - return false; + $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership + WHERE access_collection_id = {$collection_id} + AND user_guid = {$user_guid}"; + + return (bool)delete_data($q); } /** @@ -725,97 +823,13 @@ function get_members_of_access_collection($collection, $idonly = FALSE) { } /** - * Displays a user's access collections, using the friends/collections view - * - * @param int $owner_guid The GUID of the owning user - * - * @return string A formatted rendition of the collections - * @todo Move to the friends/collection.php page. - */ -function elgg_view_access_collections($owner_guid) { - if ($collections = get_user_access_collections($owner_guid)) { - foreach ($collections as $key => $collection) { - $collections[$key]->members = get_members_of_access_collection($collection->id, true); - $collections[$key]->entities = get_user_friends($owner_guid, "", 9999); - } - } - - return elgg_view('friends/collections', array('collections' => $collections)); -} - -/** - * Get entities with the specified access collection id. - * - * @deprecated 1.7. Use elgg_get_entities_from_access_id() - * - * @param int $collection_id ID of collection - * @param string $entity_type Type of entities - * @param string $entity_subtype Subtype of entities - * @param int $owner_guid Guid of owner - * @param int $limit Limit of number of entities to return - * @param int $offset Skip this many entities - * @param string $order_by Column to order by - * @param int $site_guid The site guid - * @param bool $count Return a count or entities - * - * @return array - */ -function get_entities_from_access_id($collection_id, $entity_type = "", $entity_subtype = "", - $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) { - // log deprecated warning - elgg_deprecated_notice('get_entities_from_access_id() was deprecated by elgg_get_entities()', 1.7); - - if (!$collection_id) { - return FALSE; - } - - // build the options using given parameters - $options = array(); - $options['limit'] = $limit; - $options['offset'] = $offset; - $options['count'] = $count; - - if ($entity_type) { - $options['type'] = sanitise_string($entity_type); - } - - if ($entity_subtype) { - $options['subtype'] = $entity_subtype; - } - - if ($site_guid) { - $options['site_guid'] = $site_guid; - } - - if ($order_by) { - $options['order_by'] = sanitise_string("e.time_created, $order_by"); - } - - if ($owner_guid) { - if (is_array($owner_guid)) { - $options['owner_guids'] = $owner_guid; - } else { - $options['owner_guid'] = $owner_guid; - } - } - - if ($site_guid) { - $options['site_guid'] = $site_guid; - } - - $options['access_id'] = $collection_id; - - return elgg_get_entities_from_access_id($options); -} - -/** * Return entities based upon access id. * - * @param array $options Any options accepted by {@link elgg_get_entities()} and: + * @param array $options Any options accepted by {@link elgg_get_entities()} and * access_id => int The access ID of the entity. * * @see elgg_get_entities() - * @return array + * @return mixed If count, int. If not count, array. false on errors. * @since 1.7.0 */ function elgg_get_entities_from_access_id(array $options = array()) { @@ -848,61 +862,37 @@ function elgg_get_entities_from_access_id(array $options = array()) { * @see elgg_list_entities() * @see elgg_get_entities_from_access_id() * - * @return str + * @return string */ function elgg_list_entities_from_access_id(array $options = array()) { return elgg_list_entities($options, 'elgg_get_entities_from_access_id'); } /** - * @return str - * @deprecated 1.8 Use elgg_list_entities_from_access_id() - */ -function list_entities_from_access_id($access_id, $entity_type = "", $entity_subtype = "", - $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true) { - - elgg_deprecated_notice("All list_entities* functions were deprecated in 1.8. Use elgg_list_entities* instead.", 1.8); - - echo elgg_list_entities_from_access_id(array( - 'access_id' => $access_id, - 'types' => $entity_type, - 'subtypes' => $entity_subtype, - 'owner_guids' => $owner_guid, - 'limit' => $limit, - 'full_view' => $fullview, - 'view_type_toggle' => $viewtypetoggle, - 'pagination' => $pagination, - )); -} - -/** * Return the name of an ACCESS_* constant or a access collection, * but only if the user has write access on that ACL. * * @warning This function probably doesn't work how it's meant to. * - * @param int $entity_accessid The entity's access id + * @param int $entity_access_id The entity's access id * - * @return string e.g. Public, Private etc + * @return string 'Public', 'Private', etc. * @since 1.7.0 * @todo I think this probably wants get_access_array() instead of get_write_access_array(), * but those two functions return different types of arrays. */ -function get_readable_access_level($entity_accessid) { - $access = (int) $entity_accessid; +function get_readable_access_level($entity_access_id) { + $access = (int) $entity_access_id; //get the access level for object in readable string $options = get_write_access_array(); - //@todo Really? Use array_key_exists() - foreach ($options as $key => $option) { - if ($key == $access) { - $entity_acl = htmlentities($option, ENT_QUOTES, 'UTF-8'); - return $entity_acl; - break; - } + if (array_key_exists($access, $options)) { + return $options[$access]; } - return false; + + // return 'Limited' if the user does not have access to the access collection + return elgg_echo('access:limited:label'); } /** @@ -911,13 +901,15 @@ function get_readable_access_level($entity_accessid) { * The access system will not return entities in any getter * functions if the user doesn't have access. * - * @internal For performance reasons this is done at the database level. + * @internal For performance reasons this is done at the database access clause level. * * @tip Use this to access entities in automated scripts * when no user is logged in. * - * @warning This will not show disabled entities. Use {@link $ENTITY_SHOW_HIDDEN_OVERRIDE} - * for that. + * @note This clears the access cache. + * + * @warning This will not show disabled entities. + * Use {@link access_show_hidden_entities()} to access disabled entities. * * @param bool $ignore If true, disables all access checks. * @@ -927,6 +919,8 @@ function get_readable_access_level($entity_accessid) { * @see elgg_get_ignore_access() */ function elgg_set_ignore_access($ignore = true) { + $cache = _elgg_get_access_cache(); + $cache->clear(); $elgg_access = elgg_get_access_object(); return $elgg_access->setIgnoreAccess($ignore); } @@ -944,17 +938,20 @@ function elgg_get_ignore_access() { } /** - * Decides if the access system is being ignored. + * Decides if the access system should be ignored for a user. + * + * Returns true (meaning ignore access) if either of these 2 conditions are true: + * 1) an admin user guid is passed to this function. + * 2) {@link elgg_get_ignore_access()} returns true. * - * The access system can be ignored if 1) an admin user is logged in - * or 2) {@link elgg_set_ignore_access()} was called with true. + * @see elgg_set_ignore_access() * - * @param mixed $user_guid The user to check against. Defaults to logged in. + * @param int $user_guid The user to check against. * * @return bool * @since 1.7.0 */ -function elgg_check_access_overrides($user_guid = null) { +function elgg_check_access_overrides($user_guid = 0) { if (!$user_guid || $user_guid <= 0) { $is_admin = false; } else { @@ -967,6 +964,7 @@ function elgg_check_access_overrides($user_guid = null) { /** * Returns the ElggAccess object. * + * // @todo comment is incomplete * This is used to * * @return ElggAccess @@ -988,7 +986,8 @@ function elgg_get_access_object() { * * @global bool $init_finished * @access private - * @todo investigate why this is needed + * @todo This is required to tell the access system to start caching because + * calls are made while in ignore access mode and before the user is logged in. */ $init_finished = false; @@ -1006,17 +1005,35 @@ function access_init() { } /** - * Check if the access system should be overridden. + * Overrides the access system if appropriate. * * Allows admin users and calls after {@link elgg_set_ignore_access} to - * by pass the access system. + * bypass the access system. + * + * Registered for the 'permissions_check', 'all' and the + * 'container_permissions_check', 'all' plugin hooks. * + * Returns true to override the access system or null if no change is needed. + * + * @param string $hook + * @param string $type + * @param bool $value + * @param array $params * @return true|null - * @since 1.7.0 - * @elgg_event_handler permissions_check all + * @access private */ -function elgg_override_permissions_hook() { - $user_guid = get_loggedin_userid(); +function elgg_override_permissions($hook, $type, $value, $params) { + $user = elgg_extract('user', $params); + if ($user) { + $user_guid = $user->getGUID(); + } else { + $user_guid = elgg_get_logged_in_user_guid(); + } + + // don't do this so ignore access still works with no one logged in + //if (!$user instanceof ElggUser) { + // return false; + //} // check for admin if ($user_guid && elgg_is_admin_user($user_guid)) { @@ -1032,9 +1049,30 @@ function elgg_override_permissions_hook() { return NULL; } -// This function will let us know when 'init' has finished -register_elgg_event_handler('init', 'system', 'access_init', 9999); +/** + * Runs unit tests for the entities object. + * + * @param string $hook + * @param string $type + * @param array $value + * @param array $params + * @return array + * + * @access private + */ +function access_test($hook, $type, $value, $params) { + global $CONFIG; + + $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php'; + return $value; +} + +// Tell the access functions the system has booted, plugins are loaded, +// and the user is logged in so it can start caching +elgg_register_event_handler('ready', 'system', 'access_init'); // For overrided permissions -register_plugin_hook('permissions_check', 'all', 'elgg_override_permissions_hook'); -register_plugin_hook('container_permissions_check', 'all', 'elgg_override_permissions_hook');
\ No newline at end of file +elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions'); +elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions'); + +elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test');
\ No newline at end of file |
