diff options
146 files changed, 2803 insertions, 621 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index ca1bdc675..13c30ae3e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,64 @@ +Version 1.8.13 +(January 29, 2013 from https://github.com/Elgg/Elgg/tree/1.8) + Contributing Developers: + * Cash Costello + * Juho Jaakkola + * Kevin Jardine + * Krzysztof Różalski + * Steve Clay + + Security Fixes: + * Added validation of Twitter usernames in Twitter widget + + Bugfixes: + * CLI usages with walled garden fixed + * Upgrading from < 1.8 to 1.8 fixed + * Default widgets fixed + * Quotes in object titles no longer result in "qout" in URLs + * List of my groups is ordered now + * Language string river:comment:object:default is defined now + * Added language string for comments: generic_comment:on + + Enhancements: + * Added confirm dialog for resetting profile fields (adds language string profile:resetdefault:confirm) + + +Version 1.8.12 +(January 4th, 2013 from https://github.com/Elgg/Elgg/tree/1.8) + Contributing Developers: + * Brett Profitt + * Cash Costello + * Jerome Bakker + * Matt Beckett + * Paweł Sroka + * Sem + * Steve Clay + + Bugfixes: + * Added an AJAX workaround for the rewrite test. + * Code cleanup to prevent some notices and warnings. + * Removed "original_order" in menu item anchor tags. + * Site menu's selected item correctly persists through content pages. + * Static caches rewritten and improved to prevent stale data being returned. + * Installation: Invalid characters in admin username are handled correctly. + * Messages: Fixed inbox link in email notifications. + * The Wire: Fixed objects not displaying correctly when upgrading from 1.7. + + Enhancements: + * Performance improvements and improved caching in entity loading. + * Added upgrade locking to prevent concurrent upgrade attempts. + * Replaced xml_to_object() and autop() with GPL / MIT-compatible code. + * Error messages (register_error()) only fade after being clicked. + * Groups: Added a sidebar entry to display membership status and a link to + group notification settings. + * Groups: Added pending membership and invitation requests to the sidebar. + * Groups: Better redirection for invisible and closed groups. + * Search: User profile fields are searched. + * Pages: Subpages can be reassigned to new parent pages. + * Twitter: Login with twitter supports persistent login and correctly forwards + after login. + + Version 1.8.11 (December 5th, 2012 from https://github.com/Elgg/Elgg/tree/1.8) diff --git a/README.txt b/README.txt index 5d9261ee4..dd604fd2b 100644 --- a/README.txt +++ b/README.txt @@ -1,5 +1,5 @@ Elgg -Copyright (c) 2008-2012 See COPYRIGHT.txt +Copyright (c) 2008-2013 See COPYRIGHT.txt See CONTRIBUTORS.txt for development credits. @@ -21,4 +21,4 @@ in the root of the package you downloaded. For installation instructions, see INSTALL.txt. -For upgrade instructions, see UPGRADE.txt.
\ No newline at end of file +For upgrade instructions, see UPGRADE.txt. diff --git a/_graphics/walled_garden/one_column_bottom.png b/_graphics/walled_garden/one_column_bottom.png Binary files differindex 1dfd7f8ad..bd2296896 100644 --- a/_graphics/walled_garden/one_column_bottom.png +++ b/_graphics/walled_garden/one_column_bottom.png diff --git a/_graphics/walled_garden/one_column_top.png b/_graphics/walled_garden/one_column_top.png Binary files differindex 429a88b75..dc8de438a 100644 --- a/_graphics/walled_garden/one_column_top.png +++ b/_graphics/walled_garden/one_column_top.png diff --git a/_graphics/walled_garden/two_column_bottom.png b/_graphics/walled_garden/two_column_bottom.png Binary files differindex 8aeceeeee..21e076991 100644 --- a/_graphics/walled_garden/two_column_bottom.png +++ b/_graphics/walled_garden/two_column_bottom.png diff --git a/_graphics/walled_garden/two_column_top.png b/_graphics/walled_garden/two_column_top.png Binary files differindex c28b3f630..cd71a4262 100644 --- a/_graphics/walled_garden/two_column_top.png +++ b/_graphics/walled_garden/two_column_top.png diff --git a/actions/admin/site/unlock_upgrade.php b/actions/admin/site/unlock_upgrade.php new file mode 100644 index 000000000..b625b1d26 --- /dev/null +++ b/actions/admin/site/unlock_upgrade.php @@ -0,0 +1,10 @@ +<?php +/** + * Unlocks the upgrade script + */ + +if (_elgg_upgrade_is_locked()) { + _elgg_upgrade_unlock(); +} +system_message(elgg_echo('upgrade:unlock:success')); +forward(REFERER); diff --git a/actions/login.php b/actions/login.php index ea7fb3508..1e5e92ede 100644 --- a/actions/login.php +++ b/actions/login.php @@ -7,7 +7,7 @@ */ // set forward url -if (isset($_SESSION['last_forward_from']) && $_SESSION['last_forward_from']) { +if (!empty($_SESSION['last_forward_from'])) { $forward_url = $_SESSION['last_forward_from']; unset($_SESSION['last_forward_from']); } elseif (get_input('returntoreferer')) { @@ -19,7 +19,7 @@ if (isset($_SESSION['last_forward_from']) && $_SESSION['last_forward_from']) { $username = get_input('username'); $password = get_input('password', null, false); -$persistent = get_input("persistent", false); +$persistent = (bool) get_input("persistent"); $result = false; if (empty($username) || empty($password)) { diff --git a/engine/classes/ElggAttributeLoader.php b/engine/classes/ElggAttributeLoader.php new file mode 100644 index 000000000..602bb8bae --- /dev/null +++ b/engine/classes/ElggAttributeLoader.php @@ -0,0 +1,199 @@ +<?php + +/** + * Loads ElggEntity attributes from DB or validates those passed in via constructor + * + * @access private + */ +class ElggAttributeLoader { + + /** + * @var array names of attributes in all entities + */ + protected static $primary_attr_names = array( + 'guid', + 'type', + 'subtype', + 'owner_guid', + 'container_guid', + 'site_guid', + 'access_id', + 'time_created', + 'time_updated', + 'last_action', + 'enabled' + ); + + /** + * @var array names of secondary attributes required for the entity + */ + protected $secondary_attr_names = array(); + + /** + * @var string entity type (not class) required for fetched primaries + */ + protected $required_type; + + /** + * @var array + */ + protected $initialized_attributes; + + /** + * @var string class of object being loaded + */ + protected $class; + + /** + * @var bool should access control be considered when fetching entity? + */ + public $requires_access_control = true; + + /** + * @var callable function used to load attributes from {prefix}entities table + */ + public $primary_loader = 'get_entity_as_row'; + + /** + * @var callable function used to load attributes from secondary table + */ + public $secondary_loader = ''; + + /** + * @var callable function used to load all necessary attributes + */ + public $full_loader = ''; + + /** + * @param string $class class of object being loaded + * @param string $required_type entity type this is being used to populate + * @param array $initialized_attrs attributes after initializeAttributes() has been run + * @throws InvalidArgumentException + */ + public function __construct($class, $required_type, array $initialized_attrs) { + if (!is_string($class)) { + throw new InvalidArgumentException('$class must be a class name.'); + } + $this->class = $class; + + if (!is_string($required_type)) { + throw new InvalidArgumentException('$requiredType must be a system entity type.'); + } + $this->required_type = $required_type; + + $this->initialized_attributes = $initialized_attrs; + unset($initialized_attrs['tables_split'], $initialized_attrs['tables_loaded']); + $all_attr_names = array_keys($initialized_attrs); + $this->secondary_attr_names = array_diff($all_attr_names, self::$primary_attr_names); + } + + protected function isMissingPrimaries($row) { + return array_diff(self::$primary_attr_names, array_keys($row)) !== array(); + } + + protected function isMissingSecondaries($row) { + return array_diff($this->secondary_attr_names, array_keys($row)) !== array(); + } + + protected function checkType($row) { + if ($row['type'] !== $this->required_type) { + $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($row['guid'], $this->class)); + throw new InvalidClassException($msg); + } + } + + /** + * Get all required attributes for the entity, validating any that are passed in. Returns empty array + * if can't be loaded (Check $failure_reason). + * + * This function splits loading between "primary" attributes (those in {prefix}entities table) and + * "secondary" attributes (e.g. those in {prefix}objects_entity), but can load all at once if a + * combined loader is available. + * + * @param mixed $row a row loaded from DB (array or stdClass) or a GUID + * @return array will be empty if failed to load all attributes (access control or entity doesn't exist) + * + * @throws InvalidArgumentException|LogicException|IncompleteEntityException + */ + public function getRequiredAttributes($row) { + if (!is_array($row) && !($row instanceof stdClass)) { + // assume row is the GUID + $row = array('guid' => $row); + } + $row = (array) $row; + if (empty($row['guid'])) { + throw new InvalidArgumentException('$row must be or contain a GUID'); + } + + // these must be present to support isFullyLoaded() + foreach (array('tables_split', 'tables_loaded') as $key) { + if (isset($this->initialized_attributes[$key])) { + $row[$key] = $this->initialized_attributes[$key]; + } + } + + $was_missing_primaries = $this->isMissingPrimaries($row); + $was_missing_secondaries = $this->isMissingSecondaries($row); + + // some types have a function to load all attributes at once, it should be faster + if (($was_missing_primaries || $was_missing_secondaries) && is_callable($this->full_loader)) { + $fetched = (array) call_user_func($this->full_loader, $row['guid']); + if (!$fetched) { + return array(); + } + $row = array_merge($row, $fetched); + $this->checkType($row); + } else { + if ($was_missing_primaries) { + if (!is_callable($this->primary_loader)) { + throw new LogicException('Primary attribute loader must be callable'); + } + if (!$this->requires_access_control) { + $ignoring_access = elgg_set_ignore_access(); + } + $fetched = (array) call_user_func($this->primary_loader, $row['guid']); + if (!$this->requires_access_control) { + elgg_set_ignore_access($ignoring_access); + } + if (!$fetched) { + return array(); + } + $row = array_merge($row, $fetched); + } + + // We must test type before trying to load the secondaries so that InvalidClassException + // gets thrown. Otherwise the secondary loader will fail and return false. + $this->checkType($row); + + if ($was_missing_secondaries) { + if (!is_callable($this->secondary_loader)) { + throw new LogicException('Secondary attribute loader must be callable'); + } + $fetched = (array) call_user_func($this->secondary_loader, $row['guid']); + if (!$fetched) { + if ($row['type'] === 'site') { + // A special case is needed for sites: When vanilla ElggEntities are created and + // saved, these are stored w/ type "site", but with no sites_entity row. These + // are probably only created in the unit tests. + // @todo Don't save vanilla ElggEntities with type "site" + $row['guid'] = (int) $row['guid']; + return $row; + } + throw new IncompleteEntityException("Secondary loader failed to return row for {$row['guid']}"); + } + $row = array_merge($row, $fetched); + } + } + + // loading complete: re-check missing and check type + if (($was_missing_primaries && $this->isMissingPrimaries($row)) + || ($was_missing_secondaries && $this->isMissingSecondaries($row))) { + throw new LogicException('Attribute loaders failed to return proper attributes'); + } + + // guid needs to be an int http://trac.elgg.org/ticket/4111 + $row['guid'] = (int) $row['guid']; + + return $row; + } +} diff --git a/engine/classes/ElggAutoP.php b/engine/classes/ElggAutoP.php new file mode 100644 index 000000000..89d77e583 --- /dev/null +++ b/engine/classes/ElggAutoP.php @@ -0,0 +1,309 @@ +<?php + +/** + * Create wrapper P and BR elements in HTML depending on newlines. Useful when + * users use newlines to signal line and paragraph breaks. In all cases output + * should be well-formed markup. + * + * In DIV elements, Ps are only added when there would be at + * least two of them. + */ +class ElggAutoP { + + public $encoding = 'UTF-8'; + + /** + * @var DOMDocument + */ + protected $_doc = null; + + /** + * @var DOMXPath + */ + protected $_xpath = null; + + protected $_blocks = 'address article area aside blockquote caption col colgroup dd + details div dl dt fieldset figure figcaption footer form h1 h2 h3 h4 h5 h6 header + hr hgroup legend map math menu nav noscript p pre section select style summary + table tbody td tfoot th thead tr ul ol option li'; + + /** + * @var array + */ + protected $_inlines = 'a abbr audio b button canvas caption cite code command datalist + del dfn em embed i iframe img input ins kbd keygen label map mark meter object + output progress q rp rt ruby s samp script select small source span strong style + sub sup textarea time var video wbr'; + + /** + * Descend into these elements to add Ps + * + * @var array + */ + protected $_descendList = 'article aside blockquote body details div footer form + header section'; + + /** + * Add Ps inside these elements + * + * @var array + */ + protected $_alterList = 'article aside blockquote body details div footer header + section'; + + protected $_unique = ''; + + public function __construct() { + $this->_blocks = preg_split('@\\s+@', $this->_blocks); + $this->_descendList = preg_split('@\\s+@', $this->_descendList); + $this->_alterList = preg_split('@\\s+@', $this->_alterList); + $this->_inlines = preg_split('@\\s+@', $this->_inlines); + $this->_unique = md5(__FILE__); + } + + /** + * Intance of class for singleton pattern. + * @var ElggAutoP + */ + private static $instance; + + /** + * Singleton pattern. + * @return ElggAutoP + */ + public static function getInstance() { + $className = __CLASS__; + if (!(self::$instance instanceof $className)) { + self::$instance = new $className(); + } + return self::$instance; + } + + /** + * Create wrapper P and BR elements in HTML depending on newlines. Useful when + * users use newlines to signal line and paragraph breaks. In all cases output + * should be well-formed markup. + * + * In DIV, LI, TD, and TH elements, Ps are only added when their would be at + * least two of them. + * + * @param string $html snippet + * @return string|false output or false if parse error occurred + */ + public function process($html) { + // normalize whitespace + $html = str_replace(array("\r\n", "\r"), "\n", $html); + + // allows preserving entities untouched + $html = str_replace('&', $this->_unique . 'AMP', $html); + + $this->_doc = new DOMDocument(); + + // parse to DOM, suppressing loadHTML warnings + // http://www.php.net/manual/en/domdocument.loadhtml.php#95463 + libxml_use_internal_errors(true); + + if (!$this->_doc->loadHTML("<html><meta http-equiv='content-type' " + . "content='text/html; charset={$this->encoding}'><body>{$html}</body>" + . "</html>")) { + return false; + } + + $this->_xpath = new DOMXPath($this->_doc); + // start processing recursively at the BODY element + $nodeList = $this->_xpath->query('//body[1]'); + $this->_addParagraphs($nodeList->item(0)); + + // serialize back to HTML + $html = $this->_doc->saveHTML(); + + // split AUTOPs into multiples at /\n\n+/ + $html = preg_replace('/(' . $this->_unique . 'NL){2,}/', '</autop><autop>', $html); + $html = str_replace(array($this->_unique . 'BR', $this->_unique . 'NL', '<br>'), + '<br />', + $html); + $html = str_replace('<br /></autop>', '</autop>', $html); + + // re-parse so we can handle new AUTOP elements + + if (!$this->_doc->loadHTML($html)) { + return false; + } + // must re-create XPath object after DOM load + $this->_xpath = new DOMXPath($this->_doc); + + // strip AUTOPs that only have comments/whitespace + foreach ($this->_xpath->query('//autop') as $autop) { + $hasContent = false; + if (trim($autop->textContent) !== '') { + $hasContent = true; + } else { + foreach ($autop->childNodes as $node) { + if ($node->nodeType === XML_ELEMENT_NODE) { + $hasContent = true; + break; + } + } + } + if (!$hasContent) { + // strip w/ preg_replace later (faster than moving nodes out) + $autop->setAttribute("r", "1"); + } + } + + // remove a single AUTOP inside certain elements + foreach ($this->_xpath->query('//div') as $el) { + $autops = $this->_xpath->query('./autop', $el); + if ($autops->length === 1) { + // strip w/ preg_replace later (faster than moving nodes out) + $autops->item(0)->setAttribute("r", "1"); + } + } + + $html = $this->_doc->saveHTML(); + + // trim to the contents of BODY + $bodyStart = strpos($html, '<body>'); + $bodyEnd = strpos($html, '</body>', $bodyStart + 6); + $html = substr($html, $bodyStart + 6, $bodyEnd - $bodyStart - 6); + + // strip AUTOPs that should be removed + $html = preg_replace('@<autop r="1">(.*?)</autop>@', '\\1', $html); + + // commit to converting AUTOPs to Ps + $html = str_replace('<autop>', "\n<p>", $html); + $html = str_replace('</autop>', "</p>\n", $html); + + $html = str_replace('<br>', '<br />', $html); + $html = str_replace($this->_unique . 'AMP', '&', $html); + return $html; + } + + /** + * Add P and BR elements as necessary + * + * @param DOMElement $el + */ + protected function _addParagraphs(DOMElement $el) { + // no need to recurse, just queue up + $elsToProcess = array($el); + $inlinesToProcess = array(); + while ($el = array_shift($elsToProcess)) { + // if true, we can alter all child nodes, if not, we'll just call + // _addParagraphs on each element in the descendInto list + $alterInline = in_array($el->nodeName, $this->_alterList); + + // inside affected elements, we want to trim leading whitespace from + // the first text node + $ltrimFirstTextNode = true; + + // should we open a new AUTOP element to move inline elements into? + $openP = true; + $autop = null; + + // after BR, ignore a newline + $isFollowingBr = false; + + $node = $el->firstChild; + while (null !== $node) { + if ($alterInline) { + if ($openP) { + $openP = false; + // create a P to move inline content into (this may be removed later) + $autop = $el->insertBefore($this->_doc->createElement('autop'), $node); + } + } + + $isElement = ($node->nodeType === XML_ELEMENT_NODE); + if ($isElement) { + $elName = $node->nodeName; + } + $isBlock = ($isElement && in_array($elName, $this->_blocks)); + + if ($alterInline) { + $isInline = $isElement && ! $isBlock; + $isText = ($node->nodeType === XML_TEXT_NODE); + $isLastInline = (! $node->nextSibling + || ($node->nextSibling->nodeType === XML_ELEMENT_NODE + && in_array($node->nextSibling->nodeName, $this->_blocks))); + if ($isElement) { + $isFollowingBr = ($node->nodeName === 'br'); + } + + if ($isText) { + $nodeText = $node->nodeValue; + if ($ltrimFirstTextNode) { + $nodeText = ltrim($nodeText); + $ltrimFirstTextNode = false; + } + if ($isFollowingBr && preg_match('@^[ \\t]*\\n[ \\t]*@', $nodeText, $m)) { + // if a user ends a line with <br>, don't add a second BR + $nodeText = substr($nodeText, strlen($m[0])); + } + if ($isLastInline) { + $nodeText = rtrim($nodeText); + } + $nodeText = str_replace("\n", $this->_unique . 'NL', $nodeText); + $tmpNode = $node; + $node = $node->nextSibling; // move loop to next node + + // alter node in place, then move into AUTOP + $tmpNode->nodeValue = $nodeText; + $autop->appendChild($tmpNode); + + continue; + } + } + if ($isBlock || ! $node->nextSibling) { + if ($isBlock) { + if (in_array($node->nodeName, $this->_descendList)) { + $elsToProcess[] = $node; + //$this->_addParagraphs($node); + } + } + $openP = true; + $ltrimFirstTextNode = true; + } + if ($alterInline) { + if (! $isBlock) { + $tmpNode = $node; + if ($isElement && false !== strpos($tmpNode->textContent, "\n")) { + $inlinesToProcess[] = $tmpNode; + } + $node = $node->nextSibling; + $autop->appendChild($tmpNode); + continue; + } + } + + $node = $node->nextSibling; + } + } + + // handle inline nodes + // no need to recurse, just queue up + while ($el = array_shift($inlinesToProcess)) { + $ignoreLeadingNewline = false; + foreach ($el->childNodes as $node) { + if ($node->nodeType === XML_ELEMENT_NODE) { + if ($node->nodeValue === 'BR') { + $ignoreLeadingNewline = true; + } else { + $ignoreLeadingNewline = false; + if (false !== strpos($node->textContent, "\n")) { + $inlinesToProcess[] = $node; + } + } + continue; + } elseif ($node->nodeType === XML_TEXT_NODE) { + $text = $node->nodeValue; + if ($text[0] === "\n" && $ignoreLeadingNewline) { + $text = substr($text, 1); + $ignoreLeadingNewline = false; + } + $node->nodeValue = str_replace("\n", $this->_unique . 'BR', $text); + } + } + } + } +} diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php index f00376481..7aace43ba 100644 --- a/engine/classes/ElggDiskFilestore.php +++ b/engine/classes/ElggDiskFilestore.php @@ -200,18 +200,18 @@ class ElggDiskFilestore extends ElggFilestore { * @return string The full path of where the file is stored */ public function getFilenameOnFilestore(ElggFile $file) { - $owner = $file->getOwnerEntity(); - if (!$owner) { - $owner = elgg_get_logged_in_user_entity(); + $owner_guid = $file->getOwnerGuid(); + if (!$owner_guid) { + $owner_guid = elgg_get_logged_in_user_guid(); } - if (!$owner) { + if (!$owner_guid) { $msg = elgg_echo('InvalidParameterException:MissingOwner', array($file->getFilename(), $file->guid)); throw new InvalidParameterException($msg); } - return $this->dir_root . $this->makefileMatrix($owner->guid) . $file->getFilename(); + return $this->dir_root . $this->makefileMatrix($owner_guid) . $file->getFilename(); } /** diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php index 121186196..ea257f368 100644 --- a/engine/classes/ElggGroup.php +++ b/engine/classes/ElggGroup.php @@ -324,37 +324,18 @@ class ElggGroup extends ElggEntity * @return bool */ protected function load($guid) { - // Test to see if we have the generic stuff - if (!parent::load($guid)) { - return false; - } + $attr_loader = new ElggAttributeLoader(get_class(), 'group', $this->attributes); + $attr_loader->requires_access_control = !($this instanceof ElggPlugin); + $attr_loader->secondary_loader = 'get_group_entity_as_row'; - // Only work with GUID from here - if ($guid instanceof stdClass) { - $guid = $guid->guid; - } - - // Check the type - if ($this->attributes['type'] != 'group') { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); - throw new InvalidClassException($msg); - } - - // Load missing data - $row = get_group_entity_as_row($guid); - if (($row) && (!$this->isFullyLoaded())) { - // If $row isn't a cached copy then increment the counter - $this->attributes['tables_loaded']++; - } - - // Now put these into the attributes array as core values - $objarray = (array) $row; - foreach ($objarray as $key => $value) { - $this->attributes[$key] = $value; + $attrs = $attr_loader->getRequiredAttributes($guid); + if (!$attrs) { + return false; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 - $this->attributes['guid'] = (int)$this->attributes['guid']; + $this->attributes = $attrs; + $this->attributes['tables_loaded'] = 2; + cache_entity($this); return true; } diff --git a/engine/classes/ElggGroupItemVisibility.php b/engine/classes/ElggGroupItemVisibility.php new file mode 100644 index 000000000..2c7e2abb4 --- /dev/null +++ b/engine/classes/ElggGroupItemVisibility.php @@ -0,0 +1,93 @@ +<?php + +/** + * Determines if otherwise visible items should be hidden from a user due to group + * policy or visibility. + * + * @class ElggGroupItemVisibility + * @package Elgg.Core + * @subpackage Groups + * + * @access private + */ +class ElggGroupItemVisibility { + + const REASON_MEMBERSHIP = 'membershiprequired'; + const REASON_LOGGEDOUT = 'loggedinrequired'; + const REASON_NOACCESS = 'noaccess'; + + /** + * @var bool + */ + public $shouldHideItems = false; + + /** + * @var string + */ + public $reasonHidden = ''; + + /** + * Determine visibility of items within a container for the current user + * + * @param int $container_guid GUID of a container (may/may not be a group) + * + * @return ElggGroupItemVisibility + * + * @todo Make this faster, considering it must run for every river item. + */ + static public function factory($container_guid) { + // cache because this may be called repeatedly during river display, and + // due to need to check group visibility, cache will be disabled for some + // get_entity() calls + static $cache = array(); + + $ret = new ElggGroupItemVisibility(); + + if (!$container_guid) { + return $ret; + } + + $user = elgg_get_logged_in_user_entity(); + $user_guid = $user ? $user->guid : 0; + + $container_guid = (int) $container_guid; + + $cache_key = "$container_guid|$user_guid"; + if (empty($cache[$cache_key])) { + // compute + + $container = get_entity($container_guid); + $is_visible = (bool) $container; + + if (!$is_visible) { + // see if it *really* exists... + $prev_access = elgg_set_ignore_access(); + $container = get_entity($container_guid); + elgg_set_ignore_access($prev_access); + } + + if ($container && $container instanceof ElggGroup) { + /* @var ElggGroup $container */ + + if ($is_visible) { + if (!$container->isPublicMembership()) { + if ($user) { + if (!$container->isMember($user) && !$user->isAdmin()) { + $ret->shouldHideItems = true; + $ret->reasonHidden = self::REASON_MEMBERSHIP; + } + } else { + $ret->shouldHideItems = true; + $ret->reasonHidden = self::REASON_LOGGEDOUT; + } + } + } else { + $ret->shouldHideItems = true; + $ret->reasonHidden = self::REASON_NOACCESS; + } + } + $cache[$cache_key] = $ret; + } + return $cache[$cache_key]; + } +} diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php index f43599999..d9a704dd9 100644 --- a/engine/classes/ElggMenuBuilder.php +++ b/engine/classes/ElggMenuBuilder.php @@ -205,7 +205,7 @@ class ElggMenuBuilder { // sort each section foreach ($this->menu as $index => $section) { foreach ($section as $key => $node) { - $section[$key]->original_order = $key; + $section[$key]->setData('original_order', $key); } usort($section, $sort_callback); $this->menu[$index] = $section; @@ -240,7 +240,7 @@ class ElggMenuBuilder { $result = strnatcmp($at, $bt); if ($result === 0) { - return $a->original_order - $b->original_order; + return $a->getData('original_order') - $b->getData('original_order'); } return $result; } @@ -258,7 +258,7 @@ class ElggMenuBuilder { $result = strcmp($an, $bn); if ($result === 0) { - return $a->original_order - $b->original_order; + return $a->getData('original_order') - $b->getData('original_order'); } return $result; } @@ -275,7 +275,7 @@ class ElggMenuBuilder { $bw = $b->getWeight(); if ($aw == $bw) { - return $a->original_order - $b->original_order; + return $a->getData('original_order') - $b->getData('original_order'); } return $aw - $bw; } diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index fe25f3ddd..81ce6c099 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -543,7 +543,7 @@ class ElggMenuItem { */ public function sortChildren($sortFunction) { foreach ($this->data['children'] as $key => $node) { - $this->data['children'][$key]->original_order = $key; + $this->data['children'][$key]->data['original_order'] = $key; } usort($this->data['children'], $sortFunction); } diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php index fa6296c8c..6263f84f6 100644 --- a/engine/classes/ElggObject.php +++ b/engine/classes/ElggObject.php @@ -99,37 +99,18 @@ class ElggObject extends ElggEntity { * @throws InvalidClassException */ protected function load($guid) { - // Load data from entity table if needed - if (!parent::load($guid)) { - return false; - } + $attr_loader = new ElggAttributeLoader(get_class(), 'object', $this->attributes); + $attr_loader->requires_access_control = !($this instanceof ElggPlugin); + $attr_loader->secondary_loader = 'get_object_entity_as_row'; - // Only work with GUID from here - if ($guid instanceof stdClass) { - $guid = $guid->guid; - } - - // Check the type - if ($this->attributes['type'] != 'object') { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); - throw new InvalidClassException($msg); - } - - // Load missing data - $row = get_object_entity_as_row($guid); - if (($row) && (!$this->isFullyLoaded())) { - // If $row isn't a cached copy then increment the counter - $this->attributes['tables_loaded']++; - } - - // Now put these into the attributes array as core values - $objarray = (array) $row; - foreach ($objarray as $key => $value) { - $this->attributes[$key] = $value; + $attrs = $attr_loader->getRequiredAttributes($guid); + if (!$attrs) { + return false; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 - $this->attributes['guid'] = (int)$this->attributes['guid']; + $this->attributes = $attrs; + $this->attributes['tables_loaded'] = 2; + cache_entity($this); return true; } @@ -149,7 +130,7 @@ class ElggObject extends ElggEntity { // Save ElggObject-specific attributes return create_object_entity($this->get('guid'), $this->get('title'), - $this->get('description'), $this->get('container_guid')); + $this->get('description')); } /** diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index c6ce2905f..8f71b79a8 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -82,64 +82,6 @@ class ElggPlugin extends ElggObject { } /** - * Overridden from ElggEntity and ElggObject::load(). Core always inits plugins with - * a query joined to the objects_entity table, so all the info is there. - * - * @param mixed $guid GUID of an ElggObject or the stdClass object from entities table - * - * @return bool - * @throws InvalidClassException - */ - protected function load($guid) { - - $expected_attributes = $this->attributes; - unset($expected_attributes['tables_split']); - unset($expected_attributes['tables_loaded']); - - // this was loaded with a full join - $needs_loaded = false; - - if ($guid instanceof stdClass) { - $row = (array) $guid; - $missing_attributes = array_diff_key($expected_attributes, $row); - if ($missing_attributes) { - $needs_loaded = true; - $guid = $row['guid']; - } else { - $this->attributes = $row; - } - } else { - $needs_loaded = true; - } - - if ($needs_loaded) { - $entity = (array) get_entity_as_row($guid); - $object = (array) get_object_entity_as_row($guid); - - if (!$entity || !$object) { - return false; - } - - $this->attributes = array_merge($this->attributes, $entity, $object); - } - - $this->attributes['tables_loaded'] = 2; - - // Check the type - if ($this->attributes['type'] != 'object') { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); - throw new InvalidClassException($msg); - } - - // guid needs to be an int http://trac.elgg.org/ticket/4111 - $this->attributes['guid'] = (int)$this->attributes['guid']; - - cache_entity($this); - - return true; - } - - /** * Save the plugin object. Make sure required values exist. * * @see ElggObject::save() @@ -361,10 +303,7 @@ class ElggPlugin extends ElggObject { $return = array(); foreach ($private_settings as $setting) { - $name = substr($setting->name, $ps_prefix_len); - $value = $setting->value; - - $return[$name] = $value; + $return[$setting->name] = $setting->value; } return $return; diff --git a/engine/classes/ElggPluginManifest.php b/engine/classes/ElggPluginManifest.php index a4f5bb95d..6912c2b08 100644 --- a/engine/classes/ElggPluginManifest.php +++ b/engine/classes/ElggPluginManifest.php @@ -130,7 +130,7 @@ class ElggPluginManifest { } // see if we need to construct the xml object. - if ($manifest instanceof XmlElement) { + if ($manifest instanceof ElggXMLElement) { $manifest_obj = $manifest; } else { if (substr(trim($manifest), 0, 1) == '<') { diff --git a/engine/classes/ElggPluginManifestParser.php b/engine/classes/ElggPluginManifestParser.php index b0480d4d8..af152b561 100644 --- a/engine/classes/ElggPluginManifestParser.php +++ b/engine/classes/ElggPluginManifestParser.php @@ -53,10 +53,10 @@ abstract class ElggPluginManifestParser { /** * Loads the manifest XML to be parsed. * - * @param XmlElement $xml The Manifest XML object to be parsed - * @param object $caller The object calling this parser. + * @param ElggXmlElement $xml The Manifest XML object to be parsed + * @param object $caller The object calling this parser. */ - public function __construct(XmlElement $xml, $caller) { + public function __construct(ElggXMLElement $xml, $caller) { $this->manifestObject = $xml; $this->caller = $caller; } diff --git a/engine/classes/ElggSession.php b/engine/classes/ElggSession.php index 13a33736c..9750f063e 100644 --- a/engine/classes/ElggSession.php +++ b/engine/classes/ElggSession.php @@ -54,7 +54,7 @@ class ElggSession implements ArrayAccess { * * @param mixed $key Name * - * @return void + * @return mixed */ function offsetGet($key) { if (!ElggSession::$__localcache) { @@ -98,7 +98,7 @@ class ElggSession implements ArrayAccess { * * @param int $offset Offset * - * @return int + * @return bool */ function offsetExists($offset) { if (isset(ElggSession::$__localcache[$offset])) { @@ -112,6 +112,8 @@ class ElggSession implements ArrayAccess { if ($this->offsetGet($offset)) { return true; } + + return false; } @@ -132,10 +134,10 @@ class ElggSession implements ArrayAccess { * @param string $key Name * @param mixed $value Value * - * @return mixed + * @return void */ function set($key, $value) { - return $this->offsetSet($key, $value); + $this->offsetSet($key, $value); } /** @@ -143,9 +145,9 @@ class ElggSession implements ArrayAccess { * * @param string $key Name * - * @return bool + * @return void */ function del($key) { - return $this->offsetUnset($key); + $this->offsetUnset($key); } } diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index 401939005..1fe49b85c 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -117,37 +117,18 @@ class ElggSite extends ElggEntity { * @throws InvalidClassException */ protected function load($guid) { - // Test to see if we have the generic stuff - if (!parent::load($guid)) { - return false; - } - - // Only work with GUID from here - if ($guid instanceof stdClass) { - $guid = $guid->guid; - } - - // Check the type - if ($this->attributes['type'] != 'site') { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); - throw new InvalidClassException($msg); - } + $attr_loader = new ElggAttributeLoader(get_class(), 'site', $this->attributes); + $attr_loader->requires_access_control = !($this instanceof ElggPlugin); + $attr_loader->secondary_loader = 'get_site_entity_as_row'; - // Load missing data - $row = get_site_entity_as_row($guid); - if (($row) && (!$this->isFullyLoaded())) { - // If $row isn't a cached copy then increment the counter - $this->attributes['tables_loaded']++; - } - - // Now put these into the attributes array as core values - $objarray = (array) $row; - foreach ($objarray as $key => $value) { - $this->attributes[$key] = $value; + $attrs = $attr_loader->getRequiredAttributes($guid); + if (!$attrs) { + return false; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 - $this->attributes['guid'] = (int)$this->attributes['guid']; + $this->attributes = $attrs; + $this->attributes['tables_loaded'] = 2; + cache_entity($this); return true; } @@ -381,6 +362,11 @@ class ElggSite extends ElggEntity { public function checkWalledGarden() { global $CONFIG; + // command line calls should not invoke the walled garden check + if (PHP_SAPI === 'cli') { + return; + } + if ($CONFIG->walled_garden) { if ($CONFIG->default_access == ACCESS_PUBLIC) { $CONFIG->default_access = ACCESS_LOGGED_IN; diff --git a/engine/classes/ElggStaticVariableCache.php b/engine/classes/ElggStaticVariableCache.php index 787d35a32..17d849400 100644 --- a/engine/classes/ElggStaticVariableCache.php +++ b/engine/classes/ElggStaticVariableCache.php @@ -21,8 +21,8 @@ class ElggStaticVariableCache extends ElggSharedMemoryCache { * This function creates a variable cache in a static variable in * memory, optionally with a given namespace (to avoid overlap). * - * @param string $namespace The namespace for this cache to write to - * note, namespaces of the same name are shared! + * @param string $namespace The namespace for this cache to write to. + * @note namespaces of the same name are shared! */ function __construct($namespace = 'default') { $this->setNamespace($namespace); diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index d7bb89265..6c1cdc1de 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -106,37 +106,17 @@ class ElggUser extends ElggEntity * @return bool */ protected function load($guid) { - // Test to see if we have the generic stuff - if (!parent::load($guid)) { - return false; - } + $attr_loader = new ElggAttributeLoader(get_class(), 'user', $this->attributes); + $attr_loader->secondary_loader = 'get_user_entity_as_row'; - // Only work with GUID from here - if ($guid instanceof stdClass) { - $guid = $guid->guid; - } - - // Check the type - if ($this->attributes['type'] != 'user') { - $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); - throw new InvalidClassException($msg); - } - - // Load missing data - $row = get_user_entity_as_row($guid); - if (($row) && (!$this->isFullyLoaded())) { - // If $row isn't a cached copy then increment the counter - $this->attributes['tables_loaded']++; - } - - // Now put these into the attributes array as core values - $objarray = (array) $row; - foreach ($objarray as $key => $value) { - $this->attributes[$key] = $value; + $attrs = $attr_loader->getRequiredAttributes($guid); + if (!$attrs) { + return false; } - // guid needs to be an int http://trac.elgg.org/ticket/4111 - $this->attributes['guid'] = (int)$this->attributes['guid']; + $this->attributes = $attrs; + $this->attributes['tables_loaded'] = 2; + cache_entity($this); return true; } diff --git a/engine/classes/ElggXMLElement.php b/engine/classes/ElggXMLElement.php new file mode 100644 index 000000000..65a13912c --- /dev/null +++ b/engine/classes/ElggXMLElement.php @@ -0,0 +1,115 @@ +<?php +/** + * A parser for XML that uses SimpleXMLElement + * + * @package Elgg.Core + * @subpackage XML + */ +class ElggXMLElement { + /** + * @var SimpleXMLElement + */ + private $_element; + + /** + * Creates an ElggXMLParser from a string or existing SimpleXMLElement + * + * @param string|SimpleXMLElement $xml The XML to parse + */ + public function __construct($xml) { + if ($xml instanceof SimpleXMLElement) { + $this->_element = $xml; + } else { + $this->_element = new SimpleXMLElement($xml); + } + } + + /** + * @return string The name of the element + */ + public function getName() { + return $this->_element->getName(); + } + + /** + * @return array:string The attributes + */ + public function getAttributes() { + //include namespace declarations as attributes + $xmlnsRaw = $this->_element->getNamespaces(); + $xmlns = array(); + foreach ($xmlnsRaw as $key => $val) { + $label = 'xmlns' . ($key ? ":$key" : $key); + $xmlns[$label] = $val; + } + //get attributes and merge with namespaces + $attrRaw = $this->_element->attributes(); + $attr = array(); + foreach ($attrRaw as $key => $val) { + $attr[$key] = $val; + } + $attr = array_merge((array) $xmlns, (array) $attr); + $result = array(); + foreach ($attr as $key => $val) { + $result[$key] = (string) $val; + } + return $result; + } + + /** + * @return string CData + */ + public function getContent() { + return (string) $this->_element; + } + + /** + * @return array:ElggXMLElement Child elements + */ + public function getChildren() { + $children = $this->_element->children(); + $result = array(); + foreach ($children as $val) { + $result[] = new ElggXMLElement($val); + } + + return $result; + } + + function __get($name) { + switch ($name) { + case 'name': + return $this->getName(); + break; + case 'attributes': + return $this->getAttributes(); + break; + case 'content': + return $this->getContent(); + break; + case 'children': + return $this->getChildren(); + break; + } + return null; + } + + function __isset($name) { + switch ($name) { + case 'name': + return $this->getName() !== null; + break; + case 'attributes': + return $this->getAttributes() !== null; + break; + case 'content': + return $this->getContent() !== null; + break; + case 'children': + return $this->getChildren() !== null; + break; + } + return false; + } + +}
\ No newline at end of file diff --git a/engine/classes/IncompleteEntityException.php b/engine/classes/IncompleteEntityException.php new file mode 100644 index 000000000..8c86edcc6 --- /dev/null +++ b/engine/classes/IncompleteEntityException.php @@ -0,0 +1,10 @@ +<?php +/** + * IncompleteEntityException + * Thrown when constructing an entity that is missing its secondary entity table + * + * @package Elgg.Core + * @subpackage Exception + * @access private + */ +class IncompleteEntityException extends Exception {} diff --git a/engine/lib/access.php b/engine/lib/access.php index 3b2b7aeaa..f7d3bf7ea 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -12,6 +12,26 @@ */ /** + * Return an ElggCache static variable cache for the access caches + * + * @staticvar ElggStaticVariableCache $access_cache + * @return \ElggStaticVariableCache + * @access private + */ +function _elgg_get_access_cache() { + /** + * A default filestore cache using the dataroot. + */ + static $access_cache; + + if (!$access_cache) { + $access_cache = new ElggStaticVariableCache('access'); + } + + return $access_cache; +} + +/** * Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause. * * @uses get_access_array @@ -29,10 +49,10 @@ */ function get_access_list($user_id = 0, $site_id = 0, $flush = false) { global $CONFIG, $init_finished; - static $access_list; - - if (!isset($access_list)) { - $access_list = array(); + $cache = _elgg_get_access_cache(); + + if ($flush) { + $cache->clear(); } if ($user_id == 0) { @@ -45,20 +65,20 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (isset($access_list[$user_id]) && $flush == false) { - return $access_list[$user_id]; - } + $hash = $user_id . $site_id . 'get_access_list'; - $access = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")"; + if ($cache[$hash]) { + return $cache[$hash]; + } + + $access_array = get_access_array($user_id, $site_id, $flush); + $access = "(" . implode(",", $access_array) . ")"; - // only cache if done with init and access is enabled (unless admin user) - // session is loaded before init is finished, so don't need to check for user session - if ($init_finished && (elgg_is_admin_logged_in() || !elgg_get_ignore_access())) { - $access_list[$user_id] = $access; - return $access_list[$user_id]; - } else { - return $access; + if ($init_finished) { + $cache[$hash] = $access; } + + return $access; } /** @@ -86,9 +106,11 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) { function get_access_array($user_id = 0, $site_id = 0, $flush = false) { global $CONFIG, $init_finished; - // @todo everything from the db is cached. - // this cache might be redundant. But db cache is flushed on every db write. - static $access_array = array(); + $cache = _elgg_get_access_cache(); + + if ($flush) { + $cache->clear(); + } if ($user_id == 0) { $user_id = elgg_get_logged_in_user_guid(); @@ -101,35 +123,41 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (empty($access_array[$user_id]) || $flush == true) { - $tmp_access_array = array(ACCESS_PUBLIC); + $hash = $user_id . $site_id . 'get_access_array'; + + if ($cache[$hash]) { + $access_array = $cache[$hash]; + } else { + $access_array = array(ACCESS_PUBLIC); // The following can only return sensible data if the user is logged in. if (elgg_is_logged_in()) { - $tmp_access_array[] = ACCESS_LOGGED_IN; + $access_array[] = ACCESS_LOGGED_IN; // Get ACL memberships $query = "SELECT am.access_collection_id" . " FROM {$CONFIG->dbprefix}access_collection_membership am" . " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id" - . " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; + . " WHERE am.user_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)"; - if ($collections = get_data($query)) { + $collections = get_data($query); + if ($collections) { foreach ($collections as $collection) { if (!empty($collection->access_collection_id)) { - $tmp_access_array[] = (int)$collection->access_collection_id; + $access_array[] = (int)$collection->access_collection_id; } } } // Get ACLs owned. $query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag "; - $query .= "WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; + $query .= "WHERE ag.owner_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)"; - if ($collections = get_data($query)) { + $collections = get_data($query); + if ($collections) { foreach ($collections as $collection) { if (!empty($collection->id)) { - $tmp_access_array[] = (int)$collection->id; + $access_array[] = (int)$collection->id; } } } @@ -137,21 +165,21 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) { $ignore_access = elgg_check_access_overrides($user_id); if ($ignore_access == true) { - $tmp_access_array[] = ACCESS_PRIVATE; + $access_array[] = ACCESS_PRIVATE; } + } - // only cache if done with init and access is enabled (unless admin user) - // session is loaded before init is finished, so don't need to check for user session - if ($init_finished && (elgg_is_admin_logged_in() || !elgg_get_ignore_access())) { - $access_array[$user_id] = $tmp_access_array; - } + if ($init_finished) { + $cache[$hash] = $access_array; } - } else { - $tmp_access_array = $access_array[$user_id]; } - $options = array('user_id' => $user_id, 'site_id' => $site_id); - return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $tmp_access_array); + $options = array( + 'user_id' => $user_id, + 'site_id' => $site_id + ); + + return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $access_array); } /** @@ -397,9 +425,12 @@ function has_access_to_entity($entity, $user = null) { * @link http://docs.elgg.org/Access */ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { - global $CONFIG; - //@todo this is probably not needed since caching happens at the DB level. - static $access_array; + global $CONFIG, $init_finished; + $cache = _elgg_get_access_cache(); + + if ($flush) { + $cache->clear(); + } if ($user_id == 0) { $user_id = elgg_get_logged_in_user_guid(); @@ -412,37 +443,41 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) { $user_id = (int) $user_id; $site_id = (int) $site_id; - if (empty($access_array[$user_id]) || $flush == true) { - $query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag "; - $query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)"; - $query .= " AND (ag.owner_guid = {$user_id})"; - // ACCESS_PRIVATE through ACCESS_PUBLIC take 0 through 2 - // @todo this AND clause is unnecessary because of id starts at 3 for table - $query .= " AND ag.id >= 3"; + $hash = $user_id . $site_id . 'get_write_access_array'; - $tmp_access_array = array( + if ($cache[$hash]) { + $access_array = $cache[$hash]; + } else { + // @todo is there such a thing as public write access? + $access_array = array( ACCESS_PRIVATE => elgg_echo("PRIVATE"), ACCESS_FRIENDS => elgg_echo("access:friends:label"), ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"), ACCESS_PUBLIC => elgg_echo("PUBLIC") ); + + $query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag "; + $query .= " WHERE (ag.site_guid = $site_id OR ag.site_guid = 0)"; + $query .= " AND (ag.owner_guid = $user_id)"; + $collections = get_data($query); if ($collections) { foreach ($collections as $collection) { - $tmp_access_array[$collection->id] = $collection->name; + $access_array[$collection->id] = $collection->name; } } - $access_array[$user_id] = $tmp_access_array; - } else { - $tmp_access_array = $access_array[$user_id]; + if ($init_finished) { + $cache[$hash] = $access_array; + } } - $options = array('user_id' => $user_id, 'site_id' => $site_id); - $tmp_access_array = elgg_trigger_plugin_hook('access:collections:write', 'user', - $options, $tmp_access_array); - - return $tmp_access_array; + $options = array( + 'user_id' => $user_id, + 'site_id' => $site_id + ); + return elgg_trigger_plugin_hook('access:collections:write', 'user', + $options, $access_array); } /** @@ -871,6 +906,8 @@ function get_readable_access_level($entity_access_id) { * @tip Use this to access entities in automated scripts * when no user is logged in. * + * @note This clears the access cache. + * * @warning This will not show disabled entities. * Use {@link access_show_hidden_entities()} to access disabled entities. * @@ -882,6 +919,8 @@ function get_readable_access_level($entity_access_id) { * @see elgg_get_ignore_access() */ function elgg_set_ignore_access($ignore = true) { + $cache = _elgg_get_access_cache(); + $cache->clear(); $elgg_access = elgg_get_access_object(); return $elgg_access->setIgnoreAccess($ignore); } diff --git a/engine/lib/admin.php b/engine/lib/admin.php index 3f23f079c..35ab5599d 100644 --- a/engine/lib/admin.php +++ b/engine/lib/admin.php @@ -233,6 +233,7 @@ function admin_init() { elgg_register_action('admin/site/update_basic', '', 'admin'); elgg_register_action('admin/site/update_advanced', '', 'admin'); elgg_register_action('admin/site/flush_cache', '', 'admin'); + elgg_register_action('admin/site/unlock_upgrade', '', 'admin'); elgg_register_action('admin/menu/save', '', 'admin'); @@ -422,7 +423,7 @@ function admin_pagesetup() { elgg_register_menu_item('admin_footer', array( 'name' => 'community_forums', 'text' => elgg_echo('admin:footer:community_forums'), - 'href' => 'http://community.elgg.org/pg/groups/world/', + 'href' => 'http://community.elgg.org/groups/all/', )); elgg_register_menu_item('admin_footer', array( diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 2036ccd61..3b9f84703 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -316,8 +316,6 @@ function elgg_list_annotations($options) { * * annotation_owner_guids => NULL|ARR guids for annotaiton owners * - * annotation_ids => NULL|ARR Annotation IDs - * * @return mixed If count, int. If not count, array. false on errors. * @since 1.7.0 */ @@ -336,8 +334,6 @@ function elgg_get_entities_from_annotations(array $options = array()) { 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE, - 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE, - 'order_by' => 'maxtime desc', 'group_by' => 'a.entity_guid' ); @@ -345,12 +341,13 @@ function elgg_get_entities_from_annotations(array $options = array()) { $options = array_merge($defaults, $options); $singulars = array('annotation_name', 'annotation_value', - 'annotation_name_value_pair', 'annotation_owner_guid', 'annotation_id'); + 'annotation_name_value_pair', 'annotation_owner_guid'); $options = elgg_normalise_plural_options_array($options, $singulars); + $options = elgg_entities_get_metastrings_options('annotation', $options); - if (!$options = elgg_entities_get_metastrings_options('annotation', $options)) { - return FALSE; + if (!$options) { + return false; } // special sorting for annotations diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index dd3cba25d..540605876 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -710,9 +710,12 @@ function elgg_register_event_handler($event, $object_type, $callback, $priority */ function elgg_unregister_event_handler($event, $object_type, $callback) { global $CONFIG; - foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) { - if ($event_callback == $callback) { - unset($CONFIG->events[$event][$object_type][$key]); + + if (isset($CONFIG->events[$event]) && isset($CONFIG->events[$event][$object_type])) { + foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) { + if ($event_callback == $callback) { + unset($CONFIG->events[$event][$object_type][$key]); + } } } } @@ -889,9 +892,12 @@ function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority = */ function elgg_unregister_plugin_hook_handler($hook, $entity_type, $callback) { global $CONFIG; - foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) { - if ($hook_callback == $callback) { - unset($CONFIG->hooks[$hook][$entity_type][$key]); + + if (isset($CONFIG->hooks[$hook]) && isset($CONFIG->hooks[$hook][$entity_type])) { + foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) { + if ($hook_callback == $callback) { + unset($CONFIG->hooks[$hook][$entity_type][$key]); + } } } } @@ -1073,8 +1079,8 @@ function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) { case E_USER_WARNING : case E_RECOVERABLE_ERROR: // (e.g. type hint violation) - // check if the error wasn't suppressed by @-functionname - if(error_reporting()){ + // check if the error wasn't suppressed by the error control operator (@) + if (error_reporting()) { error_log("PHP WARNING: $error"); } break; diff --git a/engine/lib/entities.php b/engine/lib/entities.php index fda554388..ce736ce05 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -773,7 +773,13 @@ function get_entity($guid) { } } - $new_entity = entity_row_to_elggstar($entity_row); + // don't let incomplete entities cause fatal exceptions + try { + $new_entity = entity_row_to_elggstar($entity_row); + } catch (IncompleteEntityException $e) { + return false; + } + if ($new_entity) { cache_entity($new_entity); } @@ -1018,7 +1024,12 @@ function elgg_get_entities(array $options = array()) { $query .= " LIMIT $offset, $limit"; } - $dt = get_data($query, $options['callback']); + if ($options['callback'] === 'entity_row_to_elggstar') { + $dt = _elgg_fetch_entities_from_sql($query); + } else { + $dt = get_data($query, $options['callback']); + } + if ($dt) { // populate entity and metadata caches $guids = array(); @@ -1047,6 +1058,97 @@ function elgg_get_entities(array $options = array()) { } /** + * Return entities from an SQL query generated by elgg_get_entities. + * + * @param string $sql + * @return ElggEntity[] + * + * @access private + * @throws LogicException + */ +function _elgg_fetch_entities_from_sql($sql) { + static $plugin_subtype; + if (null === $plugin_subtype) { + $plugin_subtype = get_subtype_id('object', 'plugin'); + } + + // Keys are types, values are columns that, if present, suggest that the secondary + // table is already JOINed + $types_to_optimize = array( + 'object' => 'title', + 'user' => 'password', + 'group' => 'name', + ); + + $rows = get_data($sql); + + // guids to look up in each type + $lookup_types = array(); + // maps GUIDs to the $rows key + $guid_to_key = array(); + + if (isset($rows[0]->type, $rows[0]->subtype) + && $rows[0]->type === 'object' + && $rows[0]->subtype == $plugin_subtype) { + // Likely the entire resultset is plugins, which have already been optimized + // to JOIN the secondary table. In this case we allow retrieving from cache, + // but abandon the extra queries. + $types_to_optimize = array(); + } + + // First pass: use cache where possible, gather GUIDs that we're optimizing + foreach ($rows as $i => $row) { + if (empty($row->guid) || empty($row->type)) { + throw new LogicException('Entity row missing guid or type'); + } + if ($entity = retrieve_cached_entity($row->guid)) { + $rows[$i] = $entity; + continue; + } + if (isset($types_to_optimize[$row->type])) { + // check if row already looks JOINed. + if (isset($row->{$types_to_optimize[$row->type]})) { + // Row probably already contains JOINed secondary table. Don't make another query just + // to pull data that's already there + continue; + } + $lookup_types[$row->type][] = $row->guid; + $guid_to_key[$row->guid] = $i; + } + } + // Do secondary queries and merge rows + if ($lookup_types) { + $dbprefix = elgg_get_config('dbprefix'); + } + foreach ($lookup_types as $type => $guids) { + $set = "(" . implode(',', $guids) . ")"; + $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set"; + $secondary_rows = get_data($sql); + if ($secondary_rows) { + foreach ($secondary_rows as $secondary_row) { + $key = $guid_to_key[$secondary_row->guid]; + // cast to arrays to merge then cast back + $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row); + } + } + } + // Second pass to finish conversion + foreach ($rows as $i => $row) { + if ($row instanceof ElggEntity) { + continue; + } else { + try { + $rows[$i] = entity_row_to_elggstar($row); + } catch (IncompleteEntityException $e) { + // don't let incomplete entities throw fatal errors + unset($rows[$i]); + } + } + } + return $rows; +} + +/** * Returns SQL where clause for type and subtype on main entity table * * @param string $table Entity table prefix as defined in SELECT...FROM entities $table diff --git a/engine/lib/group.php b/engine/lib/group.php index feb1f1e7f..5a38e1ea6 100644 --- a/engine/lib/group.php +++ b/engine/lib/group.php @@ -33,6 +33,7 @@ function get_group_entity_as_row($guid) { * @param string $description Description * * @return bool + * @access private */ function create_group_entity($guid, $name, $description) { global $CONFIG; @@ -247,48 +248,42 @@ function get_users_membership($user_guid) { } /** - * Checks access to a group. + * May the current user access item(s) on this page? If the page owner is a group, + * membership, visibility, and logged in status are taken into account. * * @param boolean $forward If set to true (default), will forward the page; * if set to false, will return true or false. * - * @return true|false If $forward is set to false. + * @return bool If $forward is set to false. */ function group_gatekeeper($forward = true) { - $allowed = true; - $url = ''; - - if ($group = elgg_get_page_owner_entity()) { - if ($group instanceof ElggGroup) { - $url = $group->getURL(); - if (!$group->isPublicMembership()) { - // closed group so must be member or an admin - - if (!elgg_is_logged_in()) { - $allowed = false; - if ($forward == true) { - $_SESSION['last_forward_from'] = current_page_url(); - register_error(elgg_echo('loggedinrequired')); - forward('', 'login'); - } - } else if (!$group->isMember(elgg_get_logged_in_user_entity())) { - $allowed = false; - } - // Admin override - if (elgg_is_admin_logged_in()) { - $allowed = true; - } - } - } + $page_owner_guid = elgg_get_page_owner_guid(); + if (!$page_owner_guid) { + return true; } + $visibility = ElggGroupItemVisibility::factory($page_owner_guid); - if ($forward && $allowed == false) { - register_error(elgg_echo('membershiprequired')); - forward($url, 'member'); + if (!$visibility->shouldHideItems) { + return true; + } + if ($forward) { + // only forward to group if user can see it + $group = get_entity($page_owner_guid); + $forward_url = $group ? $group->getURL() : ''; + + if (!elgg_is_logged_in()) { + $_SESSION['last_forward_from'] = current_page_url(); + $forward_reason = 'login'; + } else { + $forward_reason = 'member'; + } + + register_error(elgg_echo($visibility->reasonHidden)); + forward($forward_url, $forward_reason); } - return $allowed; + return false; } /** diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index 8c3952594..86624cd7c 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -308,6 +308,32 @@ function elgg_site_menu_setup($hook, $type, $return, $params) { $return['more'] = array_splice($return['default'], $max_display_items); } } + + // check if we have anything selected + $selected = false; + foreach ($return as $section_name => $section) { + foreach ($section as $key => $item) { + if ($item->getSelected()) { + $selected = true; + break 2; + } + } + } + + if (!$selected) { + // nothing selected, match name to context + foreach ($return as $section_name => $section) { + foreach ($section as $key => $item) { + // only highlight internal links + if (strpos($item->getHref(), elgg_get_site_url()) === 0) { + if ($item->getName() == elgg_get_context()) { + $return[$section_name][$key]->setSelected(true); + break 2; + } + } + } + } + } return $return; } diff --git a/engine/lib/objects.php b/engine/lib/objects.php index f186c66cb..e5e8f67c4 100644 --- a/engine/lib/objects.php +++ b/engine/lib/objects.php @@ -31,6 +31,7 @@ function get_object_entity_as_row($guid) { * @param string $description The object's description * * @return bool + * @access private */ function create_object_entity($guid, $title, $description) { global $CONFIG; diff --git a/engine/lib/output.php b/engine/lib/output.php index 352de863b..9295f2173 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -16,7 +16,7 @@ **/ function parse_urls($text) { // @todo this causes problems with <attr = "val"> - // must be ing <attr="val"> format (no space). + // must be in <attr="val"> format (no space). // By default htmlawed rewrites tags to this format. // if PHP supported conditional negative lookbehinds we could use this: // $r = preg_replace_callback('/(?<!=)(?<![ ])?(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i', @@ -43,51 +43,26 @@ function parse_urls($text) { /** * Create paragraphs from text with line spacing - * Borrowed from Wordpress. * * @param string $pee The string - * @param bool $br Add BRs? + * @deprecated Use elgg_autop instead + * @todo Add deprecation warning in 1.9 * - * @todo Rewrite * @return string **/ -function autop($pee, $br = 1) { - $pee = $pee . "\n"; // just to make things a little easier, pad the end - $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee); - // Space things out a little - $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)'; - $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee); - $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee); - $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines - if (strpos($pee, '<object') !== false) { - $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed - $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee); - } - $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates - $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end - $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace - $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee); - $pee = preg_replace('|<p>|', "$1<p>", $pee); - $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag - $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists - $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee); - $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee); - $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee); - $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); - if ($br) { - $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee); - $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks - $pee = str_replace('<WPPreserveNewline />', "\n", $pee); - } - $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee); - $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee); - //if (strpos($pee, '<pre') !== false) { - // mind the space between the ? and >. Only there because of the comment. - // $pee = preg_replace_callback('!(<pre.*? >)(.*?)</pre>!is', 'clean_pre', $pee ); - //} - $pee = preg_replace("|\n</p>$|", '</p>', $pee); - - return $pee; +function autop($pee) { + return elgg_autop($pee); +} + +/** + * Create paragraphs from text with line spacing + * + * @param string $string The string + * + * @return string + **/ +function elgg_autop($string) { + return ElggAutoP::getInstance()->process($string); } /** @@ -312,6 +287,8 @@ function elgg_get_friendly_title($title) { // handle some special cases $title = str_replace('&', 'and', $title); + // quotes and angle brackets stored in the database as html encoded + $title = htmlspecialchars_decode($title); $title = ElggTranslit::urlize($title); @@ -384,7 +361,7 @@ function elgg_get_friendly_time($time) { /** * Strip tags and offer plugins the chance. * Plugins register for output:strip_tags plugin hook. - * Original string included in $params['original_string'] + * Original string included in $params['original_string'] * * @param string $string Formatted string * @@ -440,3 +417,32 @@ function _elgg_html_decode($string) { ); return $string; } + +/** + * Unit tests for Output + * + * @param sting $hook unit_test + * @param string $type system + * @param mixed $value Array of tests + * @param mixed $params Params + * + * @return array + * @access private + */ +function output_unit_test($hook, $type, $value, $params) { + global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/api/output.php'; + return $value; +} + +/** + * Initialise the Output subsystem. + * + * @return void + * @access private + */ +function output_init() { + elgg_register_plugin_hook_handler('unit_test', 'system', 'output_unit_test'); +} + +elgg_register_event_handler('init', 'system', 'output_init'); diff --git a/engine/lib/pageowner.php b/engine/lib/pageowner.php index 0cf0e0625..94765feee 100644 --- a/engine/lib/pageowner.php +++ b/engine/lib/pageowner.php @@ -37,6 +37,8 @@ function elgg_get_page_owner_guid($guid = 0) { /** * Gets the owner entity for the current page. * + * @note Access is disabled when getting the page owner entity. + * * @return ElggEntity|false The current page owner or false if none. * * @since 1.8.0 @@ -44,10 +46,14 @@ function elgg_get_page_owner_guid($guid = 0) { function elgg_get_page_owner_entity() { $guid = elgg_get_page_owner_guid(); if ($guid > 0) { - return get_entity($guid); + $ia = elgg_set_ignore_access(true); + $owner = get_entity($guid); + elgg_set_ignore_access($ia); + + return $owner; } - return FALSE; + return false; } /** @@ -75,6 +81,8 @@ function elgg_set_page_owner_guid($guid) { * <handler>/edit/<entity guid> * <handler>/group/<group guid> * + * @note Access is disabled while finding the page owner for the group gatekeeper functions. + * * * @param string $hook 'page_owner' * @param string $entity_type 'system' @@ -90,6 +98,8 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) return $returnvalue; } + $ia = elgg_set_ignore_access(true); + $username = get_input("username"); if ($username) { // @todo using a username of group:<guid> is deprecated @@ -97,6 +107,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) preg_match('/group\:([0-9]+)/i', $username, $matches); $guid = $matches[1]; if ($entity = get_entity($guid)) { + elgg_set_ignore_access($ia); return $entity->getGUID(); } } @@ -109,6 +120,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) $owner = get_input("owner_guid"); if ($owner) { if ($user = get_entity($owner)) { + elgg_set_ignore_access($ia); return $user->getGUID(); } } @@ -130,6 +142,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) case 'friends': $user = get_user_by_username($segments[2]); if ($user) { + elgg_set_ignore_access($ia); return $user->getGUID(); } break; @@ -137,6 +150,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) case 'edit': $entity = get_entity($segments[2]); if ($entity) { + elgg_set_ignore_access($ia); return $entity->getContainerGUID(); } break; @@ -144,6 +158,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) case 'group': $entity = get_entity($segments[2]); if ($entity) { + elgg_set_ignore_access($ia); return $entity->getGUID(); } break; @@ -151,7 +166,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) } } - return $returnvalue; + elgg_set_ignore_access($ia); } /** diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index ca4a957f4..94aff277e 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -208,6 +208,7 @@ function elgg_get_plugin_from_id($plugin_id) { 'type' => 'object', 'subtype' => 'plugin', 'joins' => array("JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"), + 'selects' => array("oe.title", "oe.description"), 'wheres' => array("oe.title = '$plugin_id'"), 'limit' => 1 ); diff --git a/engine/lib/private_settings.php b/engine/lib/private_settings.php index 1fa9bdb66..7541f7b3b 100644 --- a/engine/lib/private_settings.php +++ b/engine/lib/private_settings.php @@ -349,11 +349,6 @@ function set_private_setting($entity_guid, $name, $value) { $name = sanitise_string($name); $value = sanitise_string($value); - $entity = get_entity($entity_guid); - if (!$entity instanceof ElggEntity) { - return false; - } - $result = insert_data("INSERT into {$CONFIG->dbprefix}private_settings (entity_guid, name, value) VALUES ($entity_guid, '$name', '$value') diff --git a/engine/lib/sites.php b/engine/lib/sites.php index 8b772668d..d9eb2d25e 100644 --- a/engine/lib/sites.php +++ b/engine/lib/sites.php @@ -58,6 +58,7 @@ function get_site_entity_as_row($guid) { * @param string $url URL of the site * * @return bool + * @access private */ function create_site_entity($guid, $name, $description, $url) { global $CONFIG; diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php index f0874a483..f4f4b16f5 100644 --- a/engine/lib/upgrade.php +++ b/engine/lib/upgrade.php @@ -311,3 +311,58 @@ function elgg_upgrade_bootstrap_17_to_18() { return elgg_set_processed_upgrades($processed_upgrades); } + +/** + * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades. + * + * @see _elgg_upgrade_lock() + * + * @return bool + * @access private + */ +function _elgg_upgrade_lock() { + global $CONFIG; + + if (!_elgg_upgrade_is_locked()) { + // lock it + insert_data("create table {$CONFIG->dbprefix}upgrade_lock (id INT)"); + elgg_log('Locked for upgrade.', 'NOTICE'); + return true; + } + + elgg_log('Cannot lock for upgrade: already locked.', 'WARNING'); + return false; +} + +/** + * Unlocks upgrade. + * + * @see _elgg_upgrade_lock() + * + * @access private + */ +function _elgg_upgrade_unlock() { + global $CONFIG; + delete_data("drop table {$CONFIG->dbprefix}upgrade_lock"); + elgg_log('Upgrade unlocked.', 'NOTICE'); +} + +/** + * Checks if upgrade is locked + * + * @return bool + * @access private + */ +function _elgg_upgrade_is_locked() { + global $CONFIG, $DB_QUERY_CACHE; + + $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'")); + + // Invalidate query cache + if ($DB_QUERY_CACHE) { + $DB_QUERY_CACHE->clear(); + elgg_log("Query cache invalidated", 'NOTICE'); + } + + return $is_locked; +} diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php index a1ee92622..f4411ee20 100644 --- a/engine/lib/upgrades/2011010101.php +++ b/engine/lib/upgrades/2011010101.php @@ -93,4 +93,6 @@ $processed_upgrades[] = '2011010101.php'; $processed_upgrades = array_unique($processed_upgrades); elgg_set_processed_upgrades($processed_upgrades); +_elgg_upgrade_unlock(); + forward('upgrade.php'); diff --git a/engine/lib/users.php b/engine/lib/users.php index 527eff3cd..95ef9d176 100644 --- a/engine/lib/users.php +++ b/engine/lib/users.php @@ -44,6 +44,7 @@ function get_user_entity_as_row($guid) { * @param string $code A code * * @return bool + * @access private */ function create_user_entity($guid, $name, $username, $password, $salt, $email, $language, $code) { global $CONFIG; diff --git a/engine/lib/views.php b/engine/lib/views.php index e24ccb942..01291b889 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1236,6 +1236,15 @@ function elgg_view_river_item($item, array $vars = array()) { // subject is disabled or subject/object deleted return ''; } + // Don't hide objects in closed groups that a user can see. + // see http://trac.elgg.org/ticket/4789 +// else { +// // hide based on object's container +// $visibility = ElggGroupItemVisibility::factory($object->container_guid); +// if ($visibility->shouldHideItems) { +// return ''; +// } +// } $vars['item'] = $item; diff --git a/engine/lib/xml.php b/engine/lib/xml.php index 813bc4ee0..ff82d7e8a 100644 --- a/engine/lib/xml.php +++ b/engine/lib/xml.php @@ -101,47 +101,11 @@ function serialise_array_to_xml(array $data, $n = 0) { /** * Parse an XML file into an object. - * Based on code from http://de.php.net/manual/en/function.xml-parse-into-struct.php by - * efredricksen at gmail dot com * * @param string $xml The XML * * @return object */ function xml_to_object($xml) { - $parser = xml_parser_create(); - - // Parse $xml into a structure - xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); - xml_parse_into_struct($parser, $xml, $tags); - - xml_parser_free($parser); - - $elements = array(); - $stack = array(); - - foreach ($tags as $tag) { - $index = count($elements); - - if ($tag['type'] == "complete" || $tag['type'] == "open") { - $elements[$index] = new XmlElement; - $elements[$index]->name = $tag['tag']; - $elements[$index]->attributes = elgg_extract('attributes', $tag, ''); - $elements[$index]->content = elgg_extract('value', $tag, ''); - - if ($tag['type'] == "open") { - $elements[$index]->children = array(); - $stack[count($stack)] = &$elements; - $elements = &$elements[$index]->children; - } - } - - if ($tag['type'] == "close") { - $elements = &$stack[count($stack) - 1]; - unset($stack[count($stack) - 1]); - } - } - - return $elements[0]; + return new ElggXMLElement($xml); } diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php index bea995a6e..ebcd7d318 100644 --- a/engine/tests/api/access_collections.php +++ b/engine/tests/api/access_collections.php @@ -268,4 +268,26 @@ class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest { $group->delete(); } + + public function testAccessCaching() { + // create a new user to check against + $user = new ElggUser(); + $user->username = 'access_test_user'; + $user->save(); + + foreach (array('get_access_list', 'get_access_array') as $func) { + $cache = _elgg_get_access_cache(); + $cache->clear(); + + // admin users run tests, so disable access + elgg_set_ignore_access(true); + $access = $func($user->getGUID()); + + elgg_set_ignore_access(false); + $access2 = $func($user->getGUID()); + $this->assertNotEqual($access, $access2, "Access test for $func"); + } + + $user->delete(); + } } diff --git a/engine/tests/api/output.php b/engine/tests/api/output.php new file mode 100644 index 000000000..c3d5aa8c6 --- /dev/null +++ b/engine/tests/api/output.php @@ -0,0 +1,74 @@ +<?php +/** + * Test case for ElggAutoP functionality. + */ +class ElggCoreOutputAutoPTest extends ElggCoreUnitTest { + + /** + * @var ElggAutoP + */ + protected $_autop; + + public function setUp() { + $this->_autop = new ElggAutoP(); + } + + public function testDomRoundtrip() { + $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop'); + $in = file_get_contents($d->path . "/domdoc_in.html"); + $exp = file_get_contents($d->path . "/domdoc_exp.html"); + $exp = $this->flattenString($exp); + + $doc = new DOMDocument(); + libxml_use_internal_errors(true); + $doc->loadHTML("<html><meta http-equiv='content-type' content='text/html; charset=utf-8'><body>" + . $in . '</body></html>'); + $serialized = $doc->saveHTML(); + list(,$out) = explode('<body>', $serialized, 2); + list($out) = explode('</body>', $out, 2); + $out = $this->flattenString($out); + + $this->assertEqual($exp, $out, "DOMDocument's parsing/serialization roundtrip"); + } + + public function testProcess() { + $data = $this->provider(); + foreach ($data as $row) { + list($test, $in, $exp) = $row; + $exp = $this->flattenString($exp); + $out = $this->_autop->process($in); + $out = $this->flattenString($out); + + $this->assertEqual($exp, $out, "Equality case {$test}"); + } + } + + public function provider() { + $d = dir(dirname(dirname(__FILE__)) . '/test_files/output/autop'); + $tests = array(); + while (false !== ($entry = $d->read())) { + if (preg_match('/^([a-z\\-]+)\.in\.html$/i', $entry, $m)) { + $tests[] = $m[1]; + } + } + + $data = array(); + foreach ($tests as $test) { + $data[] = array( + $test, + file_get_contents($d->path . '/' . "{$test}.in.html"), + file_get_contents($d->path . '/' . "{$test}.exp.html"), + ); + } + return $data; + } + + /** + * Different versions of PHP return different whitespace between tags. + * Removing all line breaks normalizes that. + */ + public function flattenString($string) { + $r = preg_replace('/[\n\r]+/', '', $string); + return $r; + } +}
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/block-a.exp.norun.html b/engine/tests/test_files/output/autop/block-a.exp.norun.html new file mode 100644 index 000000000..addf29dec --- /dev/null +++ b/engine/tests/test_files/output/autop/block-a.exp.norun.html @@ -0,0 +1,6 @@ + +<p>HTML5 allows A to contain block-level content</p> +<a href="foo"><h3>A treated as block</h3> +<p>Read more</p> +</a> +<p><a href="foo">A treated as<br /> inline</a></p> diff --git a/engine/tests/test_files/output/autop/block-a.in.norun.html b/engine/tests/test_files/output/autop/block-a.in.norun.html new file mode 100644 index 000000000..fc2dac43a --- /dev/null +++ b/engine/tests/test_files/output/autop/block-a.in.norun.html @@ -0,0 +1,9 @@ +HTML5 allows A to contain block-level content +<a href="foo"> + + <h3>A treated as block</h3> + + Read more +</a> +<a href="foo">A treated as + inline</a> diff --git a/engine/tests/test_files/output/autop/domdoc_exp.html b/engine/tests/test_files/output/autop/domdoc_exp.html new file mode 100644 index 000000000..8480c1083 --- /dev/null +++ b/engine/tests/test_files/output/autop/domdoc_exp.html @@ -0,0 +1,46 @@ +› + +Vietnamese - Tiếng Việt + +<h1>h1</h1> +<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span></p> +<h2>h2</h2> +<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p> +<h3>h3</h3> +<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p> +<blockquote> + <p>Blockquoted paragraph</p> +</blockquote> +<p>Paragraph following blockquote</p> +<ul><li>Unordered</li> + <li>List</li> +</ul><p>Paragraph between lists</p> +<ol><li>Ordered</li> + <li>List</li> +</ol><p>Paragraph between lists</p> +<ul><li>OL list</li> + <li>nested<ol><li>inside a</li> + <li>UL list</li> + </ol></li> +</ul><p>Paragraph between lists</p> +<table border="0"><tbody><tr><td>Table with</td> + <td></td> + </tr><tr><td></td> + <td>border=0</td> + </tr></tbody></table><p>Paragraph</p> +<ol><li>UL list</li> + <li>nested + <ul><li>inside a</li> + <li>OL list</li> + </ul></li> +</ol><p>Paragraph between tables</p> +<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td> + <td></td> + </tr><tr><td></td> + <td>cellpadding = 5</td> + </tr></tbody></table><p>Paragraph between tables</p> +<table border="2"><tbody><tr><td>Table with</td> + <td></td> + </tr><tr><td></td> + <td>border=2</td> + </tr></tbody></table>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/domdoc_in.html b/engine/tests/test_files/output/autop/domdoc_in.html new file mode 100644 index 000000000..4c465b435 --- /dev/null +++ b/engine/tests/test_files/output/autop/domdoc_in.html @@ -0,0 +1,80 @@ +› + +Vietnamese - Tiếng Việt + +<h1>h1</h1> +<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span></p> +<h2>h2</h2> +<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p> +<h3>h3</h3> +<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p> +<blockquote> + <p>Blockquoted paragraph</p> +</blockquote> +<p>Paragraph following blockquote</p> +<ul> + <li>Unordered</li> + <li>List</li> +</ul> +<p>Paragraph between lists</p> +<ol> + <li>Ordered</li> + <li>List</li> +</ol> +<p>Paragraph between lists</p> +<ul> + <li>OL list</li> + <li>nested<ol> + <li>inside a</li> + <li>UL list</li> + </ol></li> +</ul> +<p>Paragraph between lists</p> +<table border="0"> + <tbody> + <tr> + <td>Table with</td> + <td></td> + </tr> + <tr> + <td></td> + <td>border=0</td> + </tr> + </tbody> +</table> +<p>Paragraph</p> +<ol> + <li>UL list</li> + <li>nested + <ul> + <li>inside a</li> + <li>OL list</li> + </ul> + </li> +</ol> +<p>Paragraph between tables</p> +<table border="1" cellpadding="5"> + <tbody> + <tr> + <td>Table with border=1</td> + <td></td> + </tr> + <tr> + <td></td> + <td>cellpadding = 5</td> + </tr> + </tbody> +</table> +<p>Paragraph between tables</p> +<table border="2"> + <tbody> + <tr> + <td>Table with</td> + <td></td> + </tr> + <tr> + <td></td> + <td>border=2</td> + </tr> + </tbody> +</table>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/typical-post.exp.html b/engine/tests/test_files/output/autop/typical-post.exp.html new file mode 100644 index 000000000..f9d75a114 --- /dev/null +++ b/engine/tests/test_files/output/autop/typical-post.exp.html @@ -0,0 +1,84 @@ +<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2> +<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p> + +<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p> +<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote> +<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p> + +<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p> + +<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p> + +<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p> +</blockquote> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p> +<pre><code><?php +class DataTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provider + */ + public function testAdd($a, $b, $c) + { + $this->assertEquals($c, $a + $b); + } + + public function provider() + { + return array( + array(0, 0, 0), + array(0, 1, 1), + array(1, 0, 1), + array(1, 1, 3) + ); + } +}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li> + <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li> + <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li> + <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li> +</ul> +<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p> + +<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p> +<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2> +<p><img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150">Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum.</p> + +<p>Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor.</p> +<h3>Donec at massa ante, sagittis fermentum urna.</h3><blockquote> +<p>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare.</p> + +<p>[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150">[/caption]</p> + +<p>Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis.</p> + +<p>Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</p> +</blockquote> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus.</p> +<pre><code><?php +class DataTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provider + */ + public function testAdd($a, $b, $c) + { + $this->assertEquals($c, $a + $b); + } + + public function provider() + { + return array( + array(0, 0, 0), + array(0, 1, 1), + array(1, 0, 1), + array(1, 1, 3) + ); + } +}</code></pre><ul><li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li> + <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li> + <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li> + <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li> +</ul> +<p>Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna.</p> + +<p><object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object></p> diff --git a/engine/tests/test_files/output/autop/typical-post.in.html b/engine/tests/test_files/output/autop/typical-post.in.html new file mode 100644 index 000000000..6e4984cc4 --- /dev/null +++ b/engine/tests/test_files/output/autop/typical-post.in.html @@ -0,0 +1,89 @@ +<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2> +<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum. + +Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. +<h3>Donec at massa ante, sagittis fermentum urna.</h3> +<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare. + +[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption] + +Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis. + +Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote> +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus. + +<pre><code><?php +class DataTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provider + */ + public function testAdd($a, $b, $c) + { + $this->assertEquals($c, $a + $b); + } + + public function provider() + { + return array( + array(0, 0, 0), + array(0, 1, 1), + array(1, 0, 1), + array(1, 1, 3) + ); + } +}</code></pre> +<ul> + <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li> + <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li> + <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li> + <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li> +</ul> +Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna. + +<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object> + +<h2>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</h2> +<img class="alignright size-thumbnail wp-image-905" title="Surest Things mixing session in Adobe Audition" src="http://www.mrclay.org/wp-content/uploads/2010/09/surestThings_audition-150x150.png" alt="screenshot of Audition mixing session" width="150" height="150" />Vivamus enim ante, <em>mattis eget imperdiet nec, pharetra vel velit.</em> Sed at euismod nibh. Praesent lacus tellus, <a href="http://google.com/">posuere et convallis</a> a, <strong>mollis et tellus. Suspendisse potenti</strong>. Phasellus tincidunt dignissim est eget mattis. Vestibulum lacinia <del>condimentum tellus, non vestibulum erat dapibus</del> quis. Aliquam arcu nibh, viverra adipiscing eleifend quis, pretium vitae ipsum. + +Curabitur turpis ante, <span style="color: #993300;">congue ac dapibus quis, vehicula ac orci.</span> Nunc luctus neque non massa porta sed pharetra ante accumsan. <a href="http://google.com/">Nam suscipit</a> risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. +<h3>Donec at massa ante, sagittis fermentum urna.</h3> +<blockquote>Mauris volutpat est id massa volutpat lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In in nisl mauris. In aliquet pretium nisl, vel convallis neque cursus vitae. Curabitur id mauris in urna gravida ornare. + +[caption id="attachment_719" align="alignleft" width="150" caption="Ibanez AGB140 Bass"]<img class="size-thumbnail wp-image-719" title="Ibanez AGB140 Bass" src="http://www.mrclay.org/wp-content/uploads/2010/04/agb140-e1271773766573-150x150.jpg" alt="Ibanez AGB140 Bass" width="150" height="150" />[/caption] + +Aenean <a href="http://google.com/">aliquet cursus purus sed gravida. Cras auctor euismod justo, ac dictum purus facilisis dignissim.</a> Quisque facilisis porta sem, ac suscipit quam molestie nec. Pellentesque quis hendrerit enim. Vivamus tempor erat diam. Sed eu felis nunc. Cras posuere lorem commodo turpis mollis sagittis. Mauris lobortis nunc felis. + +Maecenas elit lorem, varius sed condimentum ac, cursus et magna. Nam ut massa id augue consectetur porttitor eleifend in nunc. Curabitur cursus varius dictum. Vestibulum vel justo et neque tempus placerat a vel sapien.</blockquote> +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus enim ante, mattis eget imperdiet nec, <a href="http://google.com/">pharetra </a>vel velit. Sed at euismod nibh. Praesent lacus tellus, posuere et convallis a, mollis et tellus. + +<pre><code><?php +class DataTest extends PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provider + */ + public function testAdd($a, $b, $c) + { + $this->assertEquals($c, $a + $b); + } + + public function provider() + { + return array( + array(0, 0, 0), + array(0, 1, 1), + array(1, 0, 1), + array(1, 1, 3) + ); + } +}</code></pre> +<ul> + <li>Suspendisse potenti. Phasellus tincidunt dignissim est eget mattis.</li> + <li>Vestibulum lacinia condimentum tellus, non vestibulum erat dapibus quis.</li> + <li>Aliquam arcu nibh, <a href="http://google.com/">viverra</a> adipiscing eleifend quis, pretium vitae ipsum.</li> + <li>Curabitur turpis ante, congue ac <a href="http://google.com/">dapibus quis</a>, vehicula ac orci.</li> +</ul> +Nunc luctus neque non massa porta sed pharetra ante accumsan. Nam suscipit risus quis libero convallis viverra. Ut at arcu enim, vel pharetra dolor. Donec at massa ante, sagittis fermentum urna. + +<object width="480" height="390"><param name="movie" value="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="480" height="390" src="http://www.youtube.com/v/zW9YOMaVTFI?fs=1&hl=en_US" allowfullscreen="true" allowscriptaccess="always"></embed></object>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/wp-welcome.exp.html b/engine/tests/test_files/output/autop/wp-welcome.exp.html new file mode 100644 index 000000000..2f612e3dd --- /dev/null +++ b/engine/tests/test_files/output/autop/wp-welcome.exp.html @@ -0,0 +1,22 @@ + +<p>Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference.</p> + +<p>First things first:</p> +<ul><li><a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li> +</ul> +<p>As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers.<br />When a new version is released, <a href="%2%24s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions.<br />Upgrading is a couple of clicks!</p> + +<p>Then you can start enjoying the WordPress experience:</p> +<ul><li>Edit your personal information at <a href="%3%24s" title="Edit settings like your password, your display name and your contact information">Users › Your Profile</a></li> + <li>Start publishing at <a href="%4%24s" title="Create a new post">Posts › Add New</a> and at <a href="%5%24s" title="Create a new page">Pages › Add New</a></li> + <li>Browse and install plugins at <a href="%6%24s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins › Add New</a></li> + <li>Browse and install themes at <a href="%7%24s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance › Add New Themes</a></li> + <li>Modify and prettify your website’s links at <a href="%8%24s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings › Permalinks</a></li> + <li>Import content from another system or WordPress site at <a href="%9%24s" title="WordPress comes with importers for the most common publishing systems">Tools › Import</a></li> + <li>Find answers to your questions at the <a href="%10%24s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li> +</ul> +<p>To keep this post for reference, <a href="%11%24s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private.</p> + +<p>Thank you for selecting WordPress. We wish you happy publishing!</p> + +<p>PS. Not yet subscribed for update notifications? <a href="%1%24s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a></p> diff --git a/engine/tests/test_files/output/autop/wp-welcome.in.html b/engine/tests/test_files/output/autop/wp-welcome.in.html new file mode 100644 index 000000000..338ede73f --- /dev/null +++ b/engine/tests/test_files/output/autop/wp-welcome.in.html @@ -0,0 +1,25 @@ +Welcome to WordPress! This post contains important information. After you read it, you can make it private to hide it from visitors but still have the information handy for future reference. + +First things first: +<ul> + <li><a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Subscribe to the WordPress mailing list for release notifications</a></li> +</ul> +As a subscriber, you will receive an email every time an update is available (and only then). This will make it easier to keep your site up to date, and secure from evildoers. +When a new version is released, <a href="%2$s" title="If you are already logged in, this will take you directly to the Dashboard">log in to the Dashboard</a> and follow the instructions. +Upgrading is a couple of clicks! + +Then you can start enjoying the WordPress experience: +<ul> + <li>Edit your personal information at <a href="%3$s" title="Edit settings like your password, your display name and your contact information">Users › Your Profile</a></li> + <li>Start publishing at <a href="%4$s" title="Create a new post">Posts › Add New</a> and at <a href="%5$s" title="Create a new page">Pages › Add New</a></li> + <li>Browse and install plugins at <a href="%6$s" title="Browse and install plugins at the official WordPress repository directly from your Dashboard">Plugins › Add New</a></li> + <li>Browse and install themes at <a href="%7$s" title="Browse and install themes at the official WordPress repository directly from your Dashboard">Appearance › Add New Themes</a></li> + <li>Modify and prettify your website’s links at <a href="%8$s" title="For example, select a link structure like: http://example.com/1999/12/post-name">Settings › Permalinks</a></li> + <li>Import content from another system or WordPress site at <a href="%9$s" title="WordPress comes with importers for the most common publishing systems">Tools › Import</a></li> + <li>Find answers to your questions at the <a href="%10$s" title="The official WordPress documentation, maintained by the WordPress community">WordPress Codex</a></li> +</ul> +To keep this post for reference, <a href="%11$s" title="Click to edit the content and settings of this post">click to edit it</a>, go to the Publish box and change its Visibility from Public to Private. + +Thank you for selecting WordPress. We wish you happy publishing! + +PS. Not yet subscribed for update notifications? <a href="%1$s" title="Subscribe to the WordPress mailing list for Release Notifications">Do it now!</a> diff --git a/engine/tests/test_files/output/autop/wpautop-fails.exp.html b/engine/tests/test_files/output/autop/wpautop-fails.exp.html new file mode 100644 index 000000000..d018db4ff --- /dev/null +++ b/engine/tests/test_files/output/autop/wpautop-fails.exp.html @@ -0,0 +1,31 @@ + +<p>paragraph</p> + +<p>paragraph</p> +<div class="whatever"><blockquote> +<p>paragraph</p> +</blockquote> +<p>line</p> +</div> +<p>paragraph</p> +<ul><li>line</li> +<li>paragraph + +paragraph</li> +</ul> +<p>paragraph<br />line<br />line</p> +<pre>Honor +this whitespace +</pre> +<p>paragraph</p> +<style><!-- +Do not alter! +--></style> +<p>paragraph <!-- do not alter --></p> +<dl><dt>term</dt> <dd>paragraph + +<a href="xx"> <img src="yy"></a> + +paragraph</dd> </dl><div><a href="xx"> <img src="yy"></a></div> +<p>Hello <a href="link"><br /><br />World</a></p> +<p id="abc">Paragraph</p><div>Line</div>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/wpautop-fails.in.html b/engine/tests/test_files/output/autop/wpautop-fails.in.html new file mode 100644 index 000000000..9aa24be59 --- /dev/null +++ b/engine/tests/test_files/output/autop/wpautop-fails.in.html @@ -0,0 +1,41 @@ + +paragraph + +paragraph <div class="whatever"><blockquote> + paragraph + </blockquote> + line +</div> + +paragraph +<ul> +<li>line</li> +<li>paragraph + +paragraph</li> +</ul> +paragraph +line<br> + line +<pre>Honor +this whitespace +</pre> +paragraph +<style><!-- +Do not alter! +--></style> +paragraph <!-- do not alter --> +<dl> <dt>term</dt> <dd>paragraph + +<a href="xx"> <img src="yy" /> </a> + +paragraph</dd> </dl> +<div><a href="xx"> <img src="yy" /> </a></div> + +Hello <a href="link"> + +World</a> + +<p id="abc">Paragraph</p> + +<div>Line</div>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.exp.html b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html new file mode 100644 index 000000000..1f23d6154 --- /dev/null +++ b/engine/tests/test_files/output/autop/wysiwyg-test.exp.html @@ -0,0 +1,51 @@ + +<p>&nbps;<br />≴</p> +<h1>h1</h1> +<p>Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span></p> +<h2>h2</h2> +<p>Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span></p> +<h3>h3</h3> +<p>Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span></p> +<blockquote> +<p>Blockquoted paragraph</p> +</blockquote> +<p>Paragraph following blockquote</p> +<ul><li>Unordered</li> + <li>List</li> +</ul> +<p>Paragraph between lists</p> +<ol><li>Ordered</li> + <li>List</li> +</ol> +<p>Paragraph between lists</p> +<ul><li>OL list</li> + <li>nested + <ol><li>inside a</li> + <li>UL list</li> + </ol></li> +</ul> +<p>Paragraph between lists</p> +<table border="0"><tbody><tr></tr><tr><td>Table with</td> + <td></td> + </tr><tr><td></td> + <td>border=0</td> + </tr></tbody></table> +<p>Paragraph</p> +<ol><li>UL list</li> + <li>nested + <ul><li>inside a</li> + <li>OL list</li> + </ul></li> +</ol> +<p>Paragraph between tables</p> +<table border="1" cellpadding="5"><tbody><tr><td>Table with border=1</td> + <td></td> + </tr><tr><td></td> + <td>cellpadding = 5</td> + </tr></tbody></table> +<p>Paragraph between tables</p> +<table border="2"><tbody><tr><td>Table with</td> + <td></td> + </tr><tr><td></td> + <td>border=2</td> + </tr></tbody></table>
\ No newline at end of file diff --git a/engine/tests/test_files/output/autop/wysiwyg-test.in.html b/engine/tests/test_files/output/autop/wysiwyg-test.in.html new file mode 100644 index 000000000..733b0e2ec --- /dev/null +++ b/engine/tests/test_files/output/autop/wysiwyg-test.in.html @@ -0,0 +1,79 @@ +&nbps; +≴ +<h1>h1</h1> +Paragraph <a href="http://google.com/">link</a> <strong>Bold</strong> <em>italic</em> <em><strong>bolditalic</strong></em> <span style="background-color: #ffff00; "></span> +<h2>h2</h2> +Paragraph <span style="font-size: xx-small;">size1</span> <span style="font-size: x-small;">size2</span> <span style="font-size: medium;">size4</span> +<h3>h3</h3> +Paragraph <span style="text-decoration: underline;">underline</span> <span style="text-decoration: line-through;">strikethrough</span> <span style="color: #ff0000;">color</span> <span style="background-color: #ffff00; ">background</span> +<blockquote>Blockquoted paragraph</blockquote> +Paragraph following blockquote +<ul> + <li>Unordered</li> + <li>List</li> +</ul> +Paragraph between lists +<ol> + <li>Ordered</li> + <li>List</li> +</ol> +Paragraph between lists +<ul> + <li>OL list</li> + <li>nested + <ol> + <li>inside a</li> + <li>UL list</li> + </ol></li> +</ul> +Paragraph between lists +<table border="0"> + <tbody> + <tr> + </tr> + <tr> + <td>Table with</td> + <td></td> + </tr> + <tr> + <td></td> + <td>border=0</td> + </tr> + </tbody> +</table> +Paragraph +<ol> + <li>UL list</li> + <li>nested + <ul> + <li>inside a</li> + <li>OL list</li> + </ul> + </li> +</ol> +Paragraph between tables +<table border="1" cellpadding="5"> + <tbody> + <tr> + <td>Table with border=1</td> + <td></td> + </tr> + <tr> + <td></td> + <td>cellpadding = 5</td> + </tr> + </tbody> +</table> +Paragraph between tables +<table border="2"> + <tbody> + <tr> + <td>Table with</td> + <td></td> + </tr> + <tr> + <td></td> + <td>border=2</td> + </tr> + </tbody> +</table>
\ No newline at end of file diff --git a/htaccess_dist b/htaccess_dist index bf163c69e..4c888e70a 100644 --- a/htaccess_dist +++ b/htaccess_dist @@ -101,35 +101,35 @@ RewriteEngine on #RewriteBase / # In for backwards compatibility -RewriteRule ^pg\/([A-Za-z0-9\_\-]+)$ engine/handlers/page_handler.php?handler=$1&%{QUERY_STRING} -RewriteRule ^pg\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2&%{QUERY_STRING} -RewriteRule ^tag\/(.+)\/?$ engine/handlers/page_handler.php?handler=search&page=$1 +RewriteRule ^pg\/([A-Za-z0-9\_\-]+)$ engine/handlers/page_handler.php?handler=$1&%{QUERY_STRING} [L] +RewriteRule ^pg\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2&%{QUERY_STRING} [L] +RewriteRule ^tag\/(.+)\/?$ engine/handlers/page_handler.php?handler=search&page=$1 [L] -RewriteRule ^action\/([A-Za-z0-9\_\-\/]+)$ engine/handlers/action_handler.php?action=$1&%{QUERY_STRING} +RewriteRule ^action\/([A-Za-z0-9\_\-\/]+)$ engine/handlers/action_handler.php?action=$1&%{QUERY_STRING} [L] -RewriteRule ^cache\/(.*)$ engine/handlers/cache_handler.php?request=$1&%{QUERY_STRING} +RewriteRule ^cache\/(.*)$ engine/handlers/cache_handler.php?request=$1&%{QUERY_STRING} [L] -RewriteRule ^services\/api\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/service_handler.php?handler=$1&request=$2&%{QUERY_STRING} +RewriteRule ^services\/api\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/service_handler.php?handler=$1&request=$2&%{QUERY_STRING} [L] -RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/?$ engine/handlers/export_handler.php?view=$1&guid=$2 -RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/([A-Za-z]+)\/([A-Za-z0-9\_]+)\/$ engine/handlers/export_handler.php?view=$1&guid=$2&type=$3&idname=$4 +RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/?$ engine/handlers/export_handler.php?view=$1&guid=$2 [L] +RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/([A-Za-z]+)\/([A-Za-z0-9\_]+)\/$ engine/handlers/export_handler.php?view=$1&guid=$2&type=$3&idname=$4 [L] -RewriteRule xml-rpc.php engine/handlers/xml-rpc_handler.php -RewriteRule mt/mt-xmlrpc.cgi engine/handlers/xml-rpc_handler.php +RewriteRule xml-rpc.php engine/handlers/xml-rpc_handler.php [L] +RewriteRule mt/mt-xmlrpc.cgi engine/handlers/xml-rpc_handler.php [L] # rule for rewrite module test during install - can be removed after installation -RewriteRule ^rewrite.php$ install.php +RewriteRule ^rewrite.php$ install.php [L] # Everything else that isn't a file gets routed through the page handler RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^([A-Za-z0-9\_\-]+)$ engine/handlers/page_handler.php?handler=$1 [QSA] +RewriteRule ^([A-Za-z0-9\_\-]+)$ engine/handlers/page_handler.php?handler=$1 [QSA,L] RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2 [QSA] +RewriteRule ^([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/page_handler.php?handler=$1&page=$2 [QSA,L] </IfModule> diff --git a/install/ElggInstaller.php b/install/ElggInstaller.php index 934b38d28..775bbf5b6 100644 --- a/install/ElggInstaller.php +++ b/install/ElggInstaller.php @@ -1519,22 +1519,27 @@ class ElggInstaller { protected function createAdminAccount($submissionVars, $login = FALSE) { global $CONFIG; - $guid = register_user( - $submissionVars['username'], - $submissionVars['password1'], - $submissionVars['displayname'], - $submissionVars['email'] - ); + try { + $guid = register_user( + $submissionVars['username'], + $submissionVars['password1'], + $submissionVars['displayname'], + $submissionVars['email'] + ); + } catch (Exception $e) { + register_error($e->getMessage()); + return false; + } if (!$guid) { register_error(elgg_echo('install:admin:cannot_create')); - return FALSE; + return false; } $user = get_entity($guid); if (!$user) { register_error(elgg_echo('install:error:loadadmin')); - return FALSE; + return false; } elgg_set_ignore_access(TRUE); @@ -1543,7 +1548,7 @@ class ElggInstaller { } else { datalist_set('admin_registered', 1); } - elgg_set_ignore_access(FALSE); + elgg_set_ignore_access(false); // add validation data to satisfy user validation plugins create_metadata($guid, 'validated', TRUE, '', 0, ACCESS_PUBLIC); diff --git a/install/ElggRewriteTester.php b/install/ElggRewriteTester.php index c01510f60..ab68da2b7 100644 --- a/install/ElggRewriteTester.php +++ b/install/ElggRewriteTester.php @@ -154,6 +154,8 @@ class ElggRewriteTester { if ($this->serverSupportsRemoteRead == FALSE) { $msg = elgg_echo('install:warning:rewrite:unknown', array($url)); + $msg .= elgg_view('install/js_rewrite_check', array('url' => $url)); + return array( 'severity' => 'warning', 'message' => $msg, @@ -165,6 +167,8 @@ class ElggRewriteTester { $msg = "$serverString\n\n"; if (!isset($this->htaccessIssue)) { $msg .= elgg_echo('install:error:rewrite:allowoverride'); + $msg .= elgg_view('install/js_rewrite_check', array('url' => $url)); + return array( 'severity' => 'failure', 'message' => $msg, diff --git a/install/js/install.js b/install/js/install.js index 49b2be10c..37e5b0dc3 100644 --- a/install/js/install.js +++ b/install/js/install.js @@ -19,3 +19,24 @@ $(function() { } }); }); + +elgg = { + installer: {} +}; + +/** + * Check the rewrite address for "success" and then allows the installation to proceed. + */ +elgg.installer.rewriteTest = function(url, success_msg, nextURL) { + $.ajax(url, { + success: function(data, status, xhr) { + if (data == 'success') { + $('.elgg-require-rewrite li').attr('class', 'pass'); + $('.elgg-require-rewrite li').html('<p>' + success_msg + '</p>'); + $('.elgg-install-nav a.elgg-state-disabled') + .removeClass('elgg-state-disabled') + .attr('href', nextURL); + } + } + }); +} diff --git a/install/languages/en.php b/install/languages/en.php index 3a692e020..b2583fbc9 100644 --- a/install/languages/en.php +++ b/install/languages/en.php @@ -154,7 +154,7 @@ If you are ready to proceed, click the Next button.", 'install:error:rewrite:htaccess:cannot_copy' => 'A unknown error occurred while creating the .htaccess file. You need to manually copy htaccess_dist to .htaccess in Elgg\'s directory.', 'install:error:rewrite:altserver' => 'The rewrite rules test failed. You need to configure your web server with Elgg\'s rewrite rules and try again.', 'install:error:rewrite:unknown' => 'Oof. We couldn\'t figure out what kind of web server is running on your server and it failed the rewrite rules. We cannot offer any specific advice. Please check the troubleshooting link.', - 'install:warning:rewrite:unknown' => 'Your server does not support automatic testing of the rewrite rules. You can continue the installation, but you may experience problems with your site. You can manually test the rewrite rules by clicking this link: <a href="%s" target="_blank">test</a>. You will see the word success if the rules are working.', + 'install:warning:rewrite:unknown' => 'Your server does not support automatic testing of the rewrite rules and your browser does not support checking via JavaScript. You can continue the installation, but you may experience problems with your site. You can manually test the rewrite rules by clicking this link: <a href="%s" target="_blank">test</a>. You will see the word success if the rules are working.', ); add_translation("en", $english); diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js index dc7c07165..af2c94000 100644 --- a/js/lib/elgglib.js +++ b/js/lib/elgglib.js @@ -347,8 +347,12 @@ elgg.system_messages = function(msgs, delay, type) { msgs.forEach(appendMessage); - $(messages_html.join('')).appendTo(systemMessages) - .animate({opacity: '1.0'}, delay).fadeOut('slow'); + if (type != 'error') { + $(messages_html.join('')).appendTo(systemMessages) + .animate({opacity: '1.0'}, delay).fadeOut('slow'); + } else { + $(messages_html.join('')).appendTo(systemMessages); + } }; /** diff --git a/js/lib/languages.js b/js/lib/languages.js index a8ba72c31..99a1ba0ee 100644 --- a/js/lib/languages.js +++ b/js/lib/languages.js @@ -4,6 +4,9 @@ */ elgg.provide('elgg.config.translations'); +// default language - required by unit tests +elgg.config.language = 'en'; + /** * Analagous to the php version. Merges translations for a * given language into the current translations map. diff --git a/js/lib/ui.js b/js/lib/ui.js index 2a4d269d6..413078b4f 100644 --- a/js/lib/ui.js +++ b/js/lib/ui.js @@ -10,7 +10,7 @@ elgg.ui.init = function () { }); $('.elgg-system-messages li').animate({opacity: 0.9}, 6000); - $('.elgg-system-messages li').fadeOut('slow'); + $('.elgg-system-messages li.elgg-state-success').fadeOut('slow'); $('[rel=toggle]').live('click', elgg.ui.toggles); diff --git a/languages/en.php b/languages/en.php index 2b5ba00fd..353896047 100644 --- a/languages/en.php +++ b/languages/en.php @@ -405,7 +405,8 @@ $english = array( 'profile:editdefault:delete:fail' => 'Removed default profile item field failed', 'profile:editdefault:delete:success' => 'Profile field deleted', 'profile:defaultprofile:reset' => 'Profile fields reset to the system default', - 'profile:resetdefault' => 'Reset default profile', + 'profile:resetdefault' => 'Reset profile fields to system defaults', + 'profile:resetdefault:confirm' => 'Are you sure you want to delete your custom profile fields?', 'profile:explainchangefields' => "You can replace the existing profile fields with your own using the form below. \n\n Give the new profile field a label, for example, 'Favorite team', then select the field type (eg. text, url, tags), and click the 'Add' button. To re-order the fields drag on the handle next to the field label. To edit a field label - click on the label's text to make it editable. \n\n At any time you can revert back to the default profile set up, but you will lose any information already entered into custom fields on profile pages.", 'profile:editdefault:success' => 'New profile field added', 'profile:editdefault:fail' => 'Default profile could not be saved', @@ -663,6 +664,7 @@ $english = array( 'admin:notices:could_not_delete' => 'Could not delete notice.', + 'item:object:admin_notice' => 'Admin notice', 'admin:options' => 'Admin options', @@ -688,7 +690,7 @@ $english = array( 'admin:plugins:label:author' => "Author", 'admin:plugins:label:copyright' => "Copyright", 'admin:plugins:label:categories' => 'Categories', - 'admin:plugins:label:licence' => "Licence", + 'admin:plugins:label:licence' => "License", 'admin:plugins:label:website' => "URL", 'admin:plugins:label:repository' => "Code", 'admin:plugins:label:bugtracker' => "Report issue", @@ -1055,6 +1057,10 @@ Once you have logged in, we highly recommend that you change your password. 'upgrading' => 'Upgrading...', 'upgrade:db' => 'Your database was upgraded.', 'upgrade:core' => 'Your Elgg installation was upgraded.', + 'upgrade:unlock' => 'Unlock upgrade', + 'upgrade:unlock:confirm' => "The database is locked for another upgrade. Running concurrent upgrades is dangerous. You should only continue if you know there is not another upgrade running. Unlock?", + 'upgrade:locked' => "Cannot upgrade. Another upgrade is running. To clear the upgrade lock, visit the Admin section.", + 'upgrade:unlock:success' => "Upgrade unlocked suscessfully.", 'upgrade:unable_to_upgrade' => 'Unable to upgrade.', 'upgrade:unable_to_upgrade_info' => 'This installation cannot be upgraded because legacy views @@ -1135,7 +1141,7 @@ If you requested this, click on the link below. Otherwise ignore this email. 'comments:count' => "%s comments", - 'riveraction:annotation:generic_comment' => '%s commented on %s', + 'river:comment:object:default' => '%s commented on %s', 'generic_comments:add' => "Leave a comment", 'generic_comments:post' => "Post comment", @@ -1149,6 +1155,7 @@ If you requested this, click on the link below. Otherwise ignore this email. 'generic_comment:failure' => "An unexpected error occurred when adding your comment.", 'generic_comment:none' => 'No comments', 'generic_comment:title' => 'Comment by %s', + 'generic_comment:on' => '%s on %s', 'generic_comment:email:subject' => 'You have a new comment!', 'generic_comment:email:body' => "You have a new comment on your item \"%s\" from %s. It reads: diff --git a/mod/blog/start.php b/mod/blog/start.php index 8cbaf5cca..eb6eee05f 100644 --- a/mod/blog/start.php +++ b/mod/blog/start.php @@ -124,9 +124,12 @@ function blog_page_handler($page) { $params = blog_get_page_content_archive($user->guid, $page[2], $page[3]); break; case 'view': - case 'read': // Elgg 1.7 compatibility $params = blog_get_page_content_read($page[1]); break; + case 'read': // Elgg 1.7 compatibility + register_error(elgg_echo("changebookmark")); + forward("blog/view/{$page[1]}"); + break; case 'add': gatekeeper(); $params = blog_get_page_content_edit($page_type, $page[1]); diff --git a/mod/bookmarks/start.php b/mod/bookmarks/start.php index 66e22b565..3846f5165 100644 --- a/mod/bookmarks/start.php +++ b/mod/bookmarks/start.php @@ -125,11 +125,14 @@ function bookmarks_page_handler($page) { include "$pages/friends.php"; break; - case "read": case "view": set_input('guid', $page[1]); include "$pages/view.php"; break; + case 'read': // Elgg 1.7 compatibility + register_error(elgg_echo("changebookmark")); + forward("bookmarks/view/{$page[1]}"); + break; case "add": gatekeeper(); diff --git a/mod/developers/languages/en.php b/mod/developers/languages/en.php index 262759e23..856efe008 100644 --- a/mod/developers/languages/en.php +++ b/mod/developers/languages/en.php @@ -54,6 +54,7 @@ $english = array( 'theme_preview:modules' => 'Modules', 'theme_preview:navigation' => 'Navigation', 'theme_preview:typography' => 'Typography', + 'theme_preview:miscellaneous' => 'Miscellaneous', // unit tests 'developers:unit_tests:description' => 'Elgg has unit and integration tests for detecting bugs in its core classes and functions.', diff --git a/mod/developers/start.php b/mod/developers/start.php index d77a96b36..413a8ed9b 100644 --- a/mod/developers/start.php +++ b/mod/developers/start.php @@ -176,6 +176,7 @@ function developers_theme_preview_controller($page) { 'modules', 'navigation', 'typography', + 'miscellaneous' ); foreach ($pages as $page_name) { diff --git a/mod/developers/views/default/developers/css.php b/mod/developers/views/default/developers/css.php index 4690945a9..b4f59fdec 100644 --- a/mod/developers/views/default/developers/css.php +++ b/mod/developers/views/default/developers/css.php @@ -21,3 +21,7 @@ color: #666; padding: 20px; } + +.developers-content-thin { + max-width: 600px; +}
\ No newline at end of file diff --git a/mod/developers/views/default/forms/developers/settings.php b/mod/developers/views/default/forms/developers/settings.php index 584f6af30..78e1372de 100644 --- a/mod/developers/views/default/forms/developers/settings.php +++ b/mod/developers/views/default/forms/developers/settings.php @@ -10,20 +10,22 @@ echo '<p>' . elgg_echo('elgg_dev_tools:settings:explanation') . '</p>'; foreach ($vars['data'] as $name => $info) { echo '<div>'; if ($info['type'] == 'checkbox') { + echo '<label>'; echo elgg_view("input/checkbox", array( 'name' => $name, 'value' => $info['value'], 'checked' => $info['checked'], )); - echo '<label>' . elgg_echo("developers:label:$name") . '</label>'; + echo elgg_echo("developers:label:$name") . '</label>'; echo '<span class="elgg-text-help">' . elgg_echo("developers:help:$name") . '</span>'; } else { - echo '<label>' . elgg_echo("developers:label:$name") . '</label>'; + echo '<label>' . elgg_echo("developers:label:$name"); echo elgg_view("input/{$info['type']}", array( 'name' => $name, 'value' => $info['value'], 'options_values' => $info['options_values'], )); + echo '</label>'; echo '<span class="elgg-text-help">' . elgg_echo("developers:help:$name") . '</span>'; } echo '</div>'; diff --git a/mod/developers/views/default/page/theme_preview.php b/mod/developers/views/default/page/theme_preview.php index 584387ec1..ee2bc0c0f 100644 --- a/mod/developers/views/default/page/theme_preview.php +++ b/mod/developers/views/default/page/theme_preview.php @@ -18,9 +18,19 @@ header("Content-type: text/html; charset=UTF-8"); </head> <body> <div class="elgg-page elgg-page-default"> + <div class="elgg-page-messages"> + <ul class="elgg-system-messages"> + <li class="hidden"></li> + </ul> + </div> <div class="elgg-page-header"> <div class="elgg-inner"> <h1 class="elgg-heading-site">Theme Sandbox</h1> + <?php + if (get_input("site_menu", false)) { + echo elgg_view_menu('site'); + } + ?> </div> </div> <div class="elgg-page-body"> diff --git a/mod/developers/views/default/theme_preview/components.php b/mod/developers/views/default/theme_preview/components.php index 2f414cd88..50c155b14 100644 --- a/mod/developers/views/default/theme_preview/components.php +++ b/mod/developers/views/default/theme_preview/components.php @@ -22,4 +22,4 @@ $body = elgg_view('theme_preview/components/tags'); echo elgg_view_module('info', 'Tags (.elgg-tag)', $body); $body = elgg_view('theme_preview/components/messages'); -echo elgg_view_module('info', 'Messages (.elgg-message)', $body); +echo elgg_view_module('info', 'Messages (.elgg-message)', $body);
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/general.php b/mod/developers/views/default/theme_preview/general.php index 629462873..7d98d4443 100644 --- a/mod/developers/views/default/theme_preview/general.php +++ b/mod/developers/views/default/theme_preview/general.php @@ -11,6 +11,29 @@ The preview is divided into sections that are listed in the page menu (usually in the sidebar but depends on your current theme). </p> +<?php +$simple_cache = elgg_get_config('simplecache_enabled'); +$system_cache = elgg_get_config('system_cache_enabled'); + +if ($simple_cache || $system_cache) { + $advanced = elgg_view('output/url', array( + 'text' => 'Advanced Settings', + 'href' => 'admin/settings/advanced', + 'is_trusted' => true + )); + $developers = elgg_view('output/url', array( + 'text' => 'Developers\' Plugin Settings', + 'href' => 'admin/developers/settings', + 'is_trusted' => true + )); + + $body = "Caches are enabled. Changes you make to CSS and views might not appear. It is + always recommended to disable caches while developing themes and plugins. To + disable caches, visit the $advanced or $developers pages."; + + echo elgg_view_module('info', 'Warning', $body); +} +?> <p> <?php echo elgg_view('output/url', array( diff --git a/mod/developers/views/default/theme_preview/miscellaneous.php b/mod/developers/views/default/theme_preview/miscellaneous.php new file mode 100644 index 000000000..2f4ee4acd --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous.php @@ -0,0 +1,22 @@ +<?php +/** + * Miscellaneous and complex components + */ + +$body = elgg_view('theme_preview/miscellaneous/lightbox'); +echo elgg_view_module('info', 'Lightbox (.elgg-lightbox)', $body); + +$body = elgg_view('theme_preview/miscellaneous/popup'); +echo elgg_view_module('info', 'Popup (rel=popup)', $body); + +$body = elgg_view('theme_preview/miscellaneous/toggle'); +echo elgg_view_module('info', 'Toggle (rel=toggle)', $body); + +$body = elgg_view('theme_preview/miscellaneous/system_messages'); +echo elgg_view_module('info', 'System Messages and Errors', $body); + +$body = elgg_view('theme_preview/miscellaneous/site_menu'); +echo elgg_view_module('info', 'Site Menu', $body); + +$body = elgg_view('theme_preview/miscellaneous/user_hover_menu'); +echo elgg_view_module('info', 'User Icon with Hover Menu', $body);
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/lightbox.php b/mod/developers/views/default/theme_preview/miscellaneous/lightbox.php new file mode 100644 index 000000000..b673c4ee0 --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/lightbox.php @@ -0,0 +1,19 @@ +<?php + +elgg_load_js('lightbox'); +elgg_load_css('lightbox'); + +$ipsum = elgg_view('developers/ipsum'); + +$link = elgg_view('output/url', array( + 'text' => 'Open lighbox', + 'href' => "#elgg-lightbox-test", + 'class' => 'elgg-lightbox' +)); + +echo $link; +echo '<div class="hidden">'; +echo elgg_view_module('aside', 'Lightbox Test', $ipsum, array( + 'id' => 'elgg-lightbox-test' +)); +echo '</div>';
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/popup.php b/mod/developers/views/default/theme_preview/miscellaneous/popup.php new file mode 100644 index 000000000..b711bb7cc --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/popup.php @@ -0,0 +1,15 @@ +<?php + +$ipsum = elgg_view('developers/ipsum'); + +$link = elgg_view('output/url', array( + 'text' => 'Popup content', + 'href' => "#elgg-popup-test", + 'rel' => 'popup' +)); + +echo $link; +echo elgg_view_module('popup', 'Popup Test', $ipsum, array( + 'id' => 'elgg-popup-test', + 'class' => 'hidden clearfix developers-content-thin', +));
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/site_menu.php b/mod/developers/views/default/theme_preview/miscellaneous/site_menu.php new file mode 100644 index 000000000..e2384b9f7 --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/site_menu.php @@ -0,0 +1,15 @@ +<?php + +if (!get_input('site_menu')) { + echo elgg_view('output/url', array( + 'text' => 'Show Site Menu', + 'href' => elgg_http_add_url_query_elements(current_page_url(), array('site_menu' => 1)), + 'is_trusted' => true + )); +} else { + echo elgg_view('output/url', array( + 'text' => 'Hide Site Menu', + 'href' => elgg_http_remove_url_query_element(current_page_url(), 'site_menu'), + 'is_trusted' => true + )); +}
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/system_messages.php b/mod/developers/views/default/theme_preview/miscellaneous/system_messages.php new file mode 100644 index 000000000..a6663a3dc --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/system_messages.php @@ -0,0 +1,35 @@ +<?php + +// can't use the ipsum because it includes html when wrapping views. +$message = elgg_view('output/url', array( + 'text' => 'Show system message (system_message())', + 'is_trusted' => true, + 'href' => '#', + 'id' => 'developers-system-message', +// 'onclick' => "elgg.system_message('Elgg System Message');" +)); + +$error = elgg_view('output/url', array( + 'text' => 'Show error message (register_error())', + 'is_trusted' => true, + 'href' => '#', + 'id' => 'developers-error-message', +)); + +?> +<script type="text/javascript"> + $(function() { + $('#developers-system-message').click(function() { + elgg.system_message('Elgg System Message'); + }) + + $('#developers-error-message').click(function() { + elgg.register_error('Elgg Error Message'); + }) + }); +</script> + +<ul> + <li><?php echo $message; ?></li> + <li><?php echo $error; ?></li> +</ul>
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/toggle.php b/mod/developers/views/default/theme_preview/miscellaneous/toggle.php new file mode 100644 index 000000000..abe39ddd8 --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/toggle.php @@ -0,0 +1,15 @@ +<?php + +$ipsum = elgg_view('developers/ipsum'); + +$link = elgg_view('output/url', array( + 'text' => 'Toggle content', + 'href' => "#elgg-toggle-test", + 'rel' => 'toggle' +)); + +echo $link; +echo elgg_view_module('featured', 'Toggle Test', $ipsum, array( + 'id' => 'elgg-toggle-test', + 'class' => 'hidden clearfix developers-content-thin', +));
\ No newline at end of file diff --git a/mod/developers/views/default/theme_preview/miscellaneous/user_hover_menu.php b/mod/developers/views/default/theme_preview/miscellaneous/user_hover_menu.php new file mode 100644 index 000000000..45331b6e0 --- /dev/null +++ b/mod/developers/views/default/theme_preview/miscellaneous/user_hover_menu.php @@ -0,0 +1,16 @@ +<?php + +$me = elgg_get_logged_in_user_entity(); +echo elgg_view_entity_icon($me); + +// show another user if available +$users = elgg_get_entities(array( + 'type' => 'user', + 'wheres' => array("guid != {$me->getGUID()}"), + 'limit' => 1 +)); + +if (is_array($users) && count($users) > 0) { + echo elgg_view_entity_icon($users[0]); +} + diff --git a/mod/developers/views/default/theme_preview/modules.php b/mod/developers/views/default/theme_preview/modules.php index 3e0acb3a5..c46c94296 100644 --- a/mod/developers/views/default/theme_preview/modules.php +++ b/mod/developers/views/default/theme_preview/modules.php @@ -2,5 +2,5 @@ echo elgg_view_module('info', 'Modules (.elgg-module)', elgg_view('theme_preview/modules/modules')); -echo elgg_view_module('info', 'Widgets (.elgg-widget)', elgg_view('theme_preview/modules/widgets')); +echo elgg_view_module('info', 'Widgets (.elgg-module-widget)', elgg_view('theme_preview/modules/widgets')); diff --git a/mod/file/start.php b/mod/file/start.php index cc777d260..7c0c216b2 100644 --- a/mod/file/start.php +++ b/mod/file/start.php @@ -121,8 +121,11 @@ function file_page_handler($page) { file_register_toggle(); include "$file_dir/friends.php"; break; - case 'view': case 'read': // Elgg 1.7 compatibility + register_error(elgg_echo("changebookmark")); + forward("file/view/{$page[1]}"); + break; + case 'view': set_input('guid', $page[1]); include "$file_dir/view.php"; break; diff --git a/mod/file/views/default/object/file.php b/mod/file/views/default/object/file.php index b3f530183..64f19c483 100644 --- a/mod/file/views/default/object/file.php +++ b/mod/file/views/default/object/file.php @@ -68,6 +68,7 @@ if ($full && !elgg_in_context('gallery')) { $params = array( 'entity' => $file, + 'title' => false, 'metadata' => $metadata, 'subtitle' => $subtitle, ); @@ -79,7 +80,6 @@ if ($full && !elgg_in_context('gallery')) { echo elgg_view('object/elements/full', array( 'entity' => $file, - 'title' => false, 'icon' => $file_icon, 'summary' => $summary, 'body' => $body, diff --git a/mod/groups/languages/en.php b/mod/groups/languages/en.php index 0d57f1680..9e0799b3a 100644 --- a/mod/groups/languages/en.php +++ b/mod/groups/languages/en.php @@ -20,7 +20,9 @@ $english = array( 'groups:edit' => "Edit group", 'groups:delete' => 'Delete group', 'groups:membershiprequests' => 'Manage join requests', + 'groups:membershiprequests:pending' => 'Manage join requests (%s)', 'groups:invitations' => 'Group invitations', + 'groups:invitations:pending' => 'Group invitations (%s)', 'groups:icon' => 'Group icon (leave blank to leave unchanged)', 'groups:name' => 'Group name', @@ -30,6 +32,12 @@ $english = array( 'groups:interests' => 'Tags', 'groups:website' => 'Website', 'groups:members' => 'Group members', + 'groups:my_status' => 'My status', + 'groups:my_status:group_owner' => 'You own this group', + 'groups:my_status:group_member' => 'You are in this group', + 'groups:subscribed' => 'Group notifications on', + 'groups:unsubscribed' => 'Group notifications off', + 'groups:members:title' => 'Members of %s', 'groups:members:more' => "View all members", 'groups:membership' => "Group membership permissions", @@ -211,7 +219,7 @@ View and reply to the discussion: 'groups:updated' => "Last reply by %s %s", 'groups:started' => "Started by %s", 'groups:joinrequest:remove:check' => 'Are you sure you want to remove this join request?', - 'groups:invite:remove:check' => 'Are you sure you want to remove this invite?', + 'groups:invite:remove:check' => 'Are you sure you want to remove this invitation?', 'groups:invite:body' => "Hi %s, %s invited you to join the '%s' group. Click below to view your invitations: diff --git a/mod/groups/lib/groups.php b/mod/groups/lib/groups.php index 505cacd01..d8d0f568d 100644 --- a/mod/groups/lib/groups.php +++ b/mod/groups/lib/groups.php @@ -152,7 +152,7 @@ function groups_handle_mine_page() { elgg_register_title_button(); - $content = elgg_list_entities_from_relationship_count(array( + $content = elgg_list_entities_from_relationship(array( 'type' => 'group', 'relationship' => 'member', 'relationship_guid' => elgg_get_page_owner_guid(), @@ -264,14 +264,33 @@ function groups_handle_profile_page($guid) { groups_register_profile_buttons($group); $content = elgg_view('groups/profile/layout', array('entity' => $group)); - if (group_gatekeeper(false)) { - $sidebar = ''; + $sidebar = ''; + + if (group_gatekeeper(false)) { if (elgg_is_active_plugin('search')) { $sidebar .= elgg_view('groups/sidebar/search', array('entity' => $group)); } $sidebar .= elgg_view('groups/sidebar/members', array('entity' => $group)); - } else { - $sidebar = ''; + + $subscribed = false; + if (elgg_is_active_plugin('notifications')) { + global $NOTIFICATION_HANDLERS; + + foreach ($NOTIFICATION_HANDLERS as $method => $foo) { + $relationship = check_entity_relationship(elgg_get_logged_in_user_guid(), + 'notify' . $method, $guid); + + if ($relationship) { + $subscribed = true; + break; + } + } + } + + $sidebar .= elgg_view('groups/sidebar/my_status', array( + 'entity' => $group, + 'subscribed' => $subscribed + )); } $params = array( diff --git a/mod/groups/start.php b/mod/groups/start.php index 9dca7dc16..4e49d9e55 100644 --- a/mod/groups/start.php +++ b/mod/groups/start.php @@ -144,9 +144,24 @@ function groups_setup_sidebar_menus() { if (elgg_in_context('group_profile')) { if (elgg_is_logged_in() && $page_owner->canEdit() && !$page_owner->isPublicMembership()) { $url = elgg_get_site_url() . "groups/requests/{$page_owner->getGUID()}"; + + $count = elgg_get_entities_from_relationship(array( + 'type' => 'user', + 'relationship' => 'membership_request', + 'relationship_guid' => $guid, + 'inverse_relationship' => true, + 'count' => true, + )); + + if ($count) { + $text = elgg_echo('groups:membershiprequests:pending', array($count)); + } else { + $text = elgg_echo('groups:membershiprequests'); + } + elgg_register_menu_item('page', array( 'name' => 'membership_requests', - 'text' => elgg_echo('groups:membershiprequests'), + 'text' => $text, 'href' => $url, )); } @@ -163,11 +178,21 @@ function groups_setup_sidebar_menus() { $url = "groups/owner/$user->username"; $item = new ElggMenuItem('groups:owned', elgg_echo('groups:owned'), $url); elgg_register_menu_item('page', $item); + $url = "groups/member/$user->username"; $item = new ElggMenuItem('groups:member', elgg_echo('groups:yours'), $url); elgg_register_menu_item('page', $item); + $url = "groups/invitations/$user->username"; - $item = new ElggMenuItem('groups:user:invites', elgg_echo('groups:invitations'), $url); + $invitations = groups_get_invited_groups($user->getGUID()); + if (is_array($invitations) && !empty($invitations)) { + $invitation_count = count($invitations); + $text = elgg_echo('groups:invitations:pending', array($invitation_count)); + } else { + $text = elgg_echo('groups:invitations'); + } + + $item = new ElggMenuItem('groups:user:invites', $text, $url); elgg_register_menu_item('page', $item); } } diff --git a/mod/groups/views/default/groups/css.php b/mod/groups/views/default/groups/css.php index 9c65d1602..6f710ddab 100644 --- a/mod/groups/views/default/groups/css.php +++ b/mod/groups/views/default/groups/css.php @@ -9,7 +9,10 @@ .groups-profile > .elgg-image { margin-right: 10px; } - +.groups-profile img { + width: 100%; + height: auto; +} .groups-stats { background: #eeeeee; padding: 5px; @@ -54,3 +57,24 @@ .groups-latest-reply { float: right; } + +.elgg-menu-groups-my-status li a { + display: block; + + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + + background-color: white; + margin: 3px 0 5px 0; + padding: 2px 4px 2px 8px; +} +.elgg-menu-groups-my-status li a:hover { + background-color: #0054A7; + color: white; + text-decoration: none; +} +.elgg-menu-groups-my-status li.elgg-state-selected > a { + background-color: #4690D6; + color: white; +} diff --git a/mod/groups/views/default/groups/profile/summary.php b/mod/groups/views/default/groups/profile/summary.php index 54abcb1e5..f1221f19a 100644 --- a/mod/groups/views/default/groups/profile/summary.php +++ b/mod/groups/views/default/groups/profile/summary.php @@ -15,6 +15,12 @@ if (!isset($vars['entity']) || !$vars['entity']) { $group = $vars['entity']; $owner = $group->getOwnerEntity(); +if (!$owner) { + // not having an owner is very bad so we throw an exception + $msg = elgg_echo('InvalidParameterException:IdNotExistForGUID', array('group owner', $group->guid)); + throw new InvalidParameterException($msg); +} + ?> <div class="groups-profile clearfix elgg-image-block"> <div class="elgg-image"> diff --git a/mod/groups/views/default/groups/sidebar/my_status.php b/mod/groups/views/default/groups/sidebar/my_status.php new file mode 100644 index 000000000..4c36c0213 --- /dev/null +++ b/mod/groups/views/default/groups/sidebar/my_status.php @@ -0,0 +1,62 @@ +<?php +/** + * Group status for logged in user + * + * @package ElggGroups + * + * @uses $vars['entity'] Group entity + */ + +$group = elgg_extract('entity', $vars); +$user = elgg_get_logged_in_user_entity(); +$subscribed = elgg_extract('subscribed', $vars); + +if (!elgg_is_logged_in()) { + return true; +} +$t = new ElggMenuItem(); +// membership status +$is_member = $group->isMember($user); +$is_owner = $group->getOwnerEntity() == $user; + +if ($is_owner) { + elgg_register_menu_item('groups:my_status', array( + 'name' => 'membership_status', + 'text' => '<a>' . elgg_echo('groups:my_status:group_owner') . '</a>', + 'href' => false + )); +} elseif ($is_member) { + elgg_register_menu_item('groups:my_status', array( + 'name' => 'membership_status', + 'text' => '<a>' . elgg_echo('groups:my_status:group_member') . '</a>', + 'href' => false + )); +} else { + elgg_register_menu_item('groups:my_status', array( + 'name' => 'membership_status', + 'text' => elgg_echo('groups:join'), + 'href' => "/action/groups/join?group_guid={$group->getGUID()}", + 'is_action' => true + )); +} + +// notification info +if (elgg_is_active_plugin('notifications')) { + if ($subscribed) { + elgg_register_menu_item('groups:my_status', array( + 'name' => 'subscription_status', + 'text' => elgg_echo('groups:subscribed'), + 'href' => "notifications/group/$user->username", + 'is_action' => true + )); + } else { + elgg_register_menu_item('groups:my_status', array( + 'name' => 'subscription_status', + 'text' => elgg_echo('groups:unsubscribed'), + 'href' => "notifications/group/$user->username" + )); + } +} + +$body = elgg_view_menu('groups:my_status'); +echo elgg_view_module('aside', elgg_echo('groups:my_status'), $body); diff --git a/mod/groups/views/rss/object/groupforumtopic.php b/mod/groups/views/rss/object/groupforumtopic.php index d730ef796..b2d05d488 100644 --- a/mod/groups/views/rss/object/groupforumtopic.php +++ b/mod/groups/views/rss/object/groupforumtopic.php @@ -14,7 +14,7 @@ if (empty($title)) { $permalink = htmlspecialchars($vars['entity']->getURL(), ENT_NOQUOTES, 'UTF-8'); $pubdate = date('r', $vars['entity']->getTimeCreated()); -$description = autop($vars['entity']->description); +$description = elgg_autop($vars['entity']->description); $creator = elgg_view('page/components/creator', $vars); $georss = elgg_view('page/components/georss', $vars); diff --git a/mod/messages/start.php b/mod/messages/start.php index 2e61d6e21..e17640098 100644 --- a/mod/messages/start.php +++ b/mod/messages/start.php @@ -212,18 +212,20 @@ function messages_can_edit_container($hook_name, $entity_type, $return_value, $p * * @param string $subject The subject line of the message * @param string $body The body of the mesage - * @param int $send_to The GUID of the user to send to - * @param int $from Optionally, the GUID of the user to send from - * @param int $reply The GUID of the message to reply from (default: none) - * @param true|false $notify Send a notification (default: true) - * @param true|false $add_to_sent If true (default), will add a message to the sender's 'sent' tray + * @param int $recipient_guid The GUID of the user to send to + * @param int $sender_guid Optionally, the GUID of the user to send from + * @param int $original_msg_guid The GUID of the message to reply from (default: none) + * @param bool $notify Send a notification (default: true) + * @param bool $add_to_sent If true (default), will add a message to the sender's 'sent' tray * @return bool */ -function messages_send($subject, $body, $send_to, $from = 0, $reply = 0, $notify = true, $add_to_sent = true) { +function messages_send($subject, $body, $recipient_guid, $sender_guid = 0, $original_msg_guid = 0, $notify = true, $add_to_sent = true) { + // @todo remove globals global $messagesendflag; $messagesendflag = 1; + // @todo remove globals global $messages_pm; if ($notify) { $messages_pm = 1; @@ -231,33 +233,40 @@ function messages_send($subject, $body, $send_to, $from = 0, $reply = 0, $notify $messages_pm = 0; } - // If $from == 0, set to current user - if ($from == 0) { - $from = (int) elgg_get_logged_in_user_guid(); + // If $sender_guid == 0, set to current user + if ($sender_guid == 0) { + $sender_guid = (int) elgg_get_logged_in_user_guid(); } // Initialise 2 new ElggObject $message_to = new ElggObject(); $message_sent = new ElggObject(); + $message_to->subtype = "messages"; $message_sent->subtype = "messages"; - $message_to->owner_guid = $send_to; - $message_to->container_guid = $send_to; - $message_sent->owner_guid = $from; - $message_sent->container_guid = $from; + + $message_to->owner_guid = $recipient_guid; + $message_to->container_guid = $recipient_guid; + $message_sent->owner_guid = $sender_guid; + $message_sent->container_guid = $sender_guid; + $message_to->access_id = ACCESS_PUBLIC; $message_sent->access_id = ACCESS_PUBLIC; + $message_to->title = $subject; $message_to->description = $body; + $message_sent->title = $subject; $message_sent->description = $body; - $message_to->toId = $send_to; // the user receiving the message - $message_to->fromId = $from; // the user receiving the message + + $message_to->toId = $recipient_guid; // the user receiving the message + $message_to->fromId = $sender_guid; // the user receiving the message $message_to->readYet = 0; // this is a toggle between 0 / 1 (1 = read) $message_to->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag $message_to->hiddenTo = 0; // this is used when a user deletes a message in their inbox - $message_sent->toId = $send_to; // the user receiving the message - $message_sent->fromId = $from; // the user receiving the message + + $message_sent->toId = $recipient_guid; // the user receiving the message + $message_sent->fromId = $sender_guid; // the user receiving the message $message_sent->readYet = 0; // this is a toggle between 0 / 1 (1 = read) $message_sent->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag $message_sent->hiddenTo = 0; // this is used when a user deletes a message in their inbox @@ -270,7 +279,7 @@ function messages_send($subject, $body, $send_to, $from = 0, $reply = 0, $notify // Save the copy of the message that goes to the sender if ($add_to_sent) { - $success2 = $message_sent->save(); + $message_sent->save(); } $message_to->access_id = ACCESS_PRIVATE; @@ -283,22 +292,25 @@ function messages_send($subject, $body, $send_to, $from = 0, $reply = 0, $notify // if the new message is a reply then create a relationship link between the new message // and the message it is in reply to - if ($reply && $success){ - $create_relationship = add_entity_relationship($message_sent->guid, "reply", $reply); + if ($original_msg_guid && $success) { + add_entity_relationship($message_sent->guid, "reply", $original_msg_guid); } $message_contents = strip_tags($body); - if ($send_to != elgg_get_logged_in_user_entity() && $notify) { + if (($recipient_guid != elgg_get_logged_in_user_guid()) && $notify) { + $recipient = get_user($recipient_guid); + $sender = get_user($sender_guid); + $subject = elgg_echo('messages:email:subject'); $body = elgg_echo('messages:email:body', array( - elgg_get_logged_in_user_entity()->name, + $sender->name, $message_contents, - elgg_get_site_url() . "messages/inbox/" . $user->username, - elgg_get_logged_in_user_entity()->name, - elgg_get_site_url() . "messages/compose?send_to=" . elgg_get_logged_in_user_guid() + elgg_get_site_url() . "messages/inbox/" . $recipient->username, + $sender->name, + elgg_get_site_url() . "messages/compose?send_to=" . $sender_guid )); - notify_user($send_to, elgg_get_logged_in_user_guid(), $subject, $body); + notify_user($recipient_guid, $sender_guid, $subject, $body); } $messagesendflag = 0; diff --git a/mod/notifications/actions/groupsave.php b/mod/notifications/actions/groupsave.php index 7838f7e63..2dd2a6db3 100644 --- a/mod/notifications/actions/groupsave.php +++ b/mod/notifications/actions/groupsave.php @@ -30,14 +30,11 @@ if ($groupmemberships = elgg_get_entities_from_relationship($options)) { } } -// Load important global vars -global $NOTIFICATION_HANDLERS; -foreach($NOTIFICATION_HANDLERS as $method => $foo) { - $subscriptions[$method] = get_input($method.'subscriptions'); - $personal[$method] = get_input($method.'personal'); - $collections[$method] = get_input($method.'collections'); - if (!empty($groups)) { - foreach($groups as $group) { +if (!empty($groups)) { + global $NOTIFICATION_HANDLERS; + foreach ($NOTIFICATION_HANDLERS as $method => $foo) { + $subscriptions[$method] = get_input($method.'subscriptions', array()); + foreach ($groups as $group) { if (in_array($group, $subscriptions[$method])) { add_entity_relationship($user->guid, 'notify'.$method, $group); } else { diff --git a/mod/pages/actions/pages/edit.php b/mod/pages/actions/pages/edit.php index fe5754d76..40215e02e 100644 --- a/mod/pages/actions/pages/edit.php +++ b/mod/pages/actions/pages/edit.php @@ -60,6 +60,9 @@ if (sizeof($input) > 0) { if (($name == 'access_id' || $name == 'write_access_id') && !$can_change_access) { continue; } + if ($name == 'parent_guid') { + continue; + } $page->$name = $value; } @@ -68,7 +71,27 @@ if (sizeof($input) > 0) { // need to add check to make sure user can write to container $page->container_guid = $container_guid; -if ($parent_guid) { +if ($parent_guid && $parent_guid != $page_guid) { + // Check if parent isn't below the page in the tree + if ($page_guid) { + $tree_page = get_entity($parent_guid); + while ($tree_page->parent_guid > 0 && $page_guid != $tree_page->guid) { + $tree_page = get_entity($tree_page->parent_guid); + } + // If is below, bring all child elements forward + if ($page_guid == $tree_page->guid) { + $previous_parent = $page->parent_guid; + $children = elgg_get_entities_from_metadata(array( + 'metadata_name' => 'parent_guid', + 'metadata_value' => $page->getGUID() + )); + if ($children) { + foreach ($children as $child) { + $child->parent_guid = $previous_parent; + } + } + } + } $page->parent_guid = $parent_guid; } diff --git a/mod/pages/languages/en.php b/mod/pages/languages/en.php index eb9d22708..930676b3e 100644 --- a/mod/pages/languages/en.php +++ b/mod/pages/languages/en.php @@ -61,6 +61,7 @@ View and comment on the new page: 'pages:title' => 'Page title', 'pages:description' => 'Page text', 'pages:tags' => 'Tags', + 'pages:parent_guid' => 'Parent page', 'pages:access_id' => 'Read access', 'pages:write_access_id' => 'Write access', @@ -110,4 +111,4 @@ View and comment on the new page: 'pages:backtoparent' => "Back to '%s'", ); -add_translation("en", $english);
\ No newline at end of file +add_translation("en", $english); diff --git a/mod/pages/lib/pages.php b/mod/pages/lib/pages.php index 9a9ba12e9..afe42b68f 100644 --- a/mod/pages/lib/pages.php +++ b/mod/pages/lib/pages.php @@ -65,11 +65,11 @@ function pages_prepare_parent_breadcrumbs($page) { } /** - * Register the navigation menu + * Produce the navigation tree * * @param ElggEntity $container Container entity for the pages */ -function pages_register_navigation_tree($container) { +function pages_get_navigation_tree($container) { if (!$container) { return; } @@ -84,13 +84,18 @@ function pages_register_navigation_tree($container) { if (!$top_pages) { return; } + + $tree = array(); + $depths = array(); foreach ($top_pages as $page) { - elgg_register_menu_item('pages_nav', array( - 'name' => $page->getGUID(), - 'text' => $page->title, - 'href' => $page->getURL(), - )); + $tree[] = array( + 'guid' => $page->getGUID(), + 'title' => $page->title, + 'url' => $page->getURL(), + 'depth' => 0, + ); + $depths[$page->guid] = 0; $stack = array(); array_push($stack, $page); @@ -106,15 +111,37 @@ function pages_register_navigation_tree($container) { if ($children) { foreach ($children as $child) { - elgg_register_menu_item('pages_nav', array( - 'name' => $child->getGUID(), - 'text' => $child->title, - 'href' => $child->getURL(), - 'parent_name' => $parent->getGUID(), - )); + $tree[] = array( + 'guid' => $child->getGUID(), + 'title' => $child->title, + 'url' => $child->getURL(), + 'parent_guid' => $parent->getGUID(), + 'depth' => $depths[$parent->guid] + 1, + ); + $depths[$child->guid] = $depths[$parent->guid] + 1; array_push($stack, $child); } } } } + return $tree; +} + +/** + * Register the navigation menu + * + * @param ElggEntity $container Container entity for the pages + */ +function pages_register_navigation_tree($container) { + $pages = pages_get_navigation_tree($container); + if ($pages) { + foreach ($pages as $page) { + elgg_register_menu_item('pages_nav', array( + 'name' => $page['guid'], + 'text' => $page['title'], + 'href' => $page['url'], + 'parent_name' => $page['parent_guid'], + )); + } + } } diff --git a/mod/pages/start.php b/mod/pages/start.php index 6b0ad38b0..6d974f122 100644 --- a/mod/pages/start.php +++ b/mod/pages/start.php @@ -63,6 +63,7 @@ function pages_init() { 'title' => 'text', 'description' => 'longtext', 'tags' => 'tags', + 'parent_guid' => 'parent', 'access_id' => 'access', 'write_access_id' => 'write_access', )); diff --git a/mod/pages/views/default/forms/pages/edit.php b/mod/pages/views/default/forms/pages/edit.php index 9469f5eb9..e14ff19ec 100644 --- a/mod/pages/views/default/forms/pages/edit.php +++ b/mod/pages/views/default/forms/pages/edit.php @@ -18,6 +18,18 @@ foreach ($variables as $name => $type) { if (($type == 'access' || $type == 'write_access') && !$can_change_access) { continue; } + + // don't show parent picker input for top or new pages. + if ($name == 'parent_guid' && (!$vars['parent_guid'] || !$vars['guid'])) { + continue; + } + + if ($type == 'parent') { + $input_view = "pages/input/$type"; + } else { + $input_view = "input/$type"; + } + ?> <div> <label><?php echo elgg_echo("pages:$name") ?></label> @@ -26,9 +38,10 @@ foreach ($variables as $name => $type) { echo '<br />'; } - echo elgg_view("input/$type", array( + echo elgg_view($input_view, array( 'name' => $name, 'value' => $vars[$name], + 'entity' => ($name == 'parent_guid') ? $vars['entity'] : null, )); ?> </div> @@ -52,7 +65,7 @@ echo elgg_view('input/hidden', array( 'name' => 'container_guid', 'value' => $vars['container_guid'], )); -if ($vars['parent_guid']) { +if (!$vars['guid']) { echo elgg_view('input/hidden', array( 'name' => 'parent_guid', 'value' => $vars['parent_guid'], diff --git a/mod/pages/views/default/pages/input/parent.php b/mod/pages/views/default/pages/input/parent.php new file mode 100644 index 000000000..c5ee3c3fb --- /dev/null +++ b/mod/pages/views/default/pages/input/parent.php @@ -0,0 +1,37 @@ +<?php +/** + * Parent picker + * + * @uses $vars['value'] The current value, if any + * @uses $vars['options_values'] + * @uses $vars['name'] The name of the input field + * @uses $vars['entity'] Optional. The child entity (uses container_guid) + */ + +elgg_load_library('elgg:pages'); + +if (empty($vars['entity'])) { + $container = elgg_get_page_owner_entity(); +} else { + $container = $vars['entity']->getContainerEntity(); +} + +$pages = pages_get_navigation_tree($container); +$options = array(); + +foreach ($pages as $page) { + $spacing = ""; + for ($i = 0; $i < $page['depth']; $i++) { + $spacing .= "--"; + } + $options[$page['guid']] = "$spacing " . $page['title']; +} + +$defaults = array( + 'class' => 'elgg-pages-input-parent-picker', + 'options_values' => $options, +); + +$vars = array_merge($defaults, $vars); + +echo elgg_view('input/dropdown', $vars); diff --git a/mod/search/search_hooks.php b/mod/search/search_hooks.php index 2143a0d24..62058abf1 100644 --- a/mod/search/search_hooks.php +++ b/mod/search/search_hooks.php @@ -122,24 +122,35 @@ function search_users_hook($hook, $type, $value, $params) { $query = sanitise_string($params['query']); - $join = "JOIN {$db_prefix}users_entity ue ON e.guid = ue.guid"; - $params['joins'] = array($join); - -// $where = "(ue.guid = e.guid -// AND (ue.username LIKE '%$query%' -// OR ue.name LIKE '%$query%' -// ) -// )"; - + $params['joins'] = array( + "JOIN {$db_prefix}users_entity ue ON e.guid = ue.guid", + "JOIN {$db_prefix}metadata md on e.guid = md.entity_guid", + "JOIN {$db_prefix}metastrings msv ON n_table.value_id = msv.id" + ); + + // username and display name $fields = array('username', 'name'); $where = search_get_where_sql('ue', $fields, $params, FALSE); + + // profile fields + $profile_fields = array_keys(elgg_get_config('profile_fields')); - $params['wheres'] = array($where); + // get the where clauses for the md names + // can't use egef_metadata() because the n_table join comes too late. + $clauses = elgg_entities_get_metastrings_options('metadata', array( + 'metadata_names' => $profile_fields, + )); + + $params['joins'] = array_merge($clauses['joins'], $params['joins']); + // no fulltext index, can't disable fulltext search in this function. + // $md_where .= " AND " . search_get_where_sql('msv', array('string'), $params, FALSE); + $md_where = "(({$clauses['wheres'][0]}) AND msv.string LIKE '%$query%')"; + + $params['wheres'] = array("(($where) OR ($md_where))"); // override subtype -- All users should be returned regardless of subtype. $params['subtype'] = ELGG_ENTITIES_ANY_VALUE; - - $params['count'] = TRUE; + $params['count'] = true; $count = elgg_get_entities($params); // no need to continue if nothing here. @@ -152,11 +163,27 @@ function search_users_hook($hook, $type, $value, $params) { // add the volatile data for why these entities have been returned. foreach ($entities as $entity) { - $username = search_get_highlighted_relevant_substrings($entity->username, $query); - $entity->setVolatileData('search_matched_title', $username); + + $title = search_get_highlighted_relevant_substrings($entity->name, $query); - $name = search_get_highlighted_relevant_substrings($entity->name, $query); - $entity->setVolatileData('search_matched_description', $name); + // include the username if it matches but the display name doesn't. + if (false !== strpos($entity->username, $query)) { + $username = search_get_highlighted_relevant_substrings($entity->username, $query); + $title .= " ($username)"; + } + + $entity->setVolatileData('search_matched_title', $title); + + $matched = ''; + foreach ($profile_fields as $md) { + $text = $entity->$md; + if (stristr($text, $query)) { + $matched .= elgg_echo("profile:{$md}") . ': ' + . search_get_highlighted_relevant_substrings($text, $query); + } + } + + $entity->setVolatileData('search_matched_description', $matched); } return array( diff --git a/mod/search/start.php b/mod/search/start.php index d2d7ed3c2..8a112a3a3 100644 --- a/mod/search/start.php +++ b/mod/search/start.php @@ -77,7 +77,7 @@ function search_page_handler($page) { /** * Return a string with highlighted matched queries and relevant context - * Determins context based upon occurance and distance of words with each other. + * Determines context based upon occurance and distance of words with each other. * * @param string $haystack * @param string $query @@ -94,6 +94,8 @@ function search_get_highlighted_relevant_substrings($haystack, $query, $min_matc if (!$tag_match) { $words = search_remove_ignored_words($query, 'array'); + } else { + $words = array(); } // if haystack < $max_length return the entire haystack w/formatting immediately @@ -142,7 +144,7 @@ function search_get_highlighted_relevant_substrings($haystack, $query, $min_matc $total_length = array_sum($offsets); $add_length = 0; - if ($total_length < $max_length) { + if ($total_length < $max_length && $offsets) { $add_length = floor((($max_length - $total_length) / count($offsets)) / 2); $starts = array(); diff --git a/mod/search/views/default/search/no_results.php b/mod/search/views/default/search/no_results.php index 74b5b2cfa..0e9a5e295 100644 --- a/mod/search/views/default/search/no_results.php +++ b/mod/search/views/default/search/no_results.php @@ -3,4 +3,4 @@ * No results from search */ -echo autop(elgg_echo('search:no_results')); +echo elgg_autop(elgg_echo('search:no_results')); diff --git a/mod/thewire/start.php b/mod/thewire/start.php index 1ba48263a..8b01cc57a 100644 --- a/mod/thewire/start.php +++ b/mod/thewire/start.php @@ -67,6 +67,8 @@ function thewire_init() { elgg_register_action("thewire/delete", "$action_base/delete.php"); elgg_register_plugin_hook_handler('unit_test', 'system', 'thewire_test'); + + elgg_register_event_handler('upgrade', 'system', 'thewire_run_upgrades'); } /** @@ -462,3 +464,12 @@ function thewire_test($hook, $type, $value, $params) { $value[] = $CONFIG->pluginspath . 'thewire/tests/regex.php'; return $value; } + +function thewire_run_upgrades() { + $path = dirname(__FILE__) . '/upgrades/'; + $files = elgg_get_upgrade_files($path); + + foreach ($files as $file) { + include $path . $file; + } +}
\ No newline at end of file diff --git a/mod/thewire/upgrades/2012122701-fix_entity_class.php b/mod/thewire/upgrades/2012122701-fix_entity_class.php new file mode 100644 index 000000000..a1f382712 --- /dev/null +++ b/mod/thewire/upgrades/2012122701-fix_entity_class.php @@ -0,0 +1,8 @@ +<?php +/** + * Register thewire objects with the ElggWire class. + */ + +if (get_subtype_id('object', 'thewire')) { + update_subtype('object', 'thewire', 'ElggWire'); +}
\ No newline at end of file diff --git a/mod/thewire/views/rss/object/thewire.php b/mod/thewire/views/rss/object/thewire.php index 494c2c8dc..8fddb8aa8 100644 --- a/mod/thewire/views/rss/object/thewire.php +++ b/mod/thewire/views/rss/object/thewire.php @@ -15,7 +15,7 @@ $title = elgg_echo('thewire:by', array($owner->name)); $permalink = htmlspecialchars($vars['entity']->getURL(), ENT_NOQUOTES, 'UTF-8'); $pubdate = date('r', $vars['entity']->getTimeCreated()); -$description = autop($vars['entity']->description); +$description = elgg_autop($vars['entity']->description); $creator = elgg_view('page/components/creator', $vars); $georss = elgg_view('page/components/georss', $vars); diff --git a/mod/twitter/languages/en.php b/mod/twitter/languages/en.php index 29700744a..11e745ba1 100644 --- a/mod/twitter/languages/en.php +++ b/mod/twitter/languages/en.php @@ -4,13 +4,14 @@ */ $english = array( - 'twitter:title' => 'Twitter', 'twitter:info' => 'Display your latest tweets', - 'twitter:username' => 'Enter your twitter username.', - 'twitter:num' => 'The number of tweets to show.', + 'twitter:username' => 'Your twitter username', + 'twitter:num' => 'Number of tweets to show*', 'twitter:visit' => 'visit my twitter', - 'twitter:notset' => 'This Twitter widget is not yet set to go. To display your latest tweets, click on - edit - and fill in your details', + 'twitter:notset' => 'This widget needs to be configured. To display your latest tweets, click the customize icon and fill in your Twitter username.', + 'twitter:invalid' => 'This widget is configured with an invalid Twitter username. Click the customize icon to correct it.', + 'twitter:apibug' => "*Due to a bug in the Twitter 1.0 API, you may see fewer tweets than you ask for.", ); add_translation("en", $english); diff --git a/mod/twitter/views/default/widgets/twitter/content.php b/mod/twitter/views/default/widgets/twitter/content.php index c616d944c..caefd369a 100644 --- a/mod/twitter/views/default/widgets/twitter/content.php +++ b/mod/twitter/views/default/widgets/twitter/content.php @@ -6,26 +6,37 @@ * @package ElggTwitter */ -//some required params - $username = $vars['entity']->twitter_username; + +if (empty($username)) { + echo "<p>" . elgg_echo("twitter:notset") . "</p>"; + return; +} + +$username_is_valid = preg_match('~^[a-zA-Z0-9_]{1,20}$~', $username); +if (!$username_is_valid) { + echo "<p>" . elgg_echo("twitter:invalid") . "</p>"; + return; +} + + $num = $vars['entity']->twitter_num; +if (empty($num)) { + $num = 5; +} -// if the twitter username is empty, then do not show -if ($username) { +// @todo upgrade to 1.1 API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline +$script_url = "https://api.twitter.com/1/statuses/user_timeline/" . urlencode($username) . ".json" + . "?callback=twitterCallback2&count=" . (int) $num; ?> - <div id="twitter_widget"> <ul id="twitter_update_list"></ul> - <p class="visit_twitter"><a href="http://twitter.com/<?php echo $username; ?>"><?php echo elgg_echo("twitter:visit"); ?></a></p> + <p class="visit_twitter"><?php echo elgg_view('output/url', array( + 'text' => elgg_echo("twitter:visit"), + 'href' => 'http://twitter.com/' . urlencode($username), + 'is_trusted' => true, + )) ?></p> <script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script> - <script type="text/javascript" src="https://api.twitter.com/1/statuses/user_timeline/<?php echo $username; ?>.json?callback=twitterCallback2&count=<?php echo $num; ?>"></script> + <script type="text/javascript" src="<?php echo htmlspecialchars($script_url, ENT_QUOTES, 'UTF-8') ?>"></script> </div> - -<?php -} else { - - echo "<p>" . elgg_echo("twitter:notset") . ".</p>"; - -} diff --git a/mod/twitter/views/default/widgets/twitter/edit.php b/mod/twitter/views/default/widgets/twitter/edit.php index 5da3a7e55..c3fc6f0d5 100644 --- a/mod/twitter/views/default/widgets/twitter/edit.php +++ b/mod/twitter/views/default/widgets/twitter/edit.php @@ -1,16 +1,24 @@ <?php - /** - * Elgg twitter edit page - * - * @package ElggTwitter - */ +/** + * Elgg twitter edit page + * + * @package ElggTwitter + */ ?> - <p> - <?php echo elgg_echo("twitter:username"); ?> - <input type="text" name="params[twitter_username]" value="<?php echo htmlentities($vars['entity']->twitter_username); ?>" /> - <br /><?php echo elgg_echo("twitter:num"); ?> - <input type="text" name="params[twitter_num]" value="<?php echo htmlentities($vars['entity']->twitter_num); ?>" /> - - </p>
\ No newline at end of file +<div> + <?php echo elgg_echo("twitter:username"); ?> + <?php echo elgg_view('input/text', array( + 'name' => 'params[twitter_username]', + 'value' => $vars['entity']->twitter_username, + )) ?> +</div> +<div> + <?php echo elgg_echo("twitter:num"); ?> + <?php echo elgg_view('input/text', array( + 'name' => 'params[twitter_num]', + 'value' => $vars['entity']->twitter_num, + )) ?> + <span class="elgg-text-help"><?php echo elgg_echo("twitter:apibug"); ?></span> +</div>
\ No newline at end of file diff --git a/mod/twitter_api/lib/twitter_api.php b/mod/twitter_api/lib/twitter_api.php index fbce00d34..e163d2b3e 100644 --- a/mod/twitter_api/lib/twitter_api.php +++ b/mod/twitter_api/lib/twitter_api.php @@ -29,6 +29,8 @@ function twitter_api_allow_sign_on_with_twitter() { * This includes the login URL as the callback */ function twitter_api_forward() { + global $SESSION; + // sanity check if (!twitter_api_allow_sign_on_with_twitter()) { forward(); @@ -37,6 +39,20 @@ function twitter_api_forward() { $callback = elgg_normalize_url("twitter_api/login"); $request_link = twitter_api_get_authorize_url($callback); + // capture metadata about login to persist through redirects + $login_metadata = array( + 'persistent' => (bool) get_input("persistent"), + ); + // capture referrer if in site, but not the twitter_api + if (!empty($SESSION['last_forward_from'])) { + $login_metadata['forward'] = $SESSION['last_forward_from']; + } elseif (!empty($_SERVER['HTTP_REFERER']) + && 0 === strpos($_SERVER['HTTP_REFERER'], elgg_get_site_url()) + && 0 !== strpos($_SERVER['HTTP_REFERER'], elgg_get_site_url() . 'twitter_api/')) { + $login_metadata['forward'] = $_SERVER['HTTP_REFERER']; + } + $SESSION['twitter_api_login_metadata'] = $login_metadata; + forward($request_link, 'twitter_api'); } @@ -55,6 +71,8 @@ function twitter_api_forward() { * the Twitter OAuth data. */ function twitter_api_login() { + /* @var ElggSession $SESSION */ + global $SESSION; // sanity check if (!twitter_api_allow_sign_on_with_twitter()) { @@ -62,6 +80,20 @@ function twitter_api_login() { } $token = twitter_api_get_access_token(get_input('oauth_verifier')); + + $persistent = false; + $forward = ''; + + // fetch login metadata from session + $login_metadata = $SESSION['twitter_api_login_metadata']; + unset($SESSION['twitter_api_login_metadata']); + if (!empty($login_metadata['persistent'])) { + $persistent = true; + } + if (!empty($login_metadata['forward'])) { + $forward = $login_metadata['forward']; + } + if (!isset($token['oauth_token']) or !isset($token['oauth_token_secret'])) { register_error(elgg_echo('twitter_api:login:error')); forward(); @@ -81,13 +113,13 @@ function twitter_api_login() { $users = elgg_get_entities_from_plugin_user_settings($options); if ($users) { - if (count($users) == 1 && login($users[0])) { - system_message(elgg_echo('twitter_api:login:success')); + if (count($users) == 1 && login($users[0], $persistent)) { + system_message(elgg_echo('twitter_api:login:success')); + forward($forward); } else { register_error(elgg_echo('twitter_api:login:error')); + forward(); } - - forward(elgg_get_site_url()); } else { $consumer_key = elgg_get_plugin_setting('consumer_key', 'twitter_api'); $consumer_secret = elgg_get_plugin_setting('consumer_secret', 'twitter_api'); @@ -301,9 +333,11 @@ function twitter_api_get_authorize_url($callback = NULL, $login = true) { /** * Returns the access token to use in twitter calls. * - * @param unknown_type $oauth_verifier + * @param bool $oauth_verifier + * @return array */ function twitter_api_get_access_token($oauth_verifier = FALSE) { + /* @var ElggSession $SESSION */ global $SESSION; $consumer_key = elgg_get_plugin_setting('consumer_key', 'twitter_api'); @@ -312,7 +346,7 @@ function twitter_api_get_access_token($oauth_verifier = FALSE) { // retrieve stored tokens $oauth_token = $SESSION['twitter_api']['oauth_token']; $oauth_token_secret = $SESSION['twitter_api']['oauth_token_secret']; - $SESSION->offsetUnset('twitter_api'); + unset($SESSION['twitter_api']); // fetch an access token $api = new TwitterOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret); diff --git a/mod/twitter_api/start.php b/mod/twitter_api/start.php index 08bce5479..e6221de6b 100644 --- a/mod/twitter_api/start.php +++ b/mod/twitter_api/start.php @@ -20,6 +20,7 @@ function twitter_api_init() { //elgg_extend_view('metatags', 'twitter_api/metatags'); elgg_extend_view('css/elgg', 'twitter_api/css'); elgg_extend_view('css/admin', 'twitter_api/css'); + elgg_extend_view('js/elgg', 'twitter_api/js'); // sign on with twitter if (twitter_api_allow_sign_on_with_twitter()) { @@ -60,7 +61,7 @@ function twitter_api_pagehandler_deprecated($page) { * Serves pages for twitter. * * @param array $page - * @return void + * @return bool */ function twitter_api_pagehandler($page) { if (!isset($page[0])) { @@ -131,14 +132,15 @@ function twitter_api_tweet($hook, $type, $returnvalue, $params) { // send tweet $api = new TwitterOAuth($consumer_key, $consumer_secret, $access_key, $access_secret); - $response = $api->post('statuses/update', array('status' => $params['message'])); + $api->post('statuses/update', array('status' => $params['message'])); } /** * Get tweets for a user. * - * @param int $user_id The Elgg user GUID + * @param int $user_guid The Elgg user GUID * @param array $options + * @return array */ function twitter_api_fetch_tweets($user_guid, $options = array()) { // check admin settings @@ -167,6 +169,7 @@ function twitter_api_fetch_tweets($user_guid, $options = array()) { * @param string $type * @param array $return_value * @param array $params + * @return array */ function twitter_api_public_pages($hook, $type, $return_value, $params) { $return_value[] = 'twitter_api/forward'; diff --git a/mod/twitter_api/views/default/twitter_api/css.php b/mod/twitter_api/views/default/twitter_api/css.php index 04bbed668..2d081d361 100644 --- a/mod/twitter_api/views/default/twitter_api/css.php +++ b/mod/twitter_api/views/default/twitter_api/css.php @@ -4,7 +4,7 @@ */ ?> -#login_with_twitter { +.login_with_twitter { padding: 10px 0 0 0; } diff --git a/mod/twitter_api/views/default/twitter_api/js.php b/mod/twitter_api/views/default/twitter_api/js.php new file mode 100644 index 000000000..3d2905a44 --- /dev/null +++ b/mod/twitter_api/views/default/twitter_api/js.php @@ -0,0 +1,16 @@ +<?php if (0): ?><script><?php endif; ?> + +// add ?persistent to login link +elgg.register_hook_handler('init', 'system', function() { + $('form.elgg-form-login').each(function () { + var link = $('.login_with_twitter a', this).get(0), + $input = $('input[name="persistent"]', this); + function sync() { + link.href = link.href.replace(/\?.*/, '') + ($input[0].checked ? '?persistent' : ''); + } + if (link && $input.length) { + sync(); + $input.change(sync); + } + }); +}); diff --git a/mod/twitter_api/views/default/twitter_api/login.php b/mod/twitter_api/views/default/twitter_api/login.php index 17bd76d56..7b4b4ecb1 100644 --- a/mod/twitter_api/views/default/twitter_api/login.php +++ b/mod/twitter_api/views/default/twitter_api/login.php @@ -7,7 +7,7 @@ $url = elgg_get_site_url() . 'twitter_api/forward'; $img_url = elgg_get_site_url() . 'mod/twitter_api/graphics/sign-in-with-twitter-d.png'; $login = <<<__HTML -<div id="login_with_twitter"> +<div class="login_with_twitter"> <a href="$url"> <img src="$img_url" alt="Twitter" /> </a> diff --git a/mod/uservalidationbyemail/views/default/forms/uservalidationbyemail/bulk_action.php b/mod/uservalidationbyemail/views/default/forms/uservalidationbyemail/bulk_action.php index cbd13a709..9199922d6 100644 --- a/mod/uservalidationbyemail/views/default/forms/uservalidationbyemail/bulk_action.php +++ b/mod/uservalidationbyemail/views/default/forms/uservalidationbyemail/bulk_action.php @@ -27,7 +27,7 @@ if (!$count) { access_show_hidden_entities($hidden_entities); elgg_set_ignore_access($ia); - echo autop(elgg_echo('uservalidationbyemail:admin:no_unvalidated_users')); + echo elgg_autop(elgg_echo('uservalidationbyemail:admin:no_unvalidated_users')); return TRUE; } diff --git a/upgrade.php b/upgrade.php index 60764ba93..c5f158c61 100644 --- a/upgrade.php +++ b/upgrade.php @@ -9,6 +9,8 @@ * new version of the script. Deleting the script is not a requirement and * leaving it behind does not affect the security of the site. * + * Upgrades use a table {db_prefix}upgrade_lock as a mutex to prevent concurrent upgrades. + * * @package Elgg.Core * @subpackage Upgrade */ @@ -20,6 +22,12 @@ define('UPGRADING', 'upgrading'); require_once(dirname(__FILE__) . "/engine/start.php"); if (get_input('upgrade') == 'upgrade') { + // prevent someone from running the upgrade script in parallel (see #4643) + if (!_elgg_upgrade_lock()) { + register_error(elgg_echo('upgrade:locked')); + forward(); + } + // disable the system log for upgrades to avoid exceptions when the schema changes. elgg_unregister_event_handler('log', 'systemlog', 'system_log_default_logger'); elgg_unregister_event_handler('all', 'all', 'system_log_listener'); @@ -33,6 +41,9 @@ if (get_input('upgrade') == 'upgrade') { elgg_trigger_event('upgrade', 'system', null); elgg_invalidate_simplecache(); elgg_reset_system_cache(); + + _elgg_upgrade_unlock(); + } else { // if upgrading from < 1.8.0, check for the core view 'welcome' and bail if it's found. // see http://trac.elgg.org/ticket/3064 @@ -53,4 +64,4 @@ if (get_input('upgrade') == 'upgrade') { exit; } -forward();
\ No newline at end of file +forward(); diff --git a/version.php b/version.php index 77d151bb6..07a08ab4a 100644 --- a/version.php +++ b/version.php @@ -11,7 +11,7 @@ // YYYYMMDD = Elgg Date // XX = Interim incrementer -$version = 2012120500; +$version = 2013012900; // Human-friendly version name -$release = '1.8.11'; +$release = '1.8.13'; diff --git a/views/default/admin/appearance/profile_fields.php b/views/default/admin/appearance/profile_fields.php index 91d14b874..f1d78c19f 100644 --- a/views/default/admin/appearance/profile_fields.php +++ b/views/default/admin/appearance/profile_fields.php @@ -5,12 +5,20 @@ $add = elgg_view_form('profile/fields/add', array('class' => 'elgg-form-settings'), array()); $list = elgg_view('admin/appearance/profile_fields/list'); -$reset = elgg_view_form('profile/fields/reset', array(), array()); + +$reset = elgg_view('output/confirmlink', array( + 'text' => elgg_echo('reset'), + 'href' => 'action/profile/fields/reset', + 'title' => elgg_echo('profile:resetdefault'), + 'confirm' => elgg_echo('profile:resetdefault:confirm'), + 'class' => 'elgg-button elgg-button-cancel', + 'is_trusted' => 'true', +)); $body = <<<__HTML $add $list -$reset +<div class="mtl">$reset</div> __HTML; echo $body; diff --git a/views/default/annotation/generic_comment.php b/views/default/annotation/generic_comment.php index 9891510e0..22a8d9211 100644 --- a/views/default/annotation/generic_comment.php +++ b/views/default/annotation/generic_comment.php @@ -55,13 +55,13 @@ HTML; //@todo need link to actual comment! - $on = elgg_echo('on'); + $commented_on = elgg_echo('generic_comment:on', array($commenter_link, $entity_link)); $excerpt = elgg_get_excerpt($comment->value, 80); $body = <<<HTML <span class="elgg-subtext"> - $commenter_link $on $entity_link ($friendlytime): $excerpt + $commented_on ($friendlytime): $excerpt </span> HTML; diff --git a/views/default/core/settings/statistics/online.php b/views/default/core/settings/statistics/online.php index f50ad9acc..1385ff60f 100644 --- a/views/default/core/settings/statistics/online.php +++ b/views/default/core/settings/statistics/online.php @@ -8,20 +8,13 @@ $user = elgg_get_page_owner_entity(); -$logged_in = 0; -$log = get_system_log($user->guid, "login", "", 'user', '', 1); - -if ($log) { - $logged_in = $log[0]->time_created; -} - $label_name = elgg_echo('usersettings:statistics:label:name'); $label_email = elgg_echo('usersettings:statistics:label:email'); $label_member_since = elgg_echo('usersettings:statistics:label:membersince'); $label_last_login = elgg_echo('usersettings:statistics:label:lastlogin'); $time_created = date("r", $user->time_created); -$last_login = date("r", $logged_in); +$last_login = date("r", $user->last_login); $title = elgg_echo('usersettings:statistics:yourdetails'); diff --git a/views/default/css/elements/layout.php b/views/default/css/elements/layout.php index 25a2bffb7..9d92752b4 100644 --- a/views/default/css/elements/layout.php +++ b/views/default/css/elements/layout.php @@ -118,4 +118,4 @@ } .elgg-page-footer a:hover { color: #666; -}
\ No newline at end of file +} diff --git a/views/default/css/elements/modules.php b/views/default/css/elements/modules.php index 74092c774..a37ae094b 100644 --- a/views/default/css/elements/modules.php +++ b/views/default/css/elements/modules.php @@ -191,4 +191,4 @@ a.elgg-widget-collapsed:before { .elgg-widget-placeholder { border: 2px dashed #dedede; margin-bottom: 15px; -}
\ No newline at end of file +} diff --git a/views/default/css/elements/typography.php b/views/default/css/elements/typography.php index d93b28d2c..c044cb1cc 100644 --- a/views/default/css/elements/typography.php +++ b/views/default/css/elements/typography.php @@ -158,4 +158,5 @@ h6 { font-size: 0.8em; } } .elgg-output img { max-width: 100%; -}
\ No newline at end of file + height: auto; +} diff --git a/views/default/forms/profile/fields/add.php b/views/default/forms/profile/fields/add.php index 1ea9c57a9..2087ec299 100644 --- a/views/default/forms/profile/fields/add.php +++ b/views/default/forms/profile/fields/add.php @@ -25,5 +25,5 @@ $formbody = <<< END $submit_control</div> END; -echo autop(elgg_echo('profile:explainchangefields')); +echo elgg_autop(elgg_echo('profile:explainchangefields')); echo $formbody; diff --git a/views/default/forms/profile/fields/reset.php b/views/default/forms/profile/fields/reset.php deleted file mode 100644 index c0bb1b7f4..000000000 --- a/views/default/forms/profile/fields/reset.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * Reset profile fields form - */ - -echo '<div class="elgg-foot">'; -$params = array( - 'value' => elgg_echo('profile:resetdefault'), - 'class' => 'elgg-button-cancel', -); -echo elgg_view('input/submit', $params); -echo '</div>'; diff --git a/views/default/forms/user/passwordreset.php b/views/default/forms/user/passwordreset.php index 3c89776f6..5946fa7c0 100644 --- a/views/default/forms/user/passwordreset.php +++ b/views/default/forms/user/passwordreset.php @@ -3,7 +3,7 @@ * Reset user password form */ -echo autop(elgg_echo('user:resetpassword:reset_password_confirm')); +echo elgg_autop(elgg_echo('user:resetpassword:reset_password_confirm')); echo elgg_view('input/hidden', array( 'name' => 'u', diff --git a/views/default/js/elgg.php b/views/default/js/elgg.php index b82d98ce4..6fe03484d 100644 --- a/views/default/js/elgg.php +++ b/views/default/js/elgg.php @@ -56,7 +56,8 @@ if (0) { ?><script><?php } elgg.version = '<?php echo get_version(); ?>'; elgg.release = '<?php echo get_version(true); ?>'; elgg.config.wwwroot = '<?php echo elgg_get_site_url(); ?>'; -elgg.security.interval = 5 * 60 * 1000; <?php //@todo make this configurable ?> +<?php //@todo make this configurable ?> +elgg.security.interval = 5 * 60 * 1000; elgg.config.domReady = false; elgg.config.language = '<?php echo isset($CONFIG->language) ? $CONFIG->language : 'en'; ?>'; elgg.config.languageReady = false; diff --git a/views/default/js/lightbox.php b/views/default/js/lightbox.php index d2bceaf90..a1f018eea 100644 --- a/views/default/js/lightbox.php +++ b/views/default/js/lightbox.php @@ -3,7 +3,8 @@ * Elgg lightbox * * Usage - * Apply the class elgg-lightbox to links. + * Call elgg_load_js('lightbox') and elgg_load_css('lightbox') then + * apply the class elgg-lightbox to links. * * Advanced Usage * Elgg is distributed with the Fancybox jQuery library. Please go to diff --git a/views/default/output/longtext.php b/views/default/output/longtext.php index 200f27de5..589100c4f 100644 --- a/views/default/output/longtext.php +++ b/views/default/output/longtext.php @@ -31,7 +31,7 @@ if ($parse_urls) { $text = filter_tags($text); -$text = autop($text); +$text = elgg_autop($text); $attributes = elgg_format_attributes($vars); diff --git a/views/default/page/components/list.php b/views/default/page/components/list.php index 0cf7d507c..28ed58ddf 100644 --- a/views/default/page/components/list.php +++ b/views/default/page/components/list.php @@ -51,14 +51,15 @@ if ($pagination && $count) { if (is_array($items) && count($items) > 0) { $html .= "<ul class=\"$list_class\">"; foreach ($items as $item) { - if (elgg_instanceof($item)) { - $id = "elgg-{$item->getType()}-{$item->getGUID()}"; - } else { - $id = "item-{$item->getType()}-{$item->id}"; + $li = elgg_view_list_item($item, $vars); + if ($li) { + if (elgg_instanceof($item)) { + $id = "elgg-{$item->getType()}-{$item->getGUID()}"; + } else { + $id = "item-{$item->getType()}-{$item->id}"; + } + $html .= "<li id=\"$id\" class=\"$item_class\">$li</li>"; } - $html .= "<li id=\"$id\" class=\"$item_class\">"; - $html .= elgg_view_list_item($item, $vars); - $html .= '</li>'; } $html .= '</ul>'; } diff --git a/views/default/page/elements/messages.php b/views/default/page/elements/messages.php index a35a48586..edd40d71e 100644 --- a/views/default/page/elements/messages.php +++ b/views/default/page/elements/messages.php @@ -18,7 +18,7 @@ if (isset($vars['object']) && is_array($vars['object']) && sizeof($vars['object' foreach ($vars['object'] as $type => $list ) { foreach ($list as $message) { echo "<li class=\"elgg-message elgg-state-$type\">"; - echo autop($message); + echo elgg_autop($message); echo '</li>'; } } diff --git a/views/default/river/elements/image.php b/views/default/river/elements/image.php index 9caa44b36..6f6aeae65 100644 --- a/views/default/river/elements/image.php +++ b/views/default/river/elements/image.php @@ -9,4 +9,8 @@ $subject = $vars['item']->getSubjectEntity(); -echo elgg_view_entity_icon($subject, 'small'); +if (elgg_in_context('widgets')) { + echo elgg_view_entity_icon($subject, 'tiny'); +} else { + echo elgg_view_entity_icon($subject, 'small'); +} diff --git a/views/default/widgets/control_panel/content.php b/views/default/widgets/control_panel/content.php index d2db54bc6..a348d612f 100644 --- a/views/default/widgets/control_panel/content.php +++ b/views/default/widgets/control_panel/content.php @@ -11,12 +11,26 @@ elgg_register_menu_item('admin_control_panel', array( 'link_class' => 'elgg-button elgg-button-action', )); -elgg_register_menu_item('admin_control_panel', array( - 'name' => 'upgrade', - 'text' => elgg_echo('upgrade'), - 'href' => 'upgrade.php', - 'link_class' => 'elgg-button elgg-button-action', -)); +// @todo Move in this in ElggUpgradeManager::isLocked() when #4682 fixed +$is_locked = _elgg_upgrade_is_locked(); + +if (!$is_locked) { + elgg_register_menu_item('admin_control_panel', array( + 'name' => 'upgrade', + 'text' => elgg_echo('upgrade'), + 'href' => 'upgrade.php', + 'link_class' => 'elgg-button elgg-button-action', + )); +} else { + elgg_register_menu_item('admin_control_panel', array( + 'name' => 'unlock_upgrade', + 'text' => elgg_echo('upgrade:unlock'), + 'href' => 'action/admin/site/unlock_upgrade', + 'is_action' => true, + 'link_class' => 'elgg-button elgg-button-action', + 'confirm' => elgg_echo('upgrade:unlock:confirm'), + )); +} echo elgg_view_menu('admin_control_panel', array( 'class' => 'elgg-menu-hz', diff --git a/views/installation/install/js_rewrite_check.php b/views/installation/install/js_rewrite_check.php new file mode 100644 index 000000000..04d81171d --- /dev/null +++ b/views/installation/install/js_rewrite_check.php @@ -0,0 +1,12 @@ +<?php +/** + * Some servers don't allow PHP to check the rewrite, so try via AJAX + */ +?> +<script type="text/javascript"> + elgg.installer.rewriteTest( + '<?php echo $vars['url'];?>', + '<?php echo elgg_echo('install:check:rewrite:success'); ?>', + '<?php echo $vars['config']->wwwroot; ?>install.php?step=database' + ); +</script>
\ No newline at end of file diff --git a/views/installation/install/pages/admin.php b/views/installation/install/pages/admin.php index 9456e682f..e810aa701 100644 --- a/views/installation/install/pages/admin.php +++ b/views/installation/install/pages/admin.php @@ -3,7 +3,7 @@ * Install create admin account page */ -echo autop(elgg_echo('install:admin:instructions')); +echo elgg_autop(elgg_echo('install:admin:instructions')); $vars['type'] = 'admin'; diff --git a/views/installation/install/pages/complete.php b/views/installation/install/pages/complete.php index 2f5a04854..80f8e7434 100644 --- a/views/installation/install/pages/complete.php +++ b/views/installation/install/pages/complete.php @@ -3,7 +3,7 @@ * Install completion page */ -echo autop(elgg_echo('install:complete:instructions')); +echo elgg_autop(elgg_echo('install:complete:instructions')); ?> diff --git a/views/installation/install/pages/database.php b/views/installation/install/pages/database.php index d3011c9e3..d24b4f57b 100644 --- a/views/installation/install/pages/database.php +++ b/views/installation/install/pages/database.php @@ -6,12 +6,12 @@ */ if (isset($vars['failure']) && $vars['failure']) { - echo autop(elgg_echo('install:database:error')); + echo elgg_autop(elgg_echo('install:database:error')); $vars['refresh'] = TRUE; $vars['advance'] = FALSE; echo elgg_view('install/nav', $vars); } else { - echo autop(elgg_echo('install:database:instructions')); + echo elgg_autop(elgg_echo('install:database:instructions')); $vars['type'] = 'database'; diff --git a/views/installation/install/pages/requirements.php b/views/installation/install/pages/requirements.php index e3689e761..3f0941c95 100644 --- a/views/installation/install/pages/requirements.php +++ b/views/installation/install/pages/requirements.php @@ -14,7 +14,7 @@ if ($vars['num_failures'] != 0) { $instruct_text = elgg_echo('install:requirements:instructions:success'); } -echo autop($instruct_text); +echo elgg_autop($instruct_text); $report = $vars['report']; foreach ($report as $category => $checks) { @@ -23,17 +23,17 @@ foreach ($report as $category => $checks) { echo "<ul class=\"elgg-require-$category\">"; foreach ($checks as $check) { echo "<li class=\"{$check['severity']}\">"; - echo autop($check['message']); + echo elgg_autop($check['message']); echo "</li>"; } echo "</ul>"; } -$vars['refresh'] = TRUE; +$vars['refresh'] = true; // cannot advance to next step with a failure if ($vars['num_failures'] != 0) { - $vars['advance'] = FALSE; + $vars['advance'] = false; } echo elgg_view('install/nav', $vars); diff --git a/views/installation/install/pages/settings.php b/views/installation/install/pages/settings.php index 30a1deb5a..04f23c0ea 100644 --- a/views/installation/install/pages/settings.php +++ b/views/installation/install/pages/settings.php @@ -1,6 +1,6 @@ <?php -echo autop(elgg_echo('install:settings:instructions')); +echo elgg_autop(elgg_echo('install:settings:instructions')); $vars['type'] = 'settings'; diff --git a/views/installation/install/pages/welcome.php b/views/installation/install/pages/welcome.php index f069e4ba7..f370c15f3 100644 --- a/views/installation/install/pages/welcome.php +++ b/views/installation/install/pages/welcome.php @@ -3,6 +3,6 @@ * Install welcome page */ -echo autop(elgg_echo('install:welcome:instructions')); +echo elgg_autop(elgg_echo('install:welcome:instructions')); echo elgg_view('install/nav', $vars); diff --git a/views/installation/page/elements/messages.php b/views/installation/page/elements/messages.php index 2a06a7b1e..46261dca4 100644 --- a/views/installation/page/elements/messages.php +++ b/views/installation/page/elements/messages.php @@ -12,7 +12,7 @@ if (isset($vars['object']) && is_array($vars['object']) && sizeof($vars['object' foreach ($vars['object'] as $type => $list ) { foreach ($list as $message) { echo "<li class=\"elgg-state-$type\">"; - echo autop($message); + echo elgg_autop($message); echo '</li>'; } } diff --git a/views/opendd/messages/exceptions/exception.php b/views/opendd/messages/exceptions/exception.php index 54868f1f4..dc0f48a8d 100644 --- a/views/opendd/messages/exceptions/exception.php +++ b/views/opendd/messages/exceptions/exception.php @@ -11,7 +11,7 @@ ?> <!-- -<?php echo get_class($vars['object']); ?>: <?php echo autop($vars['object']->getMessage()); ?> +<?php echo get_class($vars['object']); ?>: <?php echo elgg_autop($vars['object']->getMessage()); ?> <?php if (elgg_get_config('debug')) { ?> <?php echo print_r($vars['object'], true); diff --git a/views/rss/group/default.php b/views/rss/group/default.php index f57c7f82c..7fef4d434 100644 --- a/views/rss/group/default.php +++ b/views/rss/group/default.php @@ -11,9 +11,9 @@ $pubdate = date('r', $vars['entity']->getTimeCreated()); $title = htmlspecialchars($vars['entity']->name, ENT_NOQUOTES, 'UTF-8'); if ($vars['entity']->description) { - $description = autop($vars['entity']->description); + $description = elgg_autop($vars['entity']->description); } elseif ($vars['entity']->briefdescription) { - $description = autop($vars['entity']->briefdescription); + $description = elgg_autop($vars['entity']->briefdescription); } else { $description = ''; } diff --git a/views/rss/object/default.php b/views/rss/object/default.php index be8025953..8c7d5d8e0 100644 --- a/views/rss/object/default.php +++ b/views/rss/object/default.php @@ -15,7 +15,7 @@ if (empty($title)) { $permalink = htmlspecialchars($vars['entity']->getURL(), ENT_NOQUOTES, 'UTF-8'); $pubdate = date('r', $vars['entity']->getTimeCreated()); -$description = autop($vars['entity']->description); +$description = elgg_autop($vars['entity']->description); $creator = elgg_view('page/components/creator', $vars); $georss = elgg_view('page/components/georss', $vars); diff --git a/views/rss/user/default.php b/views/rss/user/default.php index 1c7bf75e7..92c9427b2 100644 --- a/views/rss/user/default.php +++ b/views/rss/user/default.php @@ -11,7 +11,7 @@ $pubdate = date('r', $vars['entity']->getTimeCreated()); $title = htmlspecialchars($vars['entity']->name, ENT_NOQUOTES, 'UTF-8'); if ($vars['entity']->description) { - $description = autop($vars['entity']->description); + $description = elgg_autop($vars['entity']->description); } else { $description = ''; } diff --git a/views/xml/messages/exceptions/exception.php b/views/xml/messages/exceptions/exception.php index 3e4e1c376..66a0f2b96 100644 --- a/views/xml/messages/exceptions/exception.php +++ b/views/xml/messages/exceptions/exception.php @@ -11,7 +11,7 @@ ?> <!-- -<?php echo get_class($vars['object']); ?>: <?php echo autop($vars['object']->getMessage()); ?> +<?php echo get_class($vars['object']); ?>: <?php echo elgg_autop($vars['object']->getMessage()); ?> <?php if (elgg_get_config('debug')) { ?> |