diff options
Diffstat (limited to 'engine')
40 files changed, 1619 insertions, 377 deletions
diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index 6edc99dd4..2fa0d7b02 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -371,13 +371,18 @@ abstract class ElggEntity extends ElggData implements * Deletes all metadata on this object (metadata.entity_guid = $this->guid). * If you pass a name, only metadata matching that name will be deleted. * - * @warning Calling this with no or empty arguments will clear all metadata on the entity. + * @warning Calling this with no $name will clear all metadata on the entity. * - * @param null|string $name The metadata name to remove. + * @param null|string $name The name of the metadata to remove. * @return bool * @since 1.8 */ public function deleteMetadata($name = null) { + + if (!$this->guid) { + return false; + } + $options = array( 'guid' => $this->guid, 'limit' => 0 @@ -1432,11 +1437,7 @@ abstract class ElggEntity extends ElggData implements * @return true */ public function setLocation($location) { - $location = sanitise_string($location); - - $this->location = $location; - - return true; + return $this->location = $location; } /** @@ -1449,9 +1450,6 @@ abstract class ElggEntity extends ElggData implements * @todo Unimplemented */ public function setLatLong($lat, $long) { - $lat = sanitise_string($lat); - $long = sanitise_string($long); - $this->set('geo:lat', $lat); $this->set('geo:long', $long); diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php index fe25491a8..f21621ffd 100644 --- a/engine/classes/ElggFile.php +++ b/engine/classes/ElggFile.php @@ -121,6 +121,47 @@ class ElggFile extends ElggObject { } /** + * Detects mime types based on filename or actual file. + * + * @param mixed $file The full path of the file to check. For uploaded files, use tmp_name. + * @param mixed $default A default. Useful to pass what the browser thinks it is. + * @since 1.7.12 + * + * @return mixed Detected type on success, false on failure. + */ + static function detectMimeType($file = null, $default = null) { + if (!$file) { + if (isset($this) && $this->filename) { + $file = $this->filename; + } else { + return false; + } + } + + $mime = false; + + // for PHP5 folks. + if (function_exists('finfo_file') && defined('FILEINFO_MIME_TYPE')) { + $resource = finfo_open(FILEINFO_MIME_TYPE); + if ($resource) { + $mime = finfo_file($resource, $file); + } + } + + // for everyone else. + if (!$mime && function_exists('mime_content_type')) { + $mime = mime_content_type($file); + } + + // default + if (!$mime) { + return $default; + } + + return $mime; + } + + /** * Set the optional file description. * * @param string $description The description. diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index cfdc2f5fa..b9c81fd78 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -59,7 +59,7 @@ class ElggMenuItem { /** * @var string Tooltip */ - protected $title = ''; + protected $title = false; /** * @var string The string to display if link is clicked @@ -543,7 +543,7 @@ class ElggMenuItem { if ($this->data['linkClass']) { if (isset($vars['class'])) { - $vars['class'] += $this->getLinkClass(); + $vars['class'] = $vars['class'] . ' ' . $this->getLinkClass(); } else { $vars['class'] = $this->getLinkClass(); } @@ -552,6 +552,8 @@ class ElggMenuItem { if ($this->confirm) { $vars['confirm'] = $this->confirm; return elgg_view('output/confirmlink', $vars); + } else { + unset($vars['confirm']); } return elgg_view('output/url', $vars); diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index d837431fc..4aee1e898 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -116,6 +116,21 @@ class ElggPlugin extends ElggObject { } /** + * Returns the manifest's name if available, otherwise the ID. + * + * @return string + * @since 1.8.1 + */ + public function getFriendlyName() { + $manifest = $this->getManifest(); + if ($manifest) { + return $manifest->getName(); + } + + return $this->getID(); + } + + /** * Returns the plugin's full path with trailing slash. * * @return string @@ -597,7 +612,12 @@ class ElggPlugin extends ElggObject { */ public function canActivate($site_guid = null) { if ($this->getPackage()) { - return $this->getPackage()->isValid() && $this->getPackage()->checkDependencies(); + $result = $this->getPackage()->isValid() && $this->getPackage()->checkDependencies(); + if (!$result) { + $this->errorMsg = $this->getPackage()->getError(); + } + + return $result; } return false; diff --git a/engine/classes/ElggPluginManifest.php b/engine/classes/ElggPluginManifest.php index 0f3b1d7a8..0e47f388d 100644 --- a/engine/classes/ElggPluginManifest.php +++ b/engine/classes/ElggPluginManifest.php @@ -224,20 +224,15 @@ class ElggPluginManifest { /** * Returns the plugin name * - * @param bool $elgg_echo Run the name through elgg_echo. * @return string */ - public function getName($elgg_echo = true) { + public function getName() { $name = $this->parser->getAttribute('name'); if (!$name && $this->pluginID) { $name = ucwords(str_replace('_', ' ', $this->pluginID)); } - if ($elgg_echo) { - $name = elgg_echo($name); - } - return $name; } @@ -245,33 +240,21 @@ class ElggPluginManifest { /** * Return the description * - * @param bool $elgg_echo Run the description through elgg_echo. * @return string */ - public function getDescription($elgg_echo = true) { - $desc = $this->parser->getAttribute('description'); - - if ($elgg_echo) { - return elgg_echo($desc); - } else { - return $desc; - } + public function getDescription() { + return $this->parser->getAttribute('description'); } /** * Return the short description * - * @param bool $elgg_echo Run the blurb through elgg_echo. * @return string */ - public function getBlurb($elgg_echo = true) { + public function getBlurb() { $blurb = $this->parser->getAttribute('blurb'); - if ($blurb) { - if ($elgg_echo) { - $blurb = elgg_echo($blurb); - } - } else { + if (!$blurb) { $blurb = elgg_get_excerpt($this->getDescription()); } @@ -348,10 +331,9 @@ class ElggPluginManifest { /** * Return the screenshots listed. * - * @param bool $elgg_echo Run the screenshot's description through elgg_echo. * @return array */ - public function getScreenshots($elgg_echo = true) { + public function getScreenshots() { $ss = $this->parser->getAttribute('screenshot'); if (!$ss) { @@ -360,13 +342,7 @@ class ElggPluginManifest { $normalized = array(); foreach ($ss as $s) { - $normalized_s = $this->buildStruct($this->screenshotStruct, $s); - - if ($elgg_echo) { - $normalized_s['description'] = elgg_echo($normalized_s['description']); - } - - $normalized[] = $normalized_s; + $normalized[] = $this->buildStruct($this->screenshotStruct, $s); } return $normalized; diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php index 977b72d76..145f71fcd 100644 --- a/engine/classes/ElggPluginPackage.php +++ b/engine/classes/ElggPluginPackage.php @@ -334,7 +334,11 @@ class ElggPluginPackage { // first, check if any active plugin conflicts with us. foreach ($enabled_plugins as $plugin) { - $temp_conflicts = $plugin->getManifest()->getConflicts(); + $temp_conflicts = array(); + $temp_manifest = $plugin->getManifest(); + if ($temp_manifest instanceof ElggPluginManifest) { + $temp_conflicts = $plugin->getManifest()->getConflicts(); + } foreach ($temp_conflicts as $conflict) { if ($conflict['type'] == 'plugin' && $conflict['name'] == $this_id) { $result = $this->checkDepPlugin($conflict, $enabled_plugins, false); @@ -343,6 +347,7 @@ class ElggPluginPackage { $conflict['name'] = $plugin->getManifest()->getName(); if (!$full_report && !$result['status']) { + $this->errorMsg = "Conflicts with plugin \"{$plugin->getManifest()->getName()}\"."; return $result['status']; } else { $report[] = array( @@ -395,6 +400,7 @@ class ElggPluginPackage { // unless we're doing a full report, break as soon as we fail. if (!$full_report && !$result['status']) { + $this->errorMsg = "Missing dependencies."; return $result['status']; } else { // build report element and comment diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php new file mode 100644 index 000000000..aa33831ff --- /dev/null +++ b/engine/classes/ElggPriorityList.php @@ -0,0 +1,358 @@ +<?php +/** + * Iterate over elements in a specific priority. + * + * $pl = new ElggPriorityList(); + * $pl->add('Element 0'); + * $pl->add('Element 10', 10); + * $pl->add('Element -10', -10); + * + * foreach ($pl as $priority => $element) { + * var_dump("$priority => $element"); + * } + * + * Yields: + * -10 => Element -10 + * 0 => Element 0 + * 10 => Element 10 + * + * Collisions on priority are handled by inserting the element at or as close to the + * requested priority as possible: + * + * $pl = new ElggPriorityList(); + * $pl->add('Element 5', 5); + * $pl->add('Colliding element 5', 5); + * $pl->add('Another colliding element 5', 5); + * + * foreach ($pl as $priority => $element) { + * var_dump("$priority => $element"); + * } + * + * Yields: + * 5 => 'Element 5', + * 6 => 'Colliding element 5', + * 7 => 'Another colliding element 5' + * + * You can do priority lookups by element: + * + * $pl = new ElggPriorityList(); + * $pl->add('Element 0'); + * $pl->add('Element -5', -5); + * $pl->add('Element 10', 10); + * $pl->add('Element -10', -10); + * + * $priority = $pl->getPriority('Element -5'); + * + * Or element lookups by priority. + * $element = $pl->getElement(-5); + * + * To remove elements, pass the element. + * $pl->remove('Element -10'); + * + * To check if an element exists: + * $pl->contains('Element -5'); + * + * To move an element: + * $pl->move('Element -5', -3); + * + * ElggPriorityList only tracks priority. No checking is done in ElggPriorityList for duplicates or + * updating. If you need to track this use objects and an external map: + * + * function elgg_register_something($id, $display_name, $location, $priority = 500) { + * // $id => $element. + * static $map = array(); + * static $list; + * + * if (!$list) { + * $list = new ElggPriorityList(); + * } + * + * // update if already registered. + * if (isset($map[$id])) { + * $element = $map[$id]; + * // move it first because we have to pass the original element. + * if (!$list->move($element, $priority)) { + * return false; + * } + * $element->display_name = $display_name; + * $element->location = $location; + * } else { + * $element = new stdClass(); + * $element->display_name = $display_name; + * $element->location = $location; + * if (!$list->add($element, $priority)) { + * return false; + * } + * $map[$id] = $element; + * } + * + * return true; + * } + * + * @package Elgg.Core + * @subpackage Helpers + */ +class ElggPriorityList + implements Iterator, Countable { + + /** + * The list of elements + * + * @var array + */ + private $elements = array(); + + /** + * Create a new priority list. + * + * @param array $elements An optional array of priorities => element + */ + public function __construct(array $elements = array()) { + if ($elements) { + foreach ($elements as $priority => $element) { + $this->add($element, $priority); + } + } + } + + /** + * Adds an element to the list. + * + * @warning This returns the priority at which the element was added, which can be 0. Use + * !== false to check for success. + * + * @param mixed $element The element to add to the list. + * @param mixed $priority Priority to add the element. In priority collisions, the original element + * maintains its priority and the new element is to the next available + * slot, taking into consideration all previously registered elements. + * Negative elements are accepted. + * @return int The priority of the added element. + */ + public function add($element, $priority = null, $exact = false) { + if ($priority !== null && !is_numeric($priority)) { + return false; + } else { + $priority = $this->getNextPriority($priority); + } + + $this->elements[$priority] = $element; + $this->sorted = false; + return $priority; + } + + /** + * Removes an element from the list. + * + * @warning The element must have the same attributes / values. If using $strict, it must have + * the same types. array(10) will fail in strict against array('10') (str vs int). + * + * @param type $element + * @return bool + */ + public function remove($element, $strict = false) { + $index = array_search($element, $this->elements, $strict); + if ($index !== false) { + unset($this->elements[$index]); + return true; + } else { + return false; + } + } + + /** + * Move an existing element to a new priority. + * + * @param mixed $current_priority + * @param int $new_priority + * + * @return int The new priority. + */ + public function move($element, $new_priority, $strict = false) { + $new_priority = (int) $new_priority; + + $current_priority = $this->getPriority($element, $strict); + if ($current_priority === false) { + return false; + } + + if ($current_priority == $new_priority) { + return true; + } + + // move the actual element so strict operations still work + $element = $this->getElement($current_priority); + unset($this->elements[$current_priority]); + return $this->add($element, $new_priority); + } + + /** + * Returns the elements + * + * @return array + */ + public function getElements() { + $this->sortIfUnsorted(); + return $this->elements; + } + + /** + * Sort the elements optionally by a callback function. + * + * If no user function is provided the elements are sorted by priority registered. + * + * The callback function should accept the array of elements as the first argument and should + * return a sorted array. + * + * This function can be called multiple times. + * + * @param type $callback + * @return bool + */ + public function sort($callback = null) { + if (!$callback) { + ksort($this->elements, SORT_NUMERIC); + } else { + $sorted = call_user_func($callback, $this->elements); + + if (!$sorted) { + return false; + } + + $this->elements = $sorted; + } + + $this->sorted = true; + return true; + } + + /** + * Sort the elements if they haven't been sorted yet. + * + * @return bool + */ + private function sortIfUnsorted() { + if (!$this->sorted) { + return $this->sort(); + } + } + + /** + * Returns the next priority available. + * + * @param int $near Make the priority as close to $near as possible. + * @return int + */ + public function getNextPriority($near = 0) { + $near = (int) $near; + + while (array_key_exists($near, $this->elements)) { + $near++; + } + + return $near; + } + + /** + * Returns the priority of an element if it exists in the list. + * + * @warning This can return 0 if the element's priority is 0. + * + * @param mixed $element The element to check for. + * @param bool $strict Use strict checking? + * @return mixed False if the element doesn't exists, the priority if it does. + */ + public function getPriority($element, $strict = false) { + return array_search($element, $this->elements, $strict); + } + + /** + * Returns the element at $priority. + * + * @param int $priority + * @return mixed The element or false on fail. + */ + public function getElement($priority) { + return (isset($this->elements[$priority])) ? $this->elements[$priority] : false; + } + + /** + * Returns if the list contains $element. + * + * @param mixed $element The element to check. + * @param bool $strict Use strict checking? + * @return bool + */ + public function contains($element, $strict = false) { + return $this->getPriority($element, $strict) !== false; + } + + + /********************** + * Interface methods * + **********************/ + + /** + * Iterator + */ + + /** + * PHP Iterator Interface + * + * @see Iterator::rewind() + * @return void + */ + public function rewind() { + $this->sortIfUnsorted(); + return rewind($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::current() + * @return mixed + */ + public function current() { + $this->sortIfUnsorted(); + return current($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::key() + * @return int + */ + public function key() { + $this->sortIfUnsorted(); + return key($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::next() + * @return mixed + */ + public function next() { + $this->sortIfUnsorted(); + return next($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::valid() + * @return bool + */ + public function valid() { + $this->sortIfUnsorted(); + $key = key($this->elements); + return ($key !== NULL && $key !== FALSE); + } + + // Countable + public function count() { + return count($this->elements); + } +}
\ No newline at end of file diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index e3b8b8f1a..40bfca060 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -410,8 +410,9 @@ class ElggSite extends ElggEntity { 'register', 'action/register', 'forgotpassword', - 'action/user/requestnewpassword', 'resetpassword', + 'action/user/requestnewpassword', + 'action/user/passwordreset', 'upgrade\.php', 'xml-rpc\.php', 'mt/mt-xmlrpc\.cgi', diff --git a/engine/handlers/cache_handler.php b/engine/handlers/cache_handler.php index 7d6f42dc3..94a0e64e9 100644 --- a/engine/handlers/cache_handler.php +++ b/engine/handlers/cache_handler.php @@ -64,7 +64,7 @@ $view = $matches[3]; switch ($type) { case 'css': header("Content-type: text/css", true); - header('Expires: ' . date('r', time() + 86400000), true); + header('Expires: ' . date('r', strtotime("+6 months")), true); header("Pragma: public", true); header("Cache-Control: public", true); @@ -72,7 +72,7 @@ switch ($type) { break; case 'js': header('Content-type: text/javascript', true); - header('Expires: ' . date('r', time() + 864000000), true); + header('Expires: ' . date('r', strtotime("+6 months")), true); header("Pragma: public", true); header("Cache-Control: public", true); diff --git a/engine/lib/access.php b/engine/lib/access.php index cde3d256f..1fe21861d 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -410,6 +410,43 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { return $tmp_access_array; } + +/** + * Can the user write to the access collection? + * + * Hook into the access:collections:write, user to change this. + * + * 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 { + $user = get_loggedin_user(); + } + + $collection = get_access_collection($collection_id); + + if (!($user instanceof ElggUser) || !$collection) { + return false; + } + + $write_access = get_write_access_array($user->getGUID(), null, true); + + // 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); + } +} + /** * Creates a new access collection. * @@ -483,37 +520,30 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { function update_access_collection($collection_id, $members) { global $CONFIG; - $collection_id = (int) $collection_id; - $members = (is_array($members)) ? $members : array(); + $acl = get_access_collection($collection_id); - $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(); + if (!$acl) { + return false; + } + $members = (is_array($members)) ? $members : array(); - $remove_members = array_diff($cur_members, $members); - $add_members = array_diff($members, $cur_members); + $cur_members = get_members_of_access_collection($collection_id, true); + $cur_members = (is_array($cur_members)) ? $cur_members : array(); - $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 +557,26 @@ 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 (!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 $result; } /** @@ -584,45 +613,34 @@ function get_access_collection($collection_id) { * @see remove_user_from_access_collection() */ 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))) { - return false; - } + $collection = get_access_collection($collection_id); - $user = get_user($user_guid); - if (!$user) { + if (!($user instanceof Elgguser) || !$collection) { return false; } - // to add someone to a collection, the user must be a member of the collection or - // no one must own it - if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0)) { - $result = true; - } else { - $result = false; - } - $params = array( 'collection_id' => $collection_id, - 'collection' => $collection, 'user_guid' => $user_guid ); - $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, $result); + $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true); if ($result == false) { return false; } try { - global $CONFIG; - $query = "insert into {$CONFIG->dbprefix}access_collection_membership" - . " set access_collection_id = {$collection_id}, user_guid = {$user_guid}"; - insert_data($query); + $q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership + SET access_collection_id = {$collection_id}, + user_guid = {$user_guid}"; + insert_data($q); } catch (DatabaseException $e) { - // nothing. return false; } @@ -640,34 +658,32 @@ function add_user_to_access_collection($user_guid, $collection_id) { * @return true|false Depending on success */ 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); + + $collection = get_access_collection($collection_id); - if (!($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 (!elgg_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 delete_data($q); } /** @@ -760,7 +776,7 @@ function elgg_view_access_collections($owner_guid) { * access_id => int The access ID of the entity. * * @see elgg_get_entities() - * @return array + * @return mixed if count, int. if not count, array or false if no entities. false also on errors. * @since 1.7.0 */ function elgg_get_entities_from_access_id(array $options = array()) { @@ -939,8 +955,18 @@ function access_init() { * @since 1.7.0 * @elgg_event_handler permissions_check all */ -function elgg_override_permissions_hook() { - $user_guid = elgg_get_logged_in_user_guid(); +function elgg_override_permissions_hook($hook, $type, $value, $params) { + $user = elgg_extract('user', $params); + if (!$user) { + $user = elgg_get_logged_in_user_entity(); + } + + // don't do this so ignore access still works. +// if (!$user instanceof ElggUser) { +// return false; +// } + + $user_guid = $user->guid; // check for admin if ($user_guid && elgg_is_admin_user($user_guid)) { @@ -956,9 +982,20 @@ function elgg_override_permissions_hook() { return NULL; } +/** + * Runs unit tests for the entities object. + */ +function access_test($hook, $type, $value, $params) { + global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php'; + return $value; +} + // This function will let us know when 'init' has finished elgg_register_event_handler('init', 'system', 'access_init', 9999); // For overrided permissions elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions_hook'); elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions_hook'); + +elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test');
\ No newline at end of file diff --git a/engine/lib/actions.php b/engine/lib/actions.php index 4ccffd267..99e22e104 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -446,7 +446,17 @@ function ajax_forward_hook($hook, $type, $reason, $params) { $params['status'] = -1; } - header("Content-type: application/json"); + // Check the requester can accept JSON responses, if not fall back to + // returning JSON in a plain-text response. Some libraries request + // JSON in an invisible iframe which they then read from the iframe, + // however some browsers will not accept the JSON MIME type. + if (stripos($_SERVER['HTTP_ACCEPT'], 'application/json') === FALSE) { + header("Content-type: text/plain"); + } + else { + header("Content-type: application/json"); + } + echo json_encode($params); exit; } diff --git a/engine/lib/admin.php b/engine/lib/admin.php index c16da9295..93ee43008 100644 --- a/engine/lib/admin.php +++ b/engine/lib/admin.php @@ -239,6 +239,9 @@ function admin_init() { elgg_register_action('profile/fields/reorder', '', 'admin'); elgg_register_simplecache_view('js/admin'); + $url = elgg_get_simplecache_url('js', 'admin'); + elgg_register_js('elgg.admin', $url); + elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js'); // administer // dashboard @@ -434,11 +437,7 @@ function admin_settings_page_handler($page) { elgg_set_context('admin'); elgg_unregister_css('elgg'); - $url = elgg_get_simplecache_url('js', 'admin'); - elgg_register_js('elgg.admin', $url); elgg_load_js('elgg.admin'); - - elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js'); elgg_load_js('jquery.jeditable'); // default to dashboard @@ -548,9 +547,8 @@ function admin_markdown_page_handler($pages) { elgg_set_context('admin'); elgg_unregister_css('elgg'); - $url = elgg_get_simplecache_url('js', 'admin'); - elgg_register_js('elgg.admin', $url); elgg_load_js('elgg.admin'); + elgg_load_js('jquery.jeditable'); elgg_load_library('elgg:markdown'); $plugin_id = elgg_extract(0, $pages); diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 80ffbe74e..14893aee6 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -285,14 +285,12 @@ function elgg_list_annotations($options) { */ /** - * Returns entities based upon annotations. Accepts the same values as - * elgg_get_entities_from_metadata() but uses the annotations table. + * Returns entities based upon annotations. Also accepts all options available + * to elgg_get_entities() and elgg_get_entities_from_metadata(). * - * NB: Entity creation time is selected as max_time. To sort based upon + * Entity creation time is selected as max_time. To sort based upon * this, pass 'order_by' => 'maxtime asc' || 'maxtime desc' * - * time_created in this case will be the time the annotation was created. - * * @see elgg_get_entities * @see elgg_get_entities_from_metadata * @@ -321,7 +319,7 @@ function elgg_list_annotations($options) { * * annotation_ids => NULL|ARR Annotation IDs * - * @return array + * @return mixed if count, int. if not count, array or false if no entities. false also on errors. * @since 1.7.0 */ function elgg_get_entities_from_annotations(array $options = array()) { diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php index b756d2e70..3a2364057 100644 --- a/engine/lib/configuration.php +++ b/engine/lib/configuration.php @@ -464,11 +464,6 @@ function get_config($name, $site_guid = 0) { $dep_version = 1.8; break; - case 'wwwroot': - $new_name = 'www_root'; - $dep_version = 1.8; - break; - case 'sitename': $new_name = 'site_name'; $dep_version = 1.8; @@ -553,7 +548,7 @@ function set_default_config() { 'path' => "$install_root/", 'view_path' => "$install_root/views/", 'plugins_path' => "$install_root/mod/", - 'www_root' => $www_root, + 'wwwroot' => $www_root, 'url' => $www_root, 'site_name' => 'New Elgg site', 'language' => 'en', @@ -561,8 +556,6 @@ function set_default_config() { // compatibility with old names for ppl not using get_config() 'viewpath' => "$install_root/views/", 'pluginspath' => "$install_root/mod/", - 'wwwroot' => $www_root, - 'url' => $www_root, 'sitename' => 'New Elgg site', ); diff --git a/engine/lib/database.php b/engine/lib/database.php index 7747eb0d5..f12b50079 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -163,10 +163,17 @@ function db_delayedexecution_shutdown_hook() { global $DB_DELAYED_QUERIES; foreach ($DB_DELAYED_QUERIES as $query_details) { - // use one of our db functions so it is included in profiling. - $result = execute_query($query_details['q'], $query_details['l']); - try { + $link = $query_details['l']; + + if ($link == 'read' || $link == 'write') { + $link = get_db_link($link); + } elseif (!is_resource($link)) { + elgg_log("Link for delayed query not valid resource or db_link type. Query: {$query_details['q']}", 'WARNING'); + } + + $result = execute_query($query_details['q'], $link); + if ((isset($query_details['h'])) && (is_callable($query_details['h']))) { $query_details['h']($result); } @@ -272,7 +279,7 @@ function execute_query($query, $dblink) { * the raw result from {@link mysql_query()}. * * @param string $query The query to execute - * @param resource $dblink The database link to use + * @param resource $dblink The database link to use or the link type (read | write) * @param string $handler A callback function to pass the results array to * * @return true @@ -284,6 +291,10 @@ function execute_delayed_query($query, $dblink, $handler = "") { $DB_DELAYED_QUERIES = array(); } + if (!is_resource($dblink) && $dblink != 'read' && $dblink != 'write') { + return false; + } + // Construct delayed query $delayed_query = array(); $delayed_query['q'] = $query; @@ -306,7 +317,7 @@ function execute_delayed_query($query, $dblink, $handler = "") { * @uses get_db_link() */ function execute_delayed_write_query($query, $handler = "") { - return execute_delayed_query($query, get_db_link('write'), $handler); + return execute_delayed_query($query, 'write', $handler); } /** @@ -320,7 +331,7 @@ function execute_delayed_write_query($query, $handler = "") { * @uses get_db_link() */ function execute_delayed_read_query($query, $handler = "") { - return execute_delayed_query($query, get_db_link('read'), $handler); + return execute_delayed_query($query, 'read', $handler); } /** diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php index ff4fa0756..beba7d2b7 100644 --- a/engine/lib/deprecated-1.8.php +++ b/engine/lib/deprecated-1.8.php @@ -1146,7 +1146,7 @@ function get_entities_from_metadata_groups_multi($group_guid, $meta_array, $enti * @param bool $navigation Display pagination? Default: true * * @return string A viewable list of entities - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_entities_from_location() */ function list_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) { elgg_deprecated_notice('list_entities_in_area() was deprecated. Use elgg_list_entities_from_location()', 1.8); @@ -1195,7 +1195,7 @@ function list_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", * @param bool $navigation Display pagination? Default: true * * @return string A viewable list of entities - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_list_entities_from_location() */ function list_entities_location($location, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) { elgg_deprecated_notice('list_entities_location() was deprecated. Use elgg_list_entities_from_metadata()', 1.8); @@ -1220,7 +1220,7 @@ function list_entities_location($location, $type = "", $subtype = "", $owner_gui * @param int|array $container_guid Container GUID * * @return array A list of entities. - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_entities_from_location() */ function get_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = NULL) { elgg_deprecated_notice('get_entities_in_area() was deprecated by elgg_get_entities_from_location()!', 1.8); @@ -1369,7 +1369,7 @@ function list_entities_from_metadata_multi($meta_array, $entity_type = "", $enti * Deprecated by elgg_register_menu_item(). Set $menu_name to 'page'. * * @see elgg_register_menu_item() - * @deprecated 1.8 + * @deprecated 1.8 Use the new menu system * * @param string $label The label * @param string $link The link @@ -1411,7 +1411,7 @@ function add_submenu_item($label, $link, $group = 'default', $onclick = false, $ /** * Remove an item from submenu by label * - * @deprecated 1.8 + * @deprecated 1.8 Use the new menu system * @see elgg_unregister_menu_item() * * @param string $label The item label @@ -1429,7 +1429,7 @@ function remove_submenu_item($label, $group = 'a') { * Use elgg_view_menu(). Set $menu_name to 'owner_block'. * * @see elgg_view_menu() - * @deprecated 1.8 + * @deprecated 1.8 Use the new menu system. elgg_view_menu() * * @return string */ @@ -1465,7 +1465,7 @@ function add_menu($menu_name, $menu_url, $menu_children = array(), $context = "" * @param string $menu_name The name of the menu item * * @return true|false Depending on success - * @deprecated 1.8 + * @deprecated 1.8 Use the new menu system */ function remove_menu($menu_name) { elgg_deprecated_notice("remove_menu() deprecated by elgg_unregister_menu_item()", 1.8); @@ -1478,7 +1478,7 @@ function remove_menu($menu_name) { * @param string $title The title * * @return string The optimised title - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_friendly_title() */ function friendly_title($title) { elgg_deprecated_notice('friendly_title was deprecated by elgg_get_friendly_title', 1.8); @@ -1491,7 +1491,7 @@ function friendly_title($title) { * @param int $time A UNIX epoch timestamp * * @return string The friendly time - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_view_friendly_time() */ function friendly_time($time) { elgg_deprecated_notice('friendly_time was deprecated by elgg_view_friendly_time', 1.8); @@ -1501,7 +1501,7 @@ function friendly_time($time) { /** * Filters a string into an array of significant words * - * @deprecated 1.8 + * @deprecated 1.8 Don't use this. * * @param string $string A string * @@ -1539,7 +1539,7 @@ function filter_string($string) { /** * Returns true if the word in $input is considered significant * - * @deprecated 1.8 + * @deprecated 1.8 Don't use this. * * @param string $input A word * @@ -1576,7 +1576,7 @@ function page_owner() { /** * Gets the owner entity for the current page. * - * @deprecated 1.8 Use elgg_get_page_owner() + * @deprecated 1.8 Use elgg_get_page_owner_entity() * @return ElggEntity|false The current page owner or false if none. */ function page_owner_entity() { @@ -1645,7 +1645,7 @@ function get_context() { /** * Returns a list of plugins to load, in the order that they should be loaded. * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_plugin_ids_in_dir() or elgg_get_plugins() * * @return array List of plugins */ @@ -1676,7 +1676,7 @@ function get_plugin_list() { * elgg_regenerate_simplecache(); * elgg_filepath_cache_reset(); * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_generate_plugin_entities() and elgg_set_plugin_priorities() * * @param array $pluginorder Optionally, a list of existing plugins and their orders * @@ -1708,7 +1708,7 @@ function regenerate_plugin_list($pluginorder = FALSE) { * * i.e., if the last plugin was in /mod/foobar/, get_plugin_name would return foo_bar. * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_calling_plugin_id() * * @param boolean $mainfilename If set to true, this will instead determine the * context from the main script filename called by @@ -1727,7 +1727,7 @@ function get_plugin_name($mainfilename = false) { * * @example plugins/manifest.xml Example 1.8-style manifest file. * - * @deprecated 1.8 + * @deprecated 1.8 Use ElggPlugin->getManifest() * * @param string $plugin Plugin name. * @return array of values @@ -1750,7 +1750,7 @@ function load_plugin_manifest($plugin) { * This function checks a plugin manifest 'elgg_version' value against the current install * returning TRUE if the elgg_version is >= the current install's version. * - * @deprecated 1.8 + * @deprecated 1.8 Use ElggPlugin->canActivate() * * @param string $manifest_elgg_version_string The build version (eg 2009010201). * @return bool @@ -1773,7 +1773,7 @@ function check_plugin_compatibility($manifest_elgg_version_string) { /** * Shorthand function for finding the plugin settings. * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id() * * @param string $plugin_id Optional plugin id, if not specified * then it is detected from where you are calling. @@ -1792,7 +1792,7 @@ function find_plugin_settings($plugin_id = null) { /** * Return an array of installed plugins. * - * @deprecated 1.8 + * @deprecated 1.8 use elgg_get_plugins() * * @param string $status any|enabled|disabled * @return array @@ -1843,7 +1843,7 @@ function get_installed_plugins($status = 'all') { * elgg_regenerate_simplecache(); * elgg_filepath_cache_reset(); * - * @deprecated 1.8 + * @deprecated 1.8 Use ElggPlugin->activate() * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. @@ -1884,7 +1884,7 @@ function enable_plugin($plugin, $site_guid = null) { * elgg_regenerate_simplecache(); * elgg_filepath_cache_reset(); * - * @deprecated 1.8 + * @deprecated 1.8 Use ElggPlugin->deactivate() * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. @@ -1915,7 +1915,7 @@ function disable_plugin($plugin, $site_guid = 0) { /** * Return whether a plugin is enabled or not. * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_is_active_plugin() * * @param string $plugin The plugin name. * @param int $site_guid The site id, if not specified then this is detected. @@ -1943,7 +1943,7 @@ function is_plugin_enabled($plugin, $site_guid = 0) { * @param mixed $container_guid The container(s) GUIDs * * @return array A list of entities. - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_entities_from_private_settings() */ function get_entities_from_private_setting($name = "", $value = "", $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, @@ -2022,13 +2022,13 @@ $container_guid = null) { * @param mixed $container_guid Container GUID * * @return array A list of entities. - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_entities_from_private_settings() */ function get_entities_from_private_setting_multi(array $name, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) { - elgg_deprecated_notice('get_entities_from_private_setting_multi() was deprecated by elgg_get_entities_from_private_setting()!', 1.8); + elgg_deprecated_notice('get_entities_from_private_setting_multi() was deprecated by elgg_get_entities_from_private_settings()!', 1.8); $options = array(); @@ -2194,7 +2194,7 @@ $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_ /** * Displays a human-readable list of entities * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_list_entities_from_relationship_count() * * @param string $relationship The relationship eg "friends_of" * @param bool $inverse_relationship Inverse relationship owners @@ -2245,7 +2245,7 @@ $listtypetoggle = false, $pagination = true) { * Gets the number of entities by a the number of entities related to * them in a particular way also constrained by metadata. * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_entities_from_relationship() * * @param string $relationship The relationship eg "friends_of" * @param int $relationship_guid The guid of the entity to use query @@ -2337,7 +2337,7 @@ $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_ * @param int $posted_max The maximum time period to look at. Default: none * * @return array|false Depending on success - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_river() */ function get_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '', $type = '', $subtype = '', $action_type = '', $limit = 20, $offset = 0, $posted_min = 0, @@ -2404,7 +2404,7 @@ $posted_max = 0) { * @param bool $pagination Show pagination? * * @return string Human-readable river. - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_list_river() */ function elgg_view_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '', $type = '', $subtype = '', $action_type = '', $limit = 20, $posted_min = 0, @@ -2424,7 +2424,7 @@ $posted_max = 0, $pagination = true) { 'offset' => $offset, 'limit' => $limit, 'pagination' => $pagination, - 'list-class' => 'elgg-river-list', + 'list-class' => 'elgg-list-river', ); return elgg_view('page/components/list', $params); @@ -2433,7 +2433,8 @@ $posted_max = 0, $pagination = true) { /** * Construct and execute the query required for the activity stream. * - * @deprecated 1.8 + * @deprecated 1.8 This is outdated and uses the systemlog table instead of the river table. + * Don't use it. */ function get_activity_stream_data($limit = 10, $offset = 0, $type = "", $subtype = "", $owner_guid = "", $owner_relationship = "") { @@ -2668,7 +2669,7 @@ function list_site_members($site_guid, $limit = 10, $fullview = true) { * @param int $collection_guid Collection GUID * * @return mixed - * @deprecated 1.8 + * @deprecated 1.8 Don't use this. */ function add_site_collection($site_guid, $collection_guid) { elgg_deprecated_notice("add_site_collection has been deprecated", 1.8); @@ -2687,7 +2688,7 @@ function add_site_collection($site_guid, $collection_guid) { * @param int $collection_guid Collection GUID * * @return mixed - * @deprecated 1.8 + * @deprecated 1.8 Don't use this. */ function remove_site_collection($site_guid, $collection_guid) { elgg_deprecated_notice("remove_site_collection has been deprecated", 1.8); @@ -2706,7 +2707,7 @@ function remove_site_collection($site_guid, $collection_guid) { * @param int $offset Offset * * @return mixed - * @deprecated 1.8 + * @deprecated 1.8 Don't use this. */ function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset = 0) { elgg_deprecated_notice("get_site_collections has been deprecated", 1.8); @@ -2944,7 +2945,7 @@ $limit = 0, $offset = 0) { * @param bool $status Validated (true) or false * @param string $method Optional method to say how a user was validated * @return bool - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_set_user_validation_status() */ function set_user_validation_status($user_guid, $status, $method = '') { elgg_deprecated_notice("set_user_validation_status() is deprecated", 1.8); @@ -2957,7 +2958,7 @@ function set_user_validation_status($user_guid, $status, $method = '') { * This function invalidates any existing validation value. * * @param int $user_guid User's GUID - * @deprecated 1.8 + * @deprecated 1.8 Hook into the register, user plugin hook and request validation. */ function request_user_validation($user_guid) { elgg_deprecated_notice("request_user_validation() is deprecated. @@ -3314,7 +3315,7 @@ function clear_all_plugin_settings($plugin_id = "") { * @param int $entity_owner_guid Owner guid for the entity * * @return array - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_annotations() */ function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0, @@ -3379,7 +3380,7 @@ $timeupper = 0, $entity_owner_guid = 0) { * @param true|false $asc Display annotations in ascending order. (Default: true) * * @return string HTML (etc) version of the annotation list - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_list_annotations() */ function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) { elgg_deprecated_notice('list_annotations() is deprecated by elgg_list_annotations()', 1.8); @@ -3412,7 +3413,7 @@ function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) { * @param unknown_type $timelower * @param unknown_type $timeupper * @param unknown_type $calculation - * @deprecated 1.8 + * @internal Don't use this at all. */ function elgg_deprecated_annotation_calculation($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0, @@ -3590,7 +3591,7 @@ $value = "", $value_type = "", $owner_guid = 0) { * @param int $timeupper Upper time limit * * @return int - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_get_annotations() and pass anntoation_calculation => <calculation> */ function get_annotations_calculate_x($sum = "avg", $entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0, @@ -4501,7 +4502,7 @@ function save_widget_info($widget_guid, $params) { * @param int $owner Owner guid * * @return void - * @deprecated 1.8 + * @deprecated 1.8 Don't use. */ function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3, $context, $owner) { elgg_deprecated_notice("reorder_widgets_from_panel() is deprecated", 1.8); @@ -4609,7 +4610,7 @@ function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3, * @param string $context The context we wish to enable context for * * @return void - * @deprecated 1.8 + * @deprecated 1.8 Don't use. */ function use_widgets($context) { elgg_deprecated_notice("use_widgets is deprecated", 1.8); @@ -4632,7 +4633,7 @@ function use_widgets($context) { * Determines whether or not the current context is using widgets * * @return bool Depending on widget status - * @deprecated 1.8 + * @deprecated 1.8 Don't use. */ function using_widgets() { elgg_deprecated_notice("using_widgets is deprecated", 1.8); @@ -4654,7 +4655,7 @@ function using_widgets() { * @param ElggObject $widget The widget to display * @return string The HTML for the widget, including JavaScript wrapper * - * @deprecated 1.8 + * @deprecated 1.8 Use elgg_view_entity() */ function display_widget(ElggObject $widget) { elgg_deprecated_notice("display_widget() was been deprecated. Use elgg_view_entity().", 1.8); diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index cb736f418..64bdf9276 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -143,9 +143,9 @@ function forward($location = "", $reason = 'system') { } else if ($location === '') { exit; } + } else { + throw new SecurityException(elgg_echo('SecurityException:ForwardFailedToRedirect')); } - - return false; } /** @@ -167,12 +167,12 @@ function forward($location = "", $reason = 'system') { * @param string $name An identifier for the JavaScript library * @param string $url URL of the JavaScript file * @param string $location Page location: head or footer. (default: head) - * @param int $priority Priority of the CSS file (lower numbers load earlier) + * @param int $priority Priority of the JS file (lower numbers load earlier) * * @return bool * @since 1.8.0 */ -function elgg_register_js($name, $url, $location = 'head', $priority = 500) { +function elgg_register_js($name, $url, $location = 'head', $priority = null) { return elgg_register_external_file('js', $name, $url, $location, $priority); } @@ -225,7 +225,7 @@ function elgg_get_loaded_js($location = 'head') { * @return bool * @since 1.8.0 */ -function elgg_register_css($name, $url, $priority = 500) { +function elgg_register_css($name, $url, $priority = null) { return elgg_register_external_file('css', $name, $url, 'head', $priority); } @@ -288,32 +288,44 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = $url = elgg_format_url($url); $url = elgg_normalize_url($url); - if (!isset($CONFIG->externals)) { - $CONFIG->externals = array(); - } + elgg_bootstrap_externals_data_structure($type); - if (!isset($CONFIG->externals[$type])) { - $CONFIG->externals[$type] = array(); + $name = trim(strtolower($name)); + + // normalize bogus priorities, but allow empty, null, and false to be defaults. + if (!is_numeric($priority)) { + $priority = 500; } - $name = trim(strtolower($name)); + // no negative priorities right now. + $priority = max((int)$priority, 0); - if (isset($CONFIG->externals[$type][$name])) { - // update a registered item - $item = $CONFIG->externals[$type][$name]; + $item = elgg_extract($name, $CONFIG->externals_map[$type]); + + if ($item) { + // updating a registered item + // don't update loaded because it could already be set + $item->url = $url; + $item->location = $location; + // if loaded before registered, that means it hasn't been added to the list yet + if ($CONFIG->externals[$type]->contains($item)) { + $priority = $CONFIG->externals[$type]->move($item, $priority); + } else { + $priority = $CONFIG->externals[$type]->add($item, $priority); + } } else { $item = new stdClass(); $item->loaded = false; - } + $item->url = $url; + $item->location = $location; - $item->url = $url; - $item->priority = max((int)$priority, 0); - $item->location = $location; + $priority = $CONFIG->externals[$type]->add($item, $priority); + } - $CONFIG->externals[$type][$name] = $item; + $CONFIG->externals_map[$type][$name] = $item; - return true; + return $priority !== false; } /** @@ -328,19 +340,14 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = function elgg_unregister_external_file($type, $name) { global $CONFIG; - if (!isset($CONFIG->externals)) { - return false; - } - - if (!isset($CONFIG->externals[$type])) { - return false; - } + elgg_bootstrap_externals_data_structure($type); $name = trim(strtolower($name)); - - if (array_key_exists($name, $CONFIG->externals[$type])) { - unset($CONFIG->externals[$type][$name]); - return true; + $item = elgg_extract($name, $CONFIG->externals_map[$type]); + + if ($item) { + unset($CONFIG->externals_map[$type][$name]); + return $CONFIG->externals[$type]->remove($item); } return false; @@ -358,27 +365,23 @@ function elgg_unregister_external_file($type, $name) { function elgg_load_external_file($type, $name) { global $CONFIG; - if (!isset($CONFIG->externals)) { - $CONFIG->externals = array(); - } - - if (!isset($CONFIG->externals[$type])) { - $CONFIG->externals[$type] = array(); - } + elgg_bootstrap_externals_data_structure($type); $name = trim(strtolower($name)); - if (isset($CONFIG->externals[$type][$name])) { + $item = elgg_extract($name, $CONFIG->externals_map[$type]); + + if ($item) { // update a registered item - $CONFIG->externals[$type][$name]->loaded = true; + $item->loaded = true; } else { $item = new stdClass(); $item->loaded = true; $item->url = ''; $item->location = ''; - $item->priority = 500; - $CONFIG->externals[$type][$name] = $item; + $priority = $CONFIG->externals[$type]->add($item); + $CONFIG->externals_map[$type][$name] = $item; } } @@ -394,13 +397,12 @@ function elgg_load_external_file($type, $name) { function elgg_get_loaded_external_files($type, $location) { global $CONFIG; - if (isset($CONFIG->externals) && isset($CONFIG->externals[$type])) { - $items = array_values($CONFIG->externals[$type]); + if (isset($CONFIG->externals) && $CONFIG->externals[$type] instanceof ElggPriorityList) { + $items = $CONFIG->externals[$type]->getElements(); $callback = "return \$v->loaded == true && \$v->location == '$location';"; $items = array_filter($items, create_function('$v', $callback)); if ($items) { - usort($items, create_function('$a,$b','return $a->priority >= $b->priority;')); array_walk($items, create_function('&$v,$k', '$v = $v->url;')); } return $items; @@ -409,6 +411,31 @@ function elgg_get_loaded_external_files($type, $location) { } /** + * Bootstraps the externals data structure in $CONFIG. + * + * @param string $type The type of external, js or css. + */ +function elgg_bootstrap_externals_data_structure($type) { + global $CONFIG; + + if (!isset($CONFIG->externals)) { + $CONFIG->externals = array(); + } + + if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { + $CONFIG->externals[$type] = new ElggPriorityList(); + } + + if (!isset($CONFIG->externals_map)) { + $CONFIG->externals_map = array(); + } + + if (!isset($CONFIG->externals_map[$type])) { + $CONFIG->externals_map[$type] = array(); + } +} + +/** * Returns a list of files in $directory. * * Only returns files. Does not recurse into subdirs. @@ -2004,7 +2031,10 @@ function elgg_init() { elgg_register_js('elgg.userpicker', 'js/lib/userpicker.js'); elgg_register_js('elgg.friendspicker', 'js/lib/friends_picker.js'); elgg_register_js('jquery.easing', 'vendors/jquery/jquery.easing.1.3.packed.js'); + elgg_register_js('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/scripts/jquery.imgareaselect.min.js'); + elgg_register_css('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/css/imgareaselect-deprecated.css'); + // Trigger the shutdown:system event upon PHP shutdown. register_shutdown_function('_elgg_shutdown_hook'); diff --git a/engine/lib/entities.php b/engine/lib/entities.php index 10313fc8c..927be4b1d 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -772,7 +772,7 @@ function elgg_entity_exists($guid) { * * callback => string A callback function to pass each row through * - * @return mixed int if count is true, an array of entity objects, or false on failure + * @return mixed if count, int. if not count, array or false if no entities. false also on errors. * @since 1.7.0 * @see elgg_get_entities_from_metadata() * @see elgg_get_entities_from_relationship() @@ -846,9 +846,6 @@ function elgg_get_entities(array $options = array()) { $wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'], $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); - // remove identical where clauses - $wheres = array_unique($wheres); - // see if any functions failed // remove empty strings on successful functions foreach ($wheres as $i => $where) { @@ -859,6 +856,9 @@ function elgg_get_entities(array $options = array()) { } } + // remove identical where clauses + $wheres = array_unique($wheres); + // evaluate join clauses if (!is_array($options['joins'])) { $options['joins'] = array($options['joins']); @@ -1118,8 +1118,12 @@ function elgg_get_guid_based_where_sql($column, $guids) { $guids_sanitized = array(); foreach ($guids as $guid) { - if (($guid != sanitise_int($guid))) { - return FALSE; + if ($guid !== ELGG_ENTITIES_NO_VALUE) { + $guid = sanitise_int($guid); + + if (!$guid) { + return false; + } } $guids_sanitized[] = $guid; } @@ -1494,6 +1498,7 @@ function delete_entity($guid, $recursive = true) { $entity_disable_override = access_get_show_hidden_status(); access_show_hidden_entities(true); + $ia = elgg_set_ignore_access(true); $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities WHERE container_guid=$guid or owner_guid=$guid @@ -1506,6 +1511,7 @@ function delete_entity($guid, $recursive = true) { access_show_hidden_entities($entity_disable_override); $__RECURSIVE_DELETE_TOKEN = null; + elgg_set_ignore_access($ia); } // Now delete the entity itself @@ -1515,8 +1521,8 @@ function delete_entity($guid, $recursive = true) { $entity->deleteOwnedAnnotations(); $entity->deleteRelationships(); - remove_from_river_by_subject($guid); - remove_from_river_by_object($guid); + elgg_delete_river(array('subject_guid' => $guid)); + elgg_delete_river(array('object_guid' => $guid)); remove_all_private_settings($guid); $res = delete_data("DELETE from {$CONFIG->dbprefix}entities where guid={$guid}"); diff --git a/engine/lib/group.php b/engine/lib/group.php index e7b70fd10..7fa188cd6 100644 --- a/engine/lib/group.php +++ b/engine/lib/group.php @@ -276,9 +276,7 @@ function group_gatekeeper($forward = true) { if ($forward && $allowed == false) { register_error(elgg_echo('membershiprequired')); - if (!forward($url, 'member')) { - throw new SecurityException(elgg_echo('SecurityException:UnexpectedOutputInGatekeeper')); - } + forward($url, 'member'); } return $allowed; diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index a6b1bb43a..e5389df38 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -366,7 +366,6 @@ function elgg_enable_metadata(array $options) { * When in doubt, use name_value_pairs. * * @see elgg_get_entities - * @see elgg_get_entities_from_annotations * * @param array $options Array in format: * @@ -398,7 +397,7 @@ function elgg_enable_metadata(array $options) { * * metadata_owner_guids => NULL|ARR guids for metadata owners * - * @return array + * @return mixed if count, int. if not count, array or false if no entities. false also on errors. * @since 1.7.0 */ function elgg_get_entities_from_metadata(array $options = array()) { diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php index d444121d0..8c00fb2ad 100644 --- a/engine/lib/metastrings.php +++ b/engine/lib/metastrings.php @@ -360,9 +360,6 @@ function elgg_get_metastring_based_objects($options) { $wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid', $options['metastring_owner_guids']); - // remove identical where clauses - $wheres = array_unique($wheres); - // see if any functions failed // remove empty strings on successful functions foreach ($wheres as $i => $where) { @@ -373,6 +370,9 @@ function elgg_get_metastring_based_objects($options) { } } + // remove identical where clauses + $wheres = array_unique($wheres); + // evaluate join clauses if (!is_array($options['joins'])) { $options['joins'] = array($options['joins']); diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index 1305ee3de..3f3a8ecd5 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -20,20 +20,20 @@ * Menus * Elgg uses a single interface to manage its menus. Menu items are added with * {@link elgg_register_menu_item()}. This is generally used for menus that - * appear only once per page. For context-sensitive menus (such as the hover + * appear only once per page. For dynamic menus (such as the hover * menu for user's avatar), a plugin hook is emitted when the menu is being * created. The hook is 'register', 'menu:<menu_name>'. For more details on this, * @see elgg_view_menu(). * * Menus supported by the Elgg core * Standard menus: - * site Site navihgation shown on every page. + * site Site navigation shown on every page. * page Page menu usually shown in a sidebar. Uses Elgg's context. * topbar Topbar menu shown on every page. The default has two sections. * footer Like the topbar but in the footer. * extras Links about content on the page. The RSS link is added to this. * - * Context-sensitive (also called just-in-time menus): + * Dynamic menus (also called just-in-time menus): * user_hover Avatar hover menu. The user entity is passed as a parameter. * entity The set of links shown in the summary of an entity. * river Links shown on river items. @@ -51,7 +51,10 @@ * * @warning Generally you should not use this in response to the plugin hook: * 'register', 'menu:<menu_name>'. If you do, you may end up with many incorrect - * links on a context-sensitive menu. + * links on a dynamic menu. + * + * @warning A menu item's name must be unique per menu. If more than one menu + * item with the same name are registered, the last menu item takes priority. * * @see elgg_view_menu() for the plugin hooks available for modifying a menu as * it is being rendered. @@ -282,7 +285,9 @@ function elgg_site_menu_setup($hook, $type, $return, $params) { } $return['default'] = $featured; - $return['more'] = $registered; + if (count($registered) > 0) { + $return['more'] = $registered; + } } else { // no featured menu items set $max_display_items = 5; @@ -373,12 +378,38 @@ function elgg_entity_menu_setup($hook, $type, $return, $params) { } /** + * Adds a delete link to "generic_comment" annotations + */ +function elgg_annotation_menu_setup($hook, $type, $return, $params) { + $annotation = $params['annotation']; + + if ($annotation->name == 'generic_comment' && $annotation->canEdit()) { + $url = elgg_http_add_url_query_elements('action/comments/delete', array( + 'annotation_id' => $annotation->id, + )); + + $options = array( + 'name' => 'delete', + 'href' => $url, + 'text' => "<span class=\"elgg-icon elgg-icon-delete\"></span>", + 'confirm' => elgg_echo('deleteconfirm'), + 'encode_text' => false + ); + $return[] = ElggMenuItem::factory($options); + } + + return $return; +} + + +/** * Navigation initialization */ function elgg_nav_init() { elgg_register_plugin_hook_handler('prepare', 'menu:site', 'elgg_site_menu_setup'); elgg_register_plugin_hook_handler('register', 'menu:river', 'elgg_river_menu_setup'); elgg_register_plugin_hook_handler('register', 'menu:entity', 'elgg_entity_menu_setup'); + elgg_register_plugin_hook_handler('register', 'menu:annotation', 'elgg_annotation_menu_setup'); } elgg_register_event_handler('init', 'system', 'elgg_nav_init'); diff --git a/engine/lib/output.php b/engine/lib/output.php index 04c737062..9479fee53 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -215,6 +215,14 @@ function elgg_clean_vars(array $vars = array()) { unset($vars['internalid']); } + if (isset($vars['__ignoreInternalid'])) { + unset($vars['__ignoreInternalid']); + } + + if (isset($vars['__ignoreInternalname'])) { + unset($vars['__ignoreInternalname']); + } + return $vars; } diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index 88217b782..365ef6fdf 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -548,7 +548,12 @@ function elgg_get_plugins_provides($type = null, $name = null) { $provides = array(); foreach ($active_plugins as $plugin) { - if ($plugin_provides = $plugin->getManifest()->getProvides()) { + $plugin_provides = array(); + $manifest = $plugin->getManifest(); + if ($manifest instanceof ElggPluginManifest) { + $plugin_provides = $plugin->getManifest()->getProvides(); + } + if ($plugin_provides) { foreach ($plugin_provides as $provided) { $provides[$provided['type']][$provided['name']] = array( 'version' => $provided['version'], @@ -811,7 +816,7 @@ function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_ /** * Unsets a user-specific plugin setting * - * @param str $name Name of the plugin setting + * @param str $name Name of the setting * @param int $user_guid Defaults to logged in user * @param str $plugin_id Defaults to contextual plugin name * @@ -834,7 +839,7 @@ function elgg_unset_plugin_user_setting($name, $user_guid = null, $plugin_id = n /** * Get a user specific setting for a plugin. * - * @param string $name The name. + * @param string $name The name of the setting. * @param int $user_guid Guid of owning user * @param string $plugin_id Optional plugin name, if not specified * it is detected from where you are calling. @@ -858,7 +863,7 @@ function elgg_get_plugin_user_setting($name, $user_guid = null, $plugin_id = nul /** * Set a setting for a plugin. * - * @param string $name The name - note, can't be "title". + * @param string $name The name of the setting - note, can't be "title". * @param mixed $value The value. * @param string $plugin_id Optional plugin name, if not specified * then it is detected from where you are calling from. @@ -882,7 +887,7 @@ function elgg_set_plugin_setting($name, $value, $plugin_id = null) { /** * Get setting for a plugin. * - * @param string $name The name. + * @param string $name The name of the setting. * @param string $plugin_id Optional plugin name, if not specified * then it is detected from where you are calling from. * @@ -905,7 +910,7 @@ function elgg_get_plugin_setting($name, $plugin_id = null) { /** * Unsets a plugin setting. * - * @param string $name The name. + * @param string $name The name of the setting. * @param string $plugin_id Optional plugin name, if not specified * then it is detected from where you are calling from. * @@ -973,7 +978,7 @@ function elgg_unset_all_plugin_settings($plugin_id = null) { * plugin_user_setting_name_value_pairs_operator => NULL|STR The operator to use for combining * (name = value) OPERATOR (name = value); default AND * - * @return mixed + * @return mixed int if count is true, an array of entity objects, or false on failure */ function elgg_get_entities_from_plugin_user_settings(array $options = array()) { // if they're passing it don't bother diff --git a/engine/lib/private_settings.php b/engine/lib/private_settings.php index e5e7b2213..d7d819e1c 100644 --- a/engine/lib/private_settings.php +++ b/engine/lib/private_settings.php @@ -38,7 +38,7 @@ * their own settings. * * - * @return array + * @return mixed int if count is true, an array of entity objects, or false on failure * @since 1.8.0 */ function elgg_get_entities_from_private_settings(array $options = array()) { diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index 9d5fd39b6..ede5ca1eb 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -235,6 +235,11 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) { /** * Return entities matching a given query joining against a relationship. + * Also accepts all options available to elgg_get_entities() and + * elgg_get_entities_from_metadata(). + * + * @see elgg_get_entities + * @see elgg_get_entities_from_metadata * * @param array $options Array in format: * @@ -244,7 +249,7 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) { * * inverse_relationship => BOOL Inverse the relationship * - * @return array + * @return mixed if count, int. if not count, array or false if no entities. false also on errors. * @since 1.7.0 */ function elgg_get_entities_from_relationship($options) { @@ -365,7 +370,7 @@ function elgg_list_entities_from_relationship(array $options = array()) { * * @param array $options An options array compatible with * elgg_get_entities_from_relationship() - * @return array + * @return mixed int if count is true, an array of entity objects, or false on failure * @since 1.8.0 */ function elgg_get_entities_from_relationship_count(array $options = array()) { diff --git a/engine/lib/river.php b/engine/lib/river.php index 143ff035f..e283c0595 100644 --- a/engine/lib/river.php +++ b/engine/lib/river.php @@ -170,9 +170,6 @@ function elgg_delete_river(array $options = array()) { $wheres[] = "rv.posted <= {$options['posted_time_upper']}"; } - // remove identical where clauses - $wheres = array_unique($wheres); - // see if any functions failed // remove empty strings on successful functions foreach ($wheres as $i => $where) { @@ -183,6 +180,9 @@ function elgg_delete_river(array $options = array()) { } } + // remove identical where clauses + $wheres = array_unique($wheres); + $query = "DELETE rv.* FROM {$CONFIG->dbprefix}river rv "; // remove identical join clauses @@ -304,9 +304,6 @@ function elgg_get_river(array $options = array()) { } } - // remove identical where clauses - $wheres = array_unique($wheres); - // see if any functions failed // remove empty strings on successful functions foreach ($wheres as $i => $where) { @@ -317,6 +314,9 @@ function elgg_get_river(array $options = array()) { } } + // remove identical where clauses + $wheres = array_unique($wheres); + if (!$options['count']) { $query = "SELECT DISTINCT rv.* FROM {$CONFIG->dbprefix}river rv "; } else { @@ -378,7 +378,7 @@ function elgg_list_river(array $options = array()) { 'offset' => (int) max(get_input('offset', 0), 0), 'limit' => (int) max(get_input('limit', 20), 0), 'pagination' => TRUE, - 'list_class' => 'elgg-river', + 'list_class' => 'elgg-list-river elgg-river', // @todo remove elgg-river in Elgg 1.9 ); $options = array_merge($defaults, $options); @@ -472,7 +472,7 @@ function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs } if (is_array($wheres) && count($wheres)) { - $wheres = array(implode(' AND ', $wheres)); + $wheres = array(implode(' OR ', $wheres)); } } else { // using type/subtype pairs diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php index 407bb69c5..ae42956a9 100644 --- a/engine/lib/sessions.php +++ b/engine/lib/sessions.php @@ -472,10 +472,7 @@ function gatekeeper() { if (!elgg_is_logged_in()) { $_SESSION['last_forward_from'] = current_page_url(); register_error(elgg_echo('loggedinrequired')); - - if (!forward('', 'login')) { - throw new SecurityException(elgg_echo('SecurityException:UnexpectedOutputInGatekeeper')); - } + forward('', 'login'); } } @@ -490,9 +487,7 @@ function admin_gatekeeper() { if (!elgg_is_admin_logged_in()) { $_SESSION['last_forward_from'] = current_page_url(); register_error(elgg_echo('adminrequired')); - if (!forward('', 'admin')) { - throw new SecurityException(elgg_echo('SecurityException:UnexpectedOutputInGatekeeper')); - } + forward('', 'admin'); } } diff --git a/engine/lib/tags.php b/engine/lib/tags.php index 1116d63f3..64feed5b2 100644 --- a/engine/lib/tags.php +++ b/engine/lib/tags.php @@ -184,9 +184,6 @@ function elgg_get_tags(array $options = array()) { $wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'], $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); - // remove identical where clauses - $wheres = array_unique($wheres); - // see if any functions failed // remove empty strings on successful functions foreach ($wheres as $i => $where) { @@ -197,6 +194,8 @@ function elgg_get_tags(array $options = array()) { } } + // remove identical where clauses + $wheres = array_unique($wheres); $joins = $options['joins']; diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php index dc3911062..dc1213187 100644 --- a/engine/lib/upgrade.php +++ b/engine/lib/upgrade.php @@ -160,7 +160,7 @@ function elgg_get_upgrade_files($upgrade_path = null) { } /** - * Get the current version information + * Get the current Elgg version information * * @param bool $humanreadable Whether to return a human readable version (default: false) * @@ -169,13 +169,18 @@ function elgg_get_upgrade_files($upgrade_path = null) { function get_version($humanreadable = false) { global $CONFIG; + static $version, $release; + if (isset($CONFIG->path)) { - if (include($CONFIG->path . "version.php")) { - return (!$humanreadable) ? $version : $release; + if (!isset($version) || !isset($release)) { + if (!include($CONFIG->path . "version.php")) { + return false; + } } + return (!$humanreadable) ? $version : $release; } - return FALSE; + return false; } /** diff --git a/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php new file mode 100644 index 000000000..3a9200b51 --- /dev/null +++ b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php @@ -0,0 +1,12 @@ +<?php +/** + * Elgg 1.8.0.1 upgrade 2011092500 + * forum_reply_river_view + * + * The forum reply river view is in a new location in Elgg 1.8 + */ + +$query = "UPDATE {$CONFIG->dbprefix}river SET view='river/annotation/group_topic_post/reply', + action_type='reply' + WHERE view='river/forum/create' AND action_type='create'"; +update_data($query); diff --git a/engine/lib/users.php b/engine/lib/users.php index 48f10f974..ce1b409f6 100644 --- a/engine/lib/users.php +++ b/engine/lib/users.php @@ -813,6 +813,7 @@ function validate_username($username) { if ( preg_match($blacklist, $username) ) { + // @todo error message needs work throw new RegistrationException(elgg_echo('registration:invalidchars')); } @@ -823,6 +824,7 @@ function validate_username($username) { for ($n = 0; $n < strlen($blacklist2); $n++) { if (strpos($username, $blacklist2[$n]) !== false) { $msg = elgg_echo('registration:invalidchars', array($blacklist2[$n], $blacklist2)); + $msg = htmlentities($msg, ENT_COMPAT, 'UTF-8'); throw new RegistrationException($msg); } } @@ -1222,12 +1224,14 @@ function elgg_user_hover_menu($hook, $type, $return, $params) { if ($user->isFriend()) { $url = "action/friends/remove?friend={$user->guid}"; $text = elgg_echo('friend:remove'); + $name = 'remove_friend'; } else { $url = "action/friends/add?friend={$user->guid}"; $text = elgg_echo('friend:add'); + $name = 'add_friend'; } $url = elgg_add_action_tokens_to_url($url); - $item = new ElggMenuItem('addfriend', $text, $url); + $item = new ElggMenuItem($name, $text, $url); $item->setSection('action'); $return[] = $item; } else { @@ -1419,11 +1423,14 @@ function elgg_profile_page_handler($page) { */ function users_pagesetup() { - if (elgg_get_page_owner_guid()) { + $owner = elgg_get_page_owner_entity(); + $viewer = elgg_get_logged_in_user_entity(); + + if ($owner) { $params = array( 'name' => 'friends', 'text' => elgg_echo('friends'), - 'href' => 'friends/' . elgg_get_page_owner_entity()->username, + 'href' => 'friends/' . $owner->username, 'contexts' => array('friends') ); elgg_register_menu_item('page', $params); @@ -1431,43 +1438,43 @@ function users_pagesetup() { $params = array( 'name' => 'friends:of', 'text' => elgg_echo('friends:of'), - 'href' => 'friendsof/' . elgg_get_page_owner_entity()->username, + 'href' => 'friendsof/' . $owner->username, 'contexts' => array('friends') ); elgg_register_menu_item('page', $params); - } - - // topbar - $user = elgg_get_logged_in_user_entity(); - if ($user) { + elgg_register_menu_item('page', array( 'name' => 'edit_avatar', - 'href' => "avatar/edit/{$user->username}", + 'href' => "avatar/edit/{$owner->username}", 'text' => elgg_echo('avatar:edit'), 'contexts' => array('profile_edit'), )); elgg_register_menu_item('page', array( 'name' => 'edit_profile', - 'href' => "profile/{$user->username}/edit", + 'href' => "profile/{$owner->username}/edit", 'text' => elgg_echo('profile:edit'), 'contexts' => array('profile_edit'), )); + } - $icon_url = $user->getIconURL('topbar'); + // topbar + if ($viewer) { + + $icon_url = $viewer->getIconURL('topbar'); $class = 'elgg-border-plain elgg-transition'; $title = elgg_echo('profile'); elgg_register_menu_item('topbar', array( 'name' => 'profile', - 'href' => $user->getURL(), - 'text' => "<img src=\"$icon_url\" alt=\"$user->name\" title=\"$title\" class=\"$class\" />", + 'href' => $viewer->getURL(), + 'text' => "<img src=\"$icon_url\" alt=\"$viewer->name\" title=\"$title\" class=\"$class\" />", 'priority' => 100, 'link_class' => 'elgg-topbar-avatar', )); elgg_register_menu_item('topbar', array( 'name' => 'friends', - 'href' => "friends/{$user->username}", + 'href' => "friends/{$viewer->username}", 'text' => elgg_view_icon('users'), 'title' => elgg_echo('friends'), 'priority' => 300, @@ -1475,7 +1482,7 @@ function users_pagesetup() { elgg_register_menu_item('topbar', array( 'name' => 'usersettings', - 'href' => "settings/user/{$user->username}", + 'href' => "settings/user/{$viewer->username}", 'text' => elgg_view_icon('settings') . elgg_echo('settings'), 'priority' => 500, 'section' => 'alt', @@ -1489,7 +1496,6 @@ function users_pagesetup() { 'priority' => 1000, 'section' => 'alt', )); - } } diff --git a/engine/lib/views.php b/engine/lib/views.php index 04f4b7c2a..a18118f32 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -369,8 +369,8 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie // Trigger the pagesetup event if (!isset($CONFIG->pagesetupdone)) { - elgg_trigger_event('pagesetup', 'system'); $CONFIG->pagesetupdone = true; + elgg_trigger_event('pagesetup', 'system'); } if (!is_array($usercache)) { @@ -411,19 +411,25 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie } // internalname => name (1.8) - if (isset($vars['internalname']) && !isset($vars['name'])) { + if (isset($vars['internalname']) && !isset($vars['__ignoreInternalname']) && !isset($vars['name'])) { elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2); $vars['name'] = $vars['internalname']; $test=false; } elseif (isset($vars['name'])) { + if (!isset($vars['internalname'])) { + $vars['__ignoreInternalname'] = ''; + } $vars['internalname'] = $vars['name']; } // internalid => id (1.8) - if (isset($vars['internalid']) && !isset($vars['name'])) { + if (isset($vars['internalid']) && !isset($vars['__ignoreInternalid']) && !isset($vars['name'])) { elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2); $vars['id'] = $vars['internalid']; } elseif (isset($vars['id'])) { + if (!isset($vars['internalid'])) { + $vars['__ignoreInternalid'] = ''; + } $vars['internalid'] = $vars['id']; } @@ -617,13 +623,12 @@ function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) $vars['title'] = $title; $vars['body'] = $body; $vars['sysmessages'] = $messages; + + $vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars); // check for deprecated view if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) { elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8); - global $CONFIG; - - $vars['config'] = $CONFIG; $output = elgg_view('pageshells/pageshell', $vars); } else { $output = elgg_view("page/$page_shell", $vars); @@ -681,15 +686,19 @@ function elgg_view_layout($layout_name, $vars = array()) { $param_array = $vars; } + $params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array); + // check deprecated location if (elgg_view_exists("canvas/layouts/$layout_name")) { elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8); - return elgg_view("canvas/layouts/$layout_name", $param_array); + $output = elgg_view("canvas/layouts/$layout_name", $params); } elseif (elgg_view_exists("page/layouts/$layout_name")) { - return elgg_view("page/layouts/$layout_name", $param_array); + $output = elgg_view("page/layouts/$layout_name", $params); } else { - return elgg_view("page/layouts/default", $param_array); + $output = elgg_view("page/layouts/default", $params); } + + return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output); } /** @@ -700,9 +709,9 @@ function elgg_view_layout($layout_name, $vars = array()) { * * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables * plugins to add menu items just before a menu is rendered. This is used by - * context-sensitive menus (menus that are specific to a particular entity such - * as the user hover menu). Using elgg_register_menu_item() in response to the hook - * can cause incorrect links to show up. See the blog plugin's blog_owner_block_menu() + * dynamic menus (menus that change based on some input such as the user hover + * menu). Using elgg_register_menu_item() in response to the hook can cause + * incorrect links to show up. See the blog plugin's blog_owner_block_menu() * for an example of using this plugin hook. * * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins @@ -715,8 +724,9 @@ function elgg_view_layout($layout_name, $vars = array()) { * @param array $vars An associative array of display options for the menu. * Options include: * sort_by => string or php callback - * string options: 'name', 'priority', 'title' (default), 'register' (registration order) - * php callback: a compare function for usort + * string options: 'name', 'priority', 'title' (default), + * 'register' (registration order) or a + * php callback (a compare function for usort) * handler: string the page handler to build action URLs * entity: ElggEntity to use to build action URLs * class: string the class for the entire menu. @@ -735,7 +745,7 @@ function elgg_view_menu($menu_name, array $vars = array()) { $menu = $CONFIG->menus[$menu_name]; // Give plugins a chance to add menu items just before creation. - // This supports context sensitive menus (ex. user_hover). + // This supports dynamic menus (example: user_hover). $menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu); $builder = new ElggMenuBuilder($menu); @@ -1035,7 +1045,7 @@ $list_type_toggle = true, $pagination = true) { function elgg_view_annotation_list($annotations, array $vars = array()) { $defaults = array( 'items' => $annotations, - 'list_class' => 'elgg-annotation-list', + 'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9 'full_view' => true, 'offset_key' => 'annoff', ); @@ -1224,6 +1234,9 @@ function elgg_view_river_item($item, array $vars = array()) { * sets the action by default to "action/$action". Automatically wraps the forms/$action * view with a <form> tag and inserts the anti-csrf security tokens. * + * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any + * slashes with dashes (blog/save becomes elgg-form-blog-save) + * * @example * <code>echo elgg_view_form('login');</code> * @@ -1253,9 +1266,18 @@ function elgg_view_form($action, $form_vars = array(), $body_vars = array()) { $defaults = array( 'action' => $CONFIG->wwwroot . "action/$action", - 'body' => elgg_view("forms/$action", $body_vars), + 'body' => elgg_view("forms/$action", $body_vars) ); + $form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action); + + // append elgg-form class to any class options set + if (isset($form_vars['class'])) { + $form_vars['class'] = $form_vars['class'] . " $form_class"; + } else { + $form_vars['class'] = $form_class; + } + return elgg_view('input/form', array_merge($defaults, $form_vars)); } @@ -1293,15 +1315,16 @@ function elgg_view_list_item($item, array $vars = array()) { * Shorthand for <span class="elgg-icon elgg-icon-$name"></span> * * @param string $name The specific icon to display - * @param bool $float Whether to float the icon + * @param string $class Additional class: float, float-alt, or custom class * * @return string The html for displaying an icon */ -function elgg_view_icon($name, $float = false) { - if ($float) { - $float = 'float'; +function elgg_view_icon($name, $class = '') { + // @todo deprecate boolean in Elgg 1.9 + if (is_bool($class) && $class === true) { + $class = 'float'; } - return "<span class=\"elgg-icon elgg-icon-$name $float\"></span>"; + return "<span class=\"elgg-icon elgg-icon-$name $class\"></span>"; } /** @@ -1480,21 +1503,6 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype) } /** - * Add the core Elgg head elements that could be cached - * - * @return void - */ -function elgg_views_register_core_head_elements() { - $url = elgg_get_simplecache_url('js', 'elgg'); - elgg_register_js('elgg', $url, 'head', 10); - elgg_load_js('elgg'); - - $url = elgg_get_simplecache_url('css', 'elgg'); - elgg_register_css('elgg', $url, 10); - elgg_load_css('elgg'); -} - -/** * Add the rss link to the extras when if needed * * @return void @@ -1546,23 +1554,32 @@ function elgg_views_boot() { elgg_register_simplecache_view('css/elgg'); elgg_register_simplecache_view('css/ie'); elgg_register_simplecache_view('css/ie6'); + elgg_register_simplecache_view('css/ie7'); elgg_register_simplecache_view('js/elgg'); - elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.1.min.js', 'head', 1); - elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.14.min.js', 'head', 2); + elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.2.min.js', 'head'); + elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head'); elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js'); + + $elgg_js_url = elgg_get_simplecache_url('js', 'elgg'); + elgg_register_js('elgg', $elgg_js_url, 'head'); + elgg_load_js('jquery'); elgg_load_js('jquery-ui'); elgg_load_js('jquery.form'); + elgg_load_js('elgg'); elgg_register_simplecache_view('js/lightbox'); $lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox'); elgg_register_js('lightbox', $lightbox_js_url); - $lightbox_css_url = 'vendors/jquery/fancybox/jquery.fancybox-1.3.4.css'; + $lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox'); elgg_register_css('lightbox', $lightbox_css_url); - elgg_register_event_handler('ready', 'system', 'elgg_views_register_core_head_elements'); - elgg_register_event_handler('pagesetup', 'system', 'elgg_views_add_rss_link'); + $elgg_css_url = elgg_get_simplecache_url('css', 'elgg'); + elgg_register_css('elgg', $elgg_css_url); + elgg_load_css('elgg'); + + elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link'); // discover the built-in view types // @todo the cache is loaded in load_plugins() but we need to know view_types earlier diff --git a/engine/start.php b/engine/start.php index 713d94cc6..132c060b4 100644 --- a/engine/start.php +++ b/engine/start.php @@ -144,7 +144,9 @@ if (!defined('UPGRADING')) { $lastcached = datalist_get("simplecache_lastcached_$viewtype"); if ($lastupdate == 0 || $lastcached < $lastupdate) { elgg_regenerate_simplecache($viewtype); + $lastcached = datalist_get("simplecache_lastcached_$viewtype"); } + $CONFIG->lastcache = $lastcached; } // System loaded and ready diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php new file mode 100644 index 000000000..1e61c45bb --- /dev/null +++ b/engine/tests/api/access_collections.php @@ -0,0 +1,269 @@ +<?php +/** + * Access Collections tests + * + * @package Elgg + * @subpackage Test + */ +class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest { + + /** + * Called before each test object. + */ + public function __construct() { + parent::__construct(); + + $this->dbPrefix = get_config("dbprefix"); + + $user = new ElggUser(); + $user->username = 'test_user_' . rand(); + $user->email = 'fake_email@fake.com' . rand(); + $user->name = 'fake user'; + $user->access_id = ACCESS_PUBLIC; + $user->salt = generate_random_cleartext_password(); + $user->password = generate_user_password($user, rand()); + $user->owner_guid = 0; + $user->container_guid = 0; + $user->save(); + + $this->user = $user; + } + + /** + * Called before each test method. + */ + public function setUp() { + + } + + /** + * Called after each test method. + */ + public function tearDown() { + // do not allow SimpleTest to interpret Elgg notices as exceptions + $this->swallowErrors(); + } + + /** + * Called after each test object. + */ + public function __destruct() { + // all __destruct() code should go above here + $this->user->delete(); + parent::__destruct(); + } + + public function testCreateGetDeleteACL() { + global $DB_QUERY_CACHE; + + $acl_name = 'test access collection'; + $acl_id = create_access_collection($acl_name); + + $this->assertTrue(is_int($acl_id)); + + $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; + $acl = get_data_row($q); + + $this->assertEqual($acl->id, $acl_id); + + if ($acl) { + $DB_QUERY_CACHE = array(); + + $this->assertEqual($acl->name, $acl_name); + + $result = delete_access_collection($acl_id); + $this->assertTrue($result); + + $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; + $data = get_data($q); + $this->assertFalse($data); + } + } + + public function testAddRemoveUserToACL() { + $acl_id = create_access_collection('test acl'); + + $result = add_user_to_access_collection($this->user->guid, $acl_id); + $this->assertTrue($result); + + if ($result) { + $result = remove_user_from_access_collection($this->user->guid, $acl_id); + $this->assertTrue($result); + } + + delete_access_collection($acl_id); + } + + public function testUpdateACL() { + // another fake user to test with + $user = new ElggUser(); + $user->username = 'test_user_' . rand(); + $user->email = 'fake_email@fake.com' . rand(); + $user->name = 'fake user'; + $user->access_id = ACCESS_PUBLIC; + $user->salt = generate_random_cleartext_password(); + $user->password = generate_user_password($user, rand()); + $user->owner_guid = 0; + $user->container_guid = 0; + $user->save(); + + $acl_id = create_access_collection('test acl'); + + $member_lists = array( + // adding + array( + $this->user->guid, + $user->guid + ), + // removing one, keeping one. + array( + $user->guid + ), + // removing one, adding one + array( + $this->user->guid, + ), + // removing all. + array() + ); + + foreach ($member_lists as $members) { + $result = update_access_collection($acl_id, $members); + $this->assertTrue($result); + + if ($result) { + $q = "SELECT * FROM {$this->dbPrefix}access_collection_membership + WHERE access_collection_id = $acl_id"; + $data = get_data($q); + + if (count($members) == 0) { + $this->assertFalse($data); + } else { + $this->assertEqual(count($members), count($data)); + } + foreach ($data as $row) { + $this->assertTrue(in_array($row->user_guid, $members)); + } + } + } + + delete_access_collection($acl_id); + $user->delete(); + } + + public function testCanEditACL() { + $acl_id = create_access_collection('test acl', $this->user->guid); + + // should be true since it's the owner + $result = can_edit_access_collection($acl_id, $this->user->guid); + $this->assertTrue($result); + + // should be true since IA is on. + $ia = elgg_set_ignore_access(true); + $result = can_edit_access_collection($acl_id); + $this->assertTrue($result); + elgg_set_ignore_access($ia); + + // should be false since IA is off + $ia = elgg_set_ignore_access(false); + $result = can_edit_access_collection($acl_id); + $this->assertFalse($result); + elgg_set_ignore_access($ia); + + delete_access_collection($acl_id); + } + + public function testCanEditACLHook() { + // if only we supported closures! + global $acl_test_info; + + $acl_id = create_access_collection('test acl'); + + $acl_test_info = array( + 'acl_id' => $acl_id, + 'user' => $this->user + ); + + function test_acl_access_hook($hook, $type, $value, $params) { + global $acl_test_info; + if ($params['user_id'] == $acl_test_info['user']->guid) { + $acl = get_access_collection($acl_test_info['acl_id']); + $value[$acl->id] = $acl->name; + } + + return $value; + } + + register_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); + + // enable security since we usually run as admin + $ia = elgg_set_ignore_access(false); + $result = can_edit_access_collection($acl_id, $this->user->guid); + $this->assertTrue($result); + $ia = elgg_set_ignore_access($ia); + + unregister_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); + } + + // groups interface + // only runs if the groups plugin is enabled because implementation is split between + // core and the plugin. + public function testCreateDeleteGroupACL() { + if (!is_plugin_enabled('groups')) { + return; + } + + $group = new ElggGroup(); + $group->name = 'Test group'; + $group->save(); + $acl = get_access_collection($group->group_acl); + + // ACLs are owned by groups + $this->assertEqual($acl->owner_guid, $group->guid); + + // removing group and acl + $this->assertTrue($group->delete()); + + $acl = get_access_collection($group->group_acl); + $this->assertFalse($acl); + + $group->delete(); + } + + public function testJoinLeaveGroupACL() { + if (!is_plugin_enabled('groups')) { + return; + } + + $group = new ElggGroup(); + $group->name = 'Test group'; + $group->save(); + + $result = $group->join($this->user); + $this->assertTrue($result); + + // disable security since we run as admin + $ia = elgg_set_ignore_access(false); + + // need to set the page owner to emulate being in a group context. + // this is kinda hacky. + elgg_set_page_owner_guid($group->getGUID()); + + if ($result) { + $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); + $this->assertTrue($can_edit); + } + + $result = $group->leave($this->user); + $this->assertTrue($result); + + if ($result) { + $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); + $this->assertFalse($can_edit); + } + + elgg_set_ignore_access($ia); + + $group->delete(); + } +} diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php index aef7a991e..59b48999c 100644 --- a/engine/tests/api/entity_getter_functions.php +++ b/engine/tests/api/entity_getter_functions.php @@ -2789,4 +2789,13 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest { $this->assertEqual($a_e_map[$a->id], $a->owner_guid); } } + + public function testElggGetEntitiesBadWheres() { + $options = array( + 'container_guid' => 'abc' + ); + + $entities = elgg_get_entities($options); + $this->assertFalse($entities); + } } diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index 461627547..36d680d54 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -31,6 +31,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { global $CONFIG; unset($CONFIG->externals); + unset($CONFIG->externals_map); } /** @@ -106,7 +107,16 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { // specify name $result = elgg_register_js('key', 'http://test1.com', 'footer'); $this->assertTrue($result); - $this->assertIdentical('http://test1.com', $CONFIG->externals['js']['key']->url); + $this->assertTrue(isset($CONFIG->externals_map['js']['key'])); + + $item = $CONFIG->externals_map['js']['key']; + $this->assertTrue($CONFIG->externals['js']->contains($item)); + + $priority = $CONFIG->externals['js']->getPriority($item); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['js']->getElement($priority); + $this->assertIdentical('http://test1.com', $item->url); // send a bad url $result = @elgg_register_js('bad'); @@ -118,11 +128,20 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { */ public function testElggRegisterCSS() { global $CONFIG; - + // specify name $result = elgg_register_css('key', 'http://test1.com'); $this->assertTrue($result); - $this->assertIdentical('http://test1.com', $CONFIG->externals['css']['key']->url); + $this->assertTrue(isset($CONFIG->externals_map['css']['key'])); + + $item = $CONFIG->externals_map['css']['key']; + $this->assertTrue($CONFIG->externals['css']->contains($item)); + + $priority = $CONFIG->externals['css']->getPriority($item); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['css']->getElement($priority); + $this->assertIdentical('http://test1.com', $item->url); } /** @@ -134,21 +153,43 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $base = trim(elgg_get_site_url(), "/"); $urls = array('id1' => "$base/urla", 'id2' => "$base/urlb", 'id3' => "$base/urlc"); + foreach ($urls as $id => $url) { elgg_register_js($id, $url); } $result = elgg_unregister_js('id1'); $this->assertTrue($result); - @$this->assertNULL($CONFIG->externals['js']['head']['id1']); + + $js = $CONFIG->externals['js']; + $elements = $js->getElements(); + $this->assertFalse(isset($CONFIG->externals_map['js']['id1'])); + + foreach ($elements as $element) { + $this->assertFalse($element->name == 'id1'); + } $result = elgg_unregister_js('id1'); $this->assertFalse($result); + $result = elgg_unregister_js('', 'does_not_exist'); $this->assertFalse($result); $result = elgg_unregister_js('id2'); - $this->assertIdentical($urls['id3'], $CONFIG->externals['js']['id3']->url); + $elements = $js->getElements(); + + $this->assertFalse(isset($CONFIG->externals_map['js']['id2'])); + foreach ($elements as $element) { + $this->assertFalse($element->name == 'id2'); + } + + $this->assertTrue(isset($CONFIG->externals_map['js']['id3'])); + + $priority = $CONFIG->externals['js']->getPriority($CONFIG->externals_map['js']['id3']); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['js']->getElement($priority); + $this->assertIdentical($urls['id3'], $item->url); } /** @@ -161,8 +202,9 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { elgg_load_js('key'); $result = elgg_register_js('key', 'http://test1.com', 'footer'); $this->assertTrue($result); + $js_urls = elgg_get_loaded_js('footer'); - $this->assertIdentical(array('http://test1.com'), $js_urls); + $this->assertIdentical(array(500 => 'http://test1.com'), $js_urls); } /** @@ -173,18 +215,295 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $base = trim(elgg_get_site_url(), "/"); - $urls = array('id1' => "$base/urla", 'id2' => "$base/urlb", 'id3' => "$base/urlc"); + $urls = array( + 'id1' => "$base/urla", + 'id2' => "$base/urlb", + 'id3' => "$base/urlc" + ); + foreach ($urls as $id => $url) { elgg_register_js($id, $url); elgg_load_js($id); } $js_urls = elgg_get_loaded_js('head'); - $this->assertIdentical($js_urls[0], $urls['id1']); - $this->assertIdentical($js_urls[1], $urls['id2']); - $this->assertIdentical($js_urls[2], $urls['id3']); + + $this->assertIdentical($js_urls[500], $urls['id1']); + $this->assertIdentical($js_urls[501], $urls['id2']); + $this->assertIdentical($js_urls[502], $urls['id3']); $js_urls = elgg_get_loaded_js('footer'); $this->assertIdentical(array(), $js_urls); } -} + + // test ElggPriorityList + public function testElggPriorityListAdd() { + $pl = new ElggPriorityList(); + $elements = array( + 'Test value', + 'Test value 2', + 'Test value 3' + ); + + shuffle($elements); + + foreach ($elements as $element) { + $this->assertTrue($pl->add($element) !== false); + } + + $test_elements = $pl->getElements(); + + $this->assertTrue(is_array($test_elements)); + + foreach ($test_elements as $i => $element) { + // should be in the array + $this->assertTrue(in_array($element, $elements)); + + // should be the only element, so priority 0 + $this->assertEqual($i, array_search($element, $elements)); + } + } + + public function testElggPriorityListAddWithPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 10 => 'Test Element 10', + 5 => 'Test Element 5', + 0 => 'Test Element 0', + 100 => 'Test Element 100', + -1 => 'Test Element -1', + -5 => 'Test Element -5' + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + $test_elements = $pl->getElements(); + + // should be sorted by priority + $elements_sorted = array( + -5 => 'Test Element -5', + -1 => 'Test Element -1', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + 10 => 'Test Element 10', + 100 => 'Test Element 100', + ); + + $this->assertIdentical($elements_sorted, $test_elements); + + foreach ($test_elements as $priority => $element) { + $this->assertIdentical($elements[$priority], $element); + } + } + + public function testElggPriorityListGetNextPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 2 => 'Test Element', + 0 => 'Test Element 2', + -2 => 'Test Element 3', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + // we're not specifying a priority so it should be the next consecutive to 0. + $this->assertEqual(1, $pl->getNextPriority()); + + // add another one at priority 1 + $pl->add('Test Element 1'); + + // next consecutive to 0 is now 3. + $this->assertEqual(3, $pl->getNextPriority()); + } + + public function testElggPriorityListRemove() { + $pl = new ElggPriorityList(); + + $elements = array(); + for ($i=0; $i<3; $i++) { + $element = new stdClass(); + $element->name = "Test Element $i"; + $element->someAttribute = rand(0, 9999); + $elements[] = $element; + $pl->add($element); + } + + $pl->remove($elements[1]); + + $test_elements = $pl->getElements(); + + // make sure it's gone. + $this->assertTrue(2, count($test_elements)); + $this->assertIdentical($elements[0], $test_elements[0]); + $this->assertIdentical($elements[2], $test_elements[2]); + } + + public function testElggPriorityListMove() { + $pl = new ElggPriorityList(); + + $elements = array( + -5 => 'Test Element -5', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + $this->assertTrue($pl->move($elements[-5], 10)); + + // check it's at the new place + $this->assertIdentical($elements[-5], $pl->getElement(10)); + + // check it's not at the old + $this->assertFalse($pl->getElement(-5)); + } + + public function testElggPriorityListConstructor() { + $elements = array( + 10 => 'Test Element 10', + 5 => 'Test Element 5', + 0 => 'Test Element 0', + 100 => 'Test Element 100', + -1 => 'Test Element -1', + -5 => 'Test Element -5' + ); + + $pl = new ElggPriorityList($elements); + $test_elements = $pl->getElements(); + + $elements_sorted = array( + -5 => 'Test Element -5', + -1 => 'Test Element -1', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + 10 => 'Test Element 10', + 100 => 'Test Element 100', + ); + + $this->assertIdentical($elements_sorted, $test_elements); + } + + public function testElggPriorityListGetPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 'Test element 0', + 'Test element 1', + 'Test element 2', + ); + + foreach ($elements as $element) { + $pl->add($element); + } + + $this->assertIdentical(0, $pl->getPriority($elements[0])); + $this->assertIdentical(1, $pl->getPriority($elements[1])); + $this->assertIdentical(2, $pl->getPriority($elements[2])); + } + + public function testElggPriorityListGetElement() { + $pl = new ElggPriorityList(); + $priorities = array(); + + $elements = array( + 'Test element 0', + 'Test element 1', + 'Test element 2', + ); + + foreach ($elements as $element) { + $priorities[] = $pl->add($element); + } + + $this->assertIdentical($elements[0], $pl->getElement($priorities[0])); + $this->assertIdentical($elements[1], $pl->getElement($priorities[1])); + $this->assertIdentical($elements[2], $pl->getElement($priorities[2])); + } + + public function testElggPriorityListPriorityCollision() { + $pl = new ElggPriorityList(); + + $elements = array( + 5 => 'Test element 5', + 6 => 'Test element 6', + 0 => 'Test element 0', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + // add at a colliding priority + $pl->add('Colliding element', 5); + + // should float to the top closest to 5, so 7 + $this->assertEqual(7, $pl->getPriority('Colliding element')); + } + + public function testElggPriorityListIterator() { + $elements = array( + -5 => 'Test element -5', + 0 => 'Test element 0', + 5 => 'Test element 5' + ); + + $pl = new ElggPriorityList($elements); + + foreach ($pl as $priority => $element) { + $this->assertIdentical($elements[$priority], $element); + } + } + + public function testElggPriorityListCountable() { + $pl = new ElggPriorityList(); + + $this->assertEqual(0, count($pl)); + + $pl->add('Test element 0'); + $this->assertEqual(1, count($pl)); + + $pl->add('Test element 1'); + $this->assertEqual(2, count($pl)); + + $pl->add('Test element 2'); + $this->assertEqual(3, count($pl)); + } + + public function testElggPriorityListUserSort() { + $elements = array( + 'A', + 'B', + 'C', + 'D', + 'E', + ); + + $elements_sorted_string = $elements; + + shuffle($elements); + $pl = new ElggPriorityList($elements); + + // will sort by priority + $test_elements = $pl->getElements(); + $this->assertIdentical($elements, $test_elements); + + function test_sort($elements) { + sort($elements, SORT_LOCALE_STRING); + return $elements; + } + + // force a new sort using our function + $pl->sort('test_sort'); + $test_elements = $pl->getElements(); + + $this->assertIdentical($elements_sorted_string, $test_elements); + } +}
\ No newline at end of file diff --git a/engine/tests/api/plugins.php b/engine/tests/api/plugins.php index 00b0d4513..72092b688 100644 --- a/engine/tests/api/plugins.php +++ b/engine/tests/api/plugins.php @@ -215,18 +215,6 @@ class ElggCorePluginsAPITest extends ElggCoreUnitTest { $this->assertEqual($this->package17->getManifest()->getDescription(), 'A 1.7-style manifest.'); } - public function testElggPluginManifestGetDescriptionTranslated() { - $en = array( - $this->package18->getManifest()->getDescription() => 'A translated 1.8 description!', - $this->package17->getManifest()->getDescription() => 'A translated 1.7 description!', - ); - - add_translation('en', $en); - - $this->assertEqual($this->package18->getManifest()->getDescription(), 'A translated 1.8 description!'); - $this->assertEqual($this->package17->getManifest()->getDescription(), 'A translated 1.7 description!'); - } - public function testElggPluginManifestGetCategories() { $categories = array( 'Admin', 'ServiceAPI' diff --git a/engine/tests/regression/trac_bugs.php b/engine/tests/regression/trac_bugs.php index 6f98c67bd..23d6d1dc6 100644 --- a/engine/tests/regression/trac_bugs.php +++ b/engine/tests/regression/trac_bugs.php @@ -112,4 +112,91 @@ class ElggCoreRegressionBugsTest extends ElggCoreUnitTest { $this->assertEqual($params['xoffset'], $options['x1']); $this->assertEqual($params['yoffset'], $options['y1']); } + + // #3722 Check canEdit() works for contains regardless of groups + function test_can_write_to_container() { + $user = new ElggUser(); + $user->username = 'test_user_' . rand(); + $user->name = 'test_user_name_' . rand(); + $user->email = 'test@user.net'; + $user->container_guid = 0; + $user->owner_guid = 0; + $user->save(); + + $object = new ElggObject(); + $object->save(); + + $group = new ElggGroup(); + $group->save(); + + // disable access overrides because we're admin. + $ia = elgg_set_ignore_access(false); + + $this->assertFalse(can_write_to_container($user->guid, $object->guid)); + + global $elgg_test_user; + $elgg_test_user = $user; + + // register hook to allow access + function can_write_to_container_test_hook($hook, $type, $value, $params) { + global $elgg_test_user; + + if ($params['user']->getGUID() == $elgg_test_user->getGUID()) { + return true; + } + } + + register_plugin_hook('container_permissions_check', 'all', 'can_write_to_container_test_hook'); + $this->assertTrue(can_write_to_container($user->guid, $object->guid)); + unregister_plugin_hook('container_permissions_check', 'all', 'can_write_to_container_test_hook'); + + $this->assertFalse(can_write_to_container($user->guid, $group->guid)); + $group->join($user); + $this->assertTrue(can_write_to_container($user->guid, $group->guid)); + + elgg_set_ignore_access($ia); + + $user->delete(); + $object->delete(); + $group->delete(); + } + + function test_db_shutdown_links() { + global $DB_DELAYED_QUERIES, $test_results; + $DB_DELAYED_QUERIES = array(); + + function test_delayed_results($results) { + global $test_results; + $test_results = $results; + } + + $q = 'SELECT 1 as test'; + + $links = array('read', 'write', get_db_link('read'), get_db_link('write')); + + foreach ($links as $link) { + $DB_DELAYED_QUERIES = array(); + + $result = execute_delayed_query($q, $link, 'test_delayed_results'); + + $this->assertTrue($result, "Failed with link = $link"); + $this->assertEqual(count($DB_DELAYED_QUERIES), 1); + $this->assertEqual($DB_DELAYED_QUERIES[0]['q'], $q); + $this->assertEqual($DB_DELAYED_QUERIES[0]['l'], $link); + $this->assertEqual($DB_DELAYED_QUERIES[0]['h'], 'test_delayed_results'); + + db_delayedexecution_shutdown_hook(); + + $num_rows = mysql_num_rows($test_results); + $this->assertEqual($num_rows, 1); + $row = mysql_fetch_assoc($test_results); + $this->assertEqual($row['test'], 1); + } + + // test bad case + $DB_DELAYED_QUERIES = array(); + $result = execute_delayed_query($q, 'not_a_link', 'test_delayed_results'); + $this->assertFalse($result); + $this->assertEqual(array(), $DB_DELAYED_QUERIES); + } } diff --git a/engine/tests/suite.php b/engine/tests/suite.php index 8f2eb41a3..4203bc5d6 100644 --- a/engine/tests/suite.php +++ b/engine/tests/suite.php @@ -9,6 +9,8 @@ require_once(dirname( __FILE__ ) . '/../start.php'); +admin_gatekeeper(); + $vendor_path = "$CONFIG->path/vendors/simpletest"; $test_path = "$CONFIG->path/engine/tests"; |