diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c859f028d052a1e7d4573009b9326051d4ba9ef8..33cf9e20c09b1028d2cc3f8551a6a74d4d08d30f 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,27 @@ +Drupal 7.7, 2011-07-27 +---------------------- +- Fixed VERSION string. + +Drupal 7.6, 2011-07-27 +---------------------- +- Fixed support for remote streamwrappers. +- AJAX now binds to 'click' instead of 'mousedown'. +- 'Translatable' flag on fields created in UI now defaults to FALSE, to match those created via the API. +- Performance enhancement to permissions page on large numbers of permissions. +- More secure password generation. +- Fix for temporary directory on Windows servers. +- run-tests.sh now uses proc_open() instead of pcntl_fork() for better Windows support. +- Numerous upgrade path fixes. +- Numerous documentation fixes. +- Numerous notice fixes. +- Numerous fixes to improve PHP 5.4 support. +- Numerous RTL improvements. + +Drupal 7.5, 2011-07-27 +---------------------- +- Fixed security issue (Access bypass), see SA-CORE-2011-003. + Drupal 7.4, 2011-06-29 ---------------------- - Rolled back patch that caused fatal errors in CTools, Feeds, and other modules using the class registry. diff --git a/includes/ajax.inc b/includes/ajax.inc index 41c69832a8e072b5c6005c83da86d370c1fdac1c..d70808efe09f320b10b445323f295fddfddb9631 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -143,6 +143,21 @@ * - #ajax['event']: The JavaScript event to respond to. This is normally * selected automatically for the type of form widget being used, and * is only needed if you need to override the default behavior. + * - #ajax['prevent']: A JavaScript event to prevent when 'event' is triggered. + * Defaults to 'click' for #ajax on #type 'submit', 'button', and + * 'image_button'. Multiple events may be specified separated by spaces. + * For example, when binding #ajax behaviors to form buttons, pressing the + * ENTER key within a textfield triggers the 'click' event of the form's first + * submit button. Triggering Ajax in this situation leads to problems, like + * breaking autocomplete textfields. Because of that, Ajax behaviors are bound + * to the 'mousedown' event on form buttons by default. However, binding to + * 'mousedown' rather than 'click' means that it is possible to trigger a + * click by pressing the mouse, holding the mouse button down until the Ajax + * request is complete and the button is re-enabled, and then releasing the + * mouse button. For this case, 'prevent' can be set to 'click', so an + * additional event handler is bound to prevent such a click from triggering a + * non-Ajax form submission. This also prevents a textfield's ENTER press + * triggering a button's non-Ajax form submission behavior. * - #ajax['method']: The jQuery method to use to place the new HTML. * Defaults to 'replaceWith'. May be: 'replaceWith', 'append', 'prepend', * 'before', 'after', or 'html'. See the @@ -591,6 +606,7 @@ function ajax_process_form($element, &$form_state) { * An associative array containing the properties of the element. * Properties used: * - #ajax['event'] + * - #ajax['prevent'] * - #ajax['path'] * - #ajax['options'] * - #ajax['wrapper'] @@ -619,13 +635,26 @@ function ajax_pre_render_element($element) { case 'submit': case 'button': case 'image_button': - // Use the mousedown instead of the click event because form - // submission via pressing the enter key triggers a click event on - // submit inputs, inappropriately triggering Ajax behaviors. + // Pressing the ENTER key within a textfield triggers the click event of + // the form's first submit button. Triggering Ajax in this situation + // leads to problems, like breaking autocomplete textfields, so we bind + // to mousedown instead of click. + // @see http://drupal.org/node/216059 $element['#ajax']['event'] = 'mousedown'; - // Attach an additional event handler so that Ajax behaviors - // can be triggered still via keyboard input. + // Retain keyboard accessibility by setting 'keypress'. This causes + // ajax.js to trigger 'event' when SPACE or ENTER are pressed while the + // button has focus. $element['#ajax']['keypress'] = TRUE; + // Binding to mousedown rather than click means that it is possible to + // trigger a click by pressing the mouse, holding the mouse button down + // until the Ajax request is complete and the button is re-enabled, and + // then releasing the mouse button. Set 'prevent' so that ajax.js binds + // an additional handler to prevent such a click from triggering a + // non-Ajax form submission. This also prevents a textfield's ENTER + // press triggering this button's non-Ajax form submission behavior. + if (!isset($element['#ajax']['prevent'])) { + $element['#ajax']['prevent'] = 'click'; + } break; case 'password': diff --git a/includes/authorize.inc b/includes/authorize.inc index 3617d7d03051c30fa919220976e3f80463637d17..852860413101f1183d0043a5dc73dd7c6c603b2e 100644 --- a/includes/authorize.inc +++ b/includes/authorize.inc @@ -193,7 +193,7 @@ function _authorize_filetransfer_connection_settings_set_defaults(&$element, $ke function authorize_filetransfer_form_validate($form, &$form_state) { // Only validate the form if we have collected all of the user input and are // ready to proceed with updating or installing. - if ($form_state['clicked_button']['#name'] != 'process_updates') { + if ($form_state['triggering_element']['#name'] != 'process_updates') { return; } @@ -224,7 +224,7 @@ function authorize_filetransfer_form_validate($form, &$form_state) { */ function authorize_filetransfer_form_submit($form, &$form_state) { global $base_url; - switch ($form_state['clicked_button']['#name']) { + switch ($form_state['triggering_element']['#name']) { case 'process_updates': // Save the connection settings to the DB. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index bb07cca471748da550d2e3f471685795b6d696f2..d65108627d8fc7964caedf60a39bed5ab2ba1841 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.4'); +define('VERSION', '7.7'); /** * Core API compatibility. @@ -38,93 +38,69 @@ define('CACHE_PERMANENT', 0); define('CACHE_TEMPORARY', -1); /** - * Log message severity -- Emergency: system is unusable. + * @defgroup logging_severity_levels Logging severity levels + * @{ + * Logging severity levels as defined in RFC 3164. * * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * + * defined in RFC 3164, section 4.1.1. PHP supplies predefined LOG_* constants + * for use in the syslog() function, but their values on Windows builds do not + * correspond to RFC 3164. The associated PHP bug report was closed with the + * comment, "And it's also not a bug, as Windows just have less log levels," + * and "So the behavior you're seeing is perfectly normal." + * + * @see http://www.faqs.org/rfcs/rfc3164.html + * @see http://bugs.php.net/bug.php?id=18090 + * @see http://php.net/manual/function.syslog.php + * @see http://php.net/manual/network.constants.php * @see watchdog() * @see watchdog_severity_levels() */ + +/** + * Log message severity -- Emergency: system is unusable. + */ define('WATCHDOG_EMERGENCY', 0); /** * Log message severity -- Alert: action must be taken immediately. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_ALERT', 1); /** * Log message severity -- Critical: critical conditions. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_CRITICAL', 2); /** * Log message severity -- Error: error conditions. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_ERROR', 3); /** * Log message severity -- Warning: warning conditions. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_WARNING', 4); /** * Log message severity -- Notice: normal but significant condition. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_NOTICE', 5); /** * Log message severity -- Informational: informational messages. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_INFO', 6); /** * Log message severity -- Debug: debug-level messages. - * - * The WATCHDOG_* constant definitions correspond to the logging severity levels - * defined in RFC 3164, section 4.1.1: http://www.faqs.org/rfcs/rfc3164.html - * - * @see watchdog() - * @see watchdog_severity_levels() */ define('WATCHDOG_DEBUG', 7); +/** + * @} End of "defgroup logging_severity_levels". + */ + /** * First bootstrap phase: initialize configuration. */ @@ -216,8 +192,11 @@ define('LANGUAGE_RTL', 1); /** * For convenience, define a short form of the request time global. + * + * REQUEST_TIME is a float with microseconds since PHP 5.4.0, but float + * timestamps confuses most of the PHP functions (including date_create()). */ -define('REQUEST_TIME', $_SERVER['REQUEST_TIME']); +define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']); /** * Flag for drupal_set_title(); text is not sanitized, so run check_plain(). @@ -311,31 +290,30 @@ function timer_stop($name) { } /** - * Find the appropriate configuration directory. + * Finds the appropriate configuration directory. * - * Try finding a matching configuration directory by stripping the website's + * Finds a matching configuration directory by stripping the website's * hostname from left to right and pathname from right to left. The first - * configuration file found will be used; the remaining will ignored. If no - * configuration file is found, return a default value '$confdir/default'. + * configuration file found will be used and the remaining ones will be ignored. + * If no configuration file is found, return a default value '$confdir/default'. * - * Example for a fictitious site installed at - * http://www.drupal.org:8080/mysite/test/ the 'settings.php' is searched in - * the following directories: + * With a site located at http://www.example.com:8080/mysite/test/, the file, + * settings.php, is searched for in the following directories: * - * 1. $confdir/8080.www.drupal.org.mysite.test - * 2. $confdir/www.drupal.org.mysite.test - * 3. $confdir/drupal.org.mysite.test - * 4. $confdir/org.mysite.test + * 1. $confdir/8080.www.example.com.mysite.test + * 2. $confdir/www.example.com.mysite.test + * 3. $confdir/example.com.mysite.test + * 4. $confdir/com.mysite.test * - * 5. $confdir/8080.www.drupal.org.mysite - * 6. $confdir/www.drupal.org.mysite - * 7. $confdir/drupal.org.mysite - * 8. $confdir/org.mysite + * 5. $confdir/8080.www.example.com.mysite + * 6. $confdir/www.example.com.mysite + * 7. $confdir/example.com.mysite + * 8. $confdir/com.mysite * - * 9. $confdir/8080.www.drupal.org - * 10. $confdir/www.drupal.org - * 11. $confdir/drupal.org - * 12. $confdir/org + * 9. $confdir/8080.www.example.com + * 10. $confdir/www.example.com + * 11. $confdir/example.com + * 12. $confdir/com * * 13. $confdir/default * @@ -343,18 +321,18 @@ function timer_stop($name) { * prior to scanning for directories. It should define an associative array * named $sites, which maps domains to directories. It should be in the form * of: - * + * @code * $sites = array( * 'The url to alias' => 'A directory within the sites directory' * ); - * + * @endcode * For example: - * + * @code * $sites = array( * 'devexample.com' => 'example.com', * 'localhost.example' => 'example.com', * ); - * + * @endcode * The above array will cause Drupal to look for a directory named * "example.com" in the sites directory whenever a request comes from * "example.com", "devexample.com", or "localhost/example". That is useful @@ -363,14 +341,15 @@ function timer_stop($name) { * (files, system table, etc.) this will ensure the paths are correct while * accessed on development servers. * - * @param $require_settings + * @param bool $require_settings * Only configuration directories with an existing settings.php file * will be recognized. Defaults to TRUE. During initial installation, * this is set to FALSE so that Drupal can detect a matching directory, * then create a new settings.php file in it. - * @param reset + * @param bool $reset * Force a full search for matching directories even if one had been - * found previously. + * found previously. Defaults to FALSE. + * * @return * The path of the matching directory. */ diff --git a/includes/common.inc b/includes/common.inc index a3c77ef948de707aafcd60734b1440cd8d83d8c5..7b0b9e7618d109e1aaea49a75151b2963f614e80 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2258,7 +2258,7 @@ function drupal_http_header_attributes(array $attributes = array()) { * An associative array of key-value pairs to be converted to attributes. * * @return - * A string ready for insertion in a tag. + * A string ready for insertion in a tag (starts with a space). * * @ingroup sanitization */ @@ -2294,7 +2294,9 @@ function drupal_attributes(array $attributes = array()) { * to work in a call to drupal_attributes($options['attributes']). * - 'html' (default FALSE): Whether $text is HTML or just plain-text. For * example, to make an image tag into a link, this must be set to TRUE, or - * you will see the escaped HTML image tag. + * you will see the escaped HTML image tag. $text is not sanitized if + * 'html' is TRUE. The calling function must ensure that $text is already + * safe. * - 'language': An optional language object. If the path being linked to is * internal to the site, $options['language'] is used to determine whether * the link is "active", or pointing to the current page (the language as @@ -7050,6 +7052,7 @@ function drupal_parse_info_format($data) { * Array of the possible severity levels for log messages. * * @see watchdog() + * @ingroup logging_severity_levels */ function watchdog_severity_levels() { return array( diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc index bc31feaafea1837582a87cbaa0873f7716117b27..157cbfa567ebd05f484caa7ea65fd51866099d5b 100644 --- a/includes/database/mysql/database.inc +++ b/includes/database/mysql/database.inc @@ -169,10 +169,8 @@ class DatabaseConnection_mysql extends DatabaseConnection { // savepoints which no longer exist. // // To avoid exceptions when no actual error has occurred, we silently - // succeed for PDOExceptions with SQLSTATE 42000 ("Syntax error or - // access rule violation") and MySQL error code 1305 ("SAVEPOINT does - // not exist"). - if ($e->getCode() == '42000' && $e->errorInfo[1] == '1305') { + // succeed for MySQL error code 1305 ("SAVEPOINT does not exist"). + if ($e->errorInfo[1] == '1305') { // If one SAVEPOINT was released automatically, then all were. // Therefore, we keep just the topmost transaction. $this->transactionLayers = array('drupal_transaction'); diff --git a/includes/entity.inc b/includes/entity.inc index 9ee7889cfb7ca439e77cfdb44282b68e19584a0a..f363c31137248e7f413e96ebe6970d8bd7d83885 100644 --- a/includes/entity.inc +++ b/includes/entity.inc @@ -457,6 +457,21 @@ class EntityFieldQuery { */ public $fieldConditions = array(); + /** + * List of field meta conditions (language and delta). + * + * Field conditions operate on columns specified by hook_field_schema(), + * the meta conditions operate on columns added by the system: delta + * and language. These can not be mixed with the field conditions because + * field columns can have any name including delta and language. + * + * @var array + * + * @see EntityFieldQuery::fieldLanguageCondition() + * @see EntityFieldQuery::fielDeltaCondition() + */ + public $fieldMetaConditions = array(); + /** * List of property conditions. * @@ -613,6 +628,90 @@ class EntityFieldQuery { /** * Adds a condition on field values. * + * @param $type + * The condition array the given conditions should be added to. + * @param $field + * Either a field name or a field array. + * @param $column + * The column that should hold the value to be matched. + * @param $value + * The value to test the column value against. + * @param $operator + * The operator to be used to test the given value. + * @param $delta_group + * An arbitrary identifier: conditions in the same group must have the same + * $delta_group. + * @param $language_group + * An arbitrary identifier: conditions in the same group must have the same + * $language_group. + * + * @return EntityFieldQuery + * The called object. + * + * @see EntityFieldQuery::addFieldCondition + * @see EntityFieldQuery::deleted + */ + public function fieldCondition($field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { + return $this->addFieldCondition($this->fieldConditions, $field, $column, $value, $operator, $delta_group, $language_group); + } + + /** + * Adds a condition on the field language column. + * + * @param $field + * Either a field name or a field array. + * @param $value + * The value to test the column value against. + * @param $operator + * The operator to be used to test the given value. + * @param $delta_group + * An arbitrary identifier: conditions in the same group must have the same + * $delta_group. + * @param $language_group + * An arbitrary identifier: conditions in the same group must have the same + * $language_group. + * + * @return EntityFieldQuery + * The called object. + * + * @see EntityFieldQuery::addFieldCondition + * @see EntityFieldQuery::deleted + */ + public function fieldLanguageCondition($field, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { + return $this->addFieldCondition($this->fieldMetaConditions, $field, 'language', $value, $operator, $delta_group, $language_group); + } + + /** + * Adds a condition on the field delta column. + * + * @param $field + * Either a field name or a field array. + * @param $value + * The value to test the column value against. + * @param $operator + * The operator to be used to test the given value. + * @param $delta_group + * An arbitrary identifier: conditions in the same group must have the same + * $delta_group. + * @param $language_group + * An arbitrary identifier: conditions in the same group must have the same + * $language_group. + * + * @return EntityFieldQuery + * The called object. + * + * @see EntityFieldQuery::addFieldCondition + * @see EntityFieldQuery::deleted + */ + public function fieldDeltaCondition($field, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { + return $this->addFieldCondition($this->fieldMetaConditions, $field, 'delta', $value, $operator, $delta_group, $language_group); + } + + /** + * Adds the given condition to the proper condition array. + * + * @param $conditions + * A reference to an array of conditions. * @param $field * Either a field name or a field array. * @param $column @@ -649,7 +748,7 @@ class EntityFieldQuery { * @return EntityFieldQuery * The called object. */ - public function fieldCondition($field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { + protected function addFieldCondition(&$conditions, $field, $column = NULL, $value = NULL, $operator = NULL, $delta_group = NULL, $language_group = NULL) { if (is_scalar($field)) { $field_definition = field_info_field($field); if (empty($field_definition)) { @@ -657,11 +756,11 @@ class EntityFieldQuery { } $field = $field_definition; } - // Ensure the same index is used for fieldConditions as for fields. + // Ensure the same index is used for field conditions as for fields. $index = count($this->fields); $this->fields[$index] = $field; if (isset($column)) { - $this->fieldConditions[$index] = array( + $conditions[$index] = array( 'field' => $field, 'column' => $column, 'value' => $value, diff --git a/includes/errors.inc b/includes/errors.inc index be72428560fb2f9c0286bb7a4a76fdbd115b0bb8..bd31bebed10e9be28843ac51a350200247fc9eb1 100644 --- a/includes/errors.inc +++ b/includes/errors.inc @@ -24,6 +24,8 @@ define('ERROR_REPORTING_DISPLAY_ALL', 2); * Map PHP error constants to watchdog severity levels. * The error constants are documented at * http://php.net/manual/en/errorfunc.constants.php + * + * @ingroup logging_severity_levels */ function drupal_error_levels() { $types = array( diff --git a/includes/file.inc b/includes/file.inc index 73e75cd4f6bef3e4cd55452d2ac23d390bd8f0e6..19420ca37e1edbedebd53f19ab132414e984104e 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -755,7 +755,12 @@ function file_usage_delete(stdClass $file, $module, $type = NULL, $id = NULL, $c */ function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { if (!file_valid_uri($destination)) { - watchdog('file', 'File %file (%realpath) could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => drupal_realpath($source->uri), '%destination' => $destination)); + if (($realpath = drupal_realpath($source->uri)) !== FALSE) { + watchdog('file', 'File %file (%realpath) could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => $realpath, '%destination' => $destination)); + } + else { + watchdog('file', 'File %file could not be copied, because the destination %destination is invalid. This is often caused by improper use of file_copy() or a missing stream wrapper.', array('%file' => $source->uri, '%destination' => $destination)); + } drupal_set_message(t('The specified file %file could not be copied, because the destination is invalid. More information is available in the system log.', array('%file' => $source->uri)), 'error'); return FALSE; } @@ -847,11 +852,15 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST $original_destination = $destination; // Assert that the source file actually exists. - $source = drupal_realpath($source); if (!file_exists($source)) { // @todo Replace drupal_set_message() calls with exceptions instead. drupal_set_message(t('The specified file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $original_source)), 'error'); - watchdog('file', 'File %file (%realpath) could not be copied because it does not exist.', array('%file' => $original_source, '%realpath' => drupal_realpath($original_source))); + if (($realpath = drupal_realpath($original_source)) !== FALSE) { + watchdog('file', 'File %file (%realpath) could not be copied because it does not exist.', array('%file' => $original_source, '%realpath' => $realpath)); + } + else { + watchdog('file', 'File %file could not be copied because it does not exist.', array('%file' => $original_source)); + } return FALSE; } @@ -871,7 +880,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST $dirname = drupal_dirname($destination); if (!file_prepare_directory($dirname)) { // The destination is not valid. - watchdog('file', 'File %file could not be copied, because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => drupal_realpath($dirname))); + watchdog('file', 'File %file could not be copied, because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => $dirname)); drupal_set_message(t('The specified file %file could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', array('%file' => $original_source)), 'error'); return FALSE; } @@ -881,12 +890,14 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST $destination = file_destination($destination, $replace); if ($destination === FALSE) { drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error'); - watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => drupal_realpath($destination))); + watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%destination' => $destination)); return FALSE; } // Assert that the source and destination filenames are not the same. - if (drupal_realpath($source) == drupal_realpath($destination)) { + $real_source = drupal_realpath($source); + $real_destination = drupal_realpath($destination); + if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) { drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error'); watchdog('file', 'File %file could not be copied because it would overwrite itself.', array('%file' => $source)); return FALSE; @@ -895,7 +906,7 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST file_ensure_htaccess(); // Perform the copy operation. if (!@copy($source, $destination)) { - watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => drupal_realpath($destination)), WATCHDOG_ERROR); + watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERR); return FALSE; } @@ -986,7 +997,12 @@ function file_destination($destination, $replace) { */ function file_move(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { if (!file_valid_uri($destination)) { - watchdog('file', 'File %file (%realpath) could not be moved, because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => drupal_realpath($source->uri), '%destination' => $destination)); + if (($realpath = drupal_realpath($source->uri)) !== FALSE) { + watchdog('file', 'File %file (%realpath) could not be moved, because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', array('%file' => $source->uri, '%realpath' => $realpath, '%destination' => $destination)); + } + else { + watchdog('file', 'File %file could not be moved, because the destination %destination is invalid. This may be caused by improper use of file_move() or a missing stream wrapper.', array('%file' => $source->uri, '%destination' => $destination)); + } drupal_set_message(t('The specified file %file could not be moved, because the destination is invalid. More information is available in the system log.', array('%file' => $source->uri)), 'error'); return FALSE; } @@ -1212,7 +1228,12 @@ function file_create_filename($basename, $directory) { */ function file_delete(stdClass $file, $force = FALSE) { if (!file_valid_uri($file->uri)) { - watchdog('file', 'File %file (%realpath) could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.', array('%file' => $file->uri, '%realpath' => drupal_realpath($file->uri))); + if (($realpath = drupal_realpath($file->uri)) !== FALSE) { + watchdog('file', 'File %file (%realpath) could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.', array('%file' => $file->uri, '%realpath' => $realpath)); + } + else { + watchdog('file', 'File %file could not be deleted because it is not a valid URI. This may be caused by improper use of file_delete() or a missing stream wrapper.', array('%file' => $file->uri)); + } drupal_set_message(t('The specified file %file could not be deleted, because it is not a valid URI. More information is available in the system log.', array('%file' => $file->uri)), 'error'); return FALSE; } @@ -1256,8 +1277,6 @@ function file_delete(stdClass $file, $force = FALSE) { * @see file_unmanaged_delete_recursive() */ function file_unmanaged_delete($path) { - // Resolve streamwrapper URI to local path. - $path = drupal_realpath($path); if (is_dir($path)) { watchdog('file', '%path is a directory and cannot be removed using file_unmanaged_delete().', array('%path' => $path), WATCHDOG_ERROR); return FALSE; @@ -1299,8 +1318,6 @@ function file_unmanaged_delete($path) { * @see file_unmanaged_delete() */ function file_unmanaged_delete_recursive($path) { - // Resolve streamwrapper URI to local path. - $path = drupal_realpath($path); if (is_dir($path)) { $dir = dir($path); while (($entry = $dir->read()) !== FALSE) { @@ -2331,11 +2348,9 @@ function file_directory_temp() { if (substr(PHP_OS, 0, 3) == 'WIN') { $directories[] = 'c:\\windows\\temp'; $directories[] = 'c:\\winnt\\temp'; - $path_delimiter = '\\'; } else { $directories[] = '/tmp'; - $path_delimiter = '/'; } // PHP may be able to find an alternative tmp directory. // This function exists in PHP 5 >= 5.2.1, but Drupal @@ -2352,8 +2367,14 @@ function file_directory_temp() { } if (empty($temporary_directory)) { - // If no directory has been found default to 'files/tmp' or 'files\\tmp'. - $temporary_directory = variable_get('file_public_path', conf_path() . '/files') . $path_delimiter . 'tmp'; + // If no directory has been found default to 'files/tmp'. + $temporary_directory = variable_get('file_public_path', conf_path() . '/files') . '/tmp'; + + // Windows accepts paths with either slash (/) or backslash (\), but will + // not accept a path which contains both a slash and a backslash. Since + // the 'file_public_path' variable may have either format, we sanitize + // everything to use slash which is supported on all platforms. + $temporary_directory = str_replace('\\', '/', $temporary_directory); } // Save the path of the discovered directory. variable_set('file_temporary_path', $temporary_directory); diff --git a/includes/form.inc b/includes/form.inc index 38ef41cf0bfcbfb5fab35f653c70e2940974cbf6..8ee0a5a52f94f95bdb8855e05ec9e4ffddd1559c 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -272,7 +272,8 @@ function drupal_get_form($form_id) { * form submission may be found in drupal_redirect_form(). * * @return - * The rendered form or NULL, depending upon the $form_state flags that were set. + * The rendered form. This function may also perform a redirect and hence may + * not return at all, depending upon the $form_state flags that were set. * * @see drupal_redirect_form() */ @@ -995,6 +996,8 @@ function drupal_prepare_form($form_id, &$form, &$form_state) { $form += array('#tree' => FALSE, '#parents' => array()); if (!isset($form['#validate'])) { + // Ensure that modules can rely on #validate being set. + $form['#validate'] = array(); // Check for a handler specific to $form_id. if (function_exists($form_id . '_validate')) { $form['#validate'][] = $form_id . '_validate'; @@ -1007,6 +1010,8 @@ function drupal_prepare_form($form_id, &$form, &$form_state) { } if (!isset($form['#submit'])) { + // Ensure that modules can rely on #submit being set. + $form['#submit'] = array(); // Check for a handler specific to $form_id. if (function_exists($form_id . '_submit')) { $form['#submit'][] = $form_id . '_submit'; @@ -2853,9 +2858,9 @@ function form_process_date($element) { /** * Validates the date type to stop dates like February 30, 2006. */ -function date_validate($form) { - if (!checkdate($form['#value']['month'], $form['#value']['day'], $form['#value']['year'])) { - form_error($form, t('The specified date is invalid.')); +function date_validate($element) { + if (!checkdate($element['#value']['month'], $element['#value']['day'], $element['#value']['year'])) { + form_error($element, t('The specified date is invalid.')); } } diff --git a/includes/mail.inc b/includes/mail.inc index d2febed39686c9bf3f6f7a2bf99fa1377d09f4de..7272df972e2970f1faeb0aa050ae3758fff93777 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -430,7 +430,7 @@ function drupal_html_to_text($string, $allowed_tags = NULL) { $indent[] = count($lists) ? ' "' : '>'; break; case 'li': - $indent[] = is_numeric($lists[0]) ? ' ' . $lists[0]++ . ') ' : ' * '; + $indent[] = isset($lists[0]) && is_numeric($lists[0]) ? ' ' . $lists[0]++ . ') ' : ' * '; break; case 'dd': $indent[] = ' '; @@ -509,7 +509,7 @@ function drupal_html_to_text($string, $allowed_tags = NULL) { $chunk = $casing($chunk); } // Format it and apply the current indentation. - $output .= drupal_wrap_mail($chunk, implode('', $indent)); + $output .= drupal_wrap_mail($chunk, implode('', $indent)) . MAIL_LINE_ENDINGS; // Remove non-quotation markers from indentation. $indent = array_map('_drupal_html_to_text_clean', $indent); } diff --git a/includes/menu.inc b/includes/menu.inc index cfd35c7944a1e03df1242396886e85fae1123db3..5582c452e87cc358333f56cb98365663c1e5595f 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -431,6 +431,11 @@ function menu_get_item($path = NULL, $router_item = NULL) { $router_items[$path] = $router_item; } if (!isset($router_items[$path])) { + // Rebuild if we know it's needed, or if the menu masks are missing which + // occurs rarely, likely due to a race condition of multiple rebuilds. + if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) { + menu_rebuild(); + } $original_map = arg(NULL, $path); // Since there is no limit to the length of $path, use a hash to keep it @@ -490,11 +495,6 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) { // Only continue if the site status is not set. if ($page_callback_result == MENU_SITE_ONLINE) { - // Rebuild if we know it's needed, or if the menu masks are missing which - // occurs rarely, likely due to a race condition of multiple rebuilds. - if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) { - menu_rebuild(); - } if ($router_item = menu_get_item($path)) { if ($router_item['access']) { if ($router_item['include_file']) { @@ -2696,19 +2696,15 @@ function _menu_navigation_links_rebuild($menu) { } } if ($menu_links) { + // Keep an array of processed menu links, to allow menu_link_save() to + // check this for parents instead of querying the database. + $parent_candidates = array(); // Make sure no child comes before its parent. array_multisort($sort, SORT_NUMERIC, $menu_links); - foreach ($menu_links as $item) { + foreach ($menu_links as $key => $item) { $existing_item = db_select('menu_links') - ->fields('menu_links', array( - 'mlid', - 'menu_name', - 'plid', - 'customized', - 'has_children', - 'updated', - )) + ->fields('menu_links') ->condition('link_path', $item['path']) ->condition('module', 'system') ->execute()->fetchAssoc(); @@ -2727,9 +2723,14 @@ function _menu_navigation_links_rebuild($menu) { $item['has_children'] = $existing_item['has_children']; $item['updated'] = $existing_item['updated']; } - if (!$existing_item || !$existing_item['customized']) { + if ($existing_item && $existing_item['customized']) { + $parent_candidates[$existing_item['mlid']] = $existing_item; + } + else { $item = _menu_link_build($item); - menu_link_save($item); + menu_link_save($item, $existing_item, $parent_candidates); + $parent_candidates[$item['mlid']] = $item; + unset($menu_links[$key]); } } } @@ -2927,12 +2928,17 @@ function _menu_delete_item($item, $force = FALSE) { * to insert a new link. * - plid: (optional) The mlid of the parent. * - router_path: (optional) The path of the relevant router item. + * @param $existing_item + * Optional, the current record from the {menu_links} table as an array. + * @param $parent_candidates + * Optional array of menu links keyed by mlid. Used by + * _menu_navigation_links_rebuild() only. * * @return * The mlid of the saved menu link, or FALSE if the menu link could not be * saved. */ -function menu_link_save(&$item) { +function menu_link_save(&$item, $existing_item = array(), $parent_candidates = array()) { drupal_alter('menu_link', $item); // This is the easiest way to handle the unique internal path '<front>', @@ -2951,15 +2957,20 @@ function menu_link_save(&$item) { 'customized' => 0, 'updated' => 0, ); - $existing_item = FALSE; if (isset($item['mlid'])) { - if ($existing_item = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['mlid']))->fetchAssoc()) { + if (!$existing_item) { + $existing_item = db_query('SELECT * FROM {menu_links} WHERE mlid = :mlid', array('mlid' => $item['mlid']))->fetchAssoc(); + } + if ($existing_item) { $existing_item['options'] = unserialize($existing_item['options']); } } + else { + $existing_item = FALSE; + } // Try to find a parent link. If found, assign it and derive its menu. - $parent = _menu_link_find_parent($item); + $parent = _menu_link_find_parent($item, $parent_candidates); if (!empty($parent['mlid'])) { $item['plid'] = $parent['mlid']; $item['menu_name'] = $parent['menu_name']; @@ -3093,11 +3104,13 @@ function menu_link_save(&$item) { * * @param $menu_link * A menu link. + * @param $parent_candidates + * An array of menu links keyed by mlid. * @return * A menu link structure of the possible parent or FALSE if no valid parent * has been found. */ -function _menu_link_find_parent($menu_link) { +function _menu_link_find_parent($menu_link, $parent_candidates = array()) { $parent = FALSE; // This item is explicitely top-level, skip the rest of the parenting. @@ -3119,7 +3132,12 @@ function _menu_link_find_parent($menu_link) { } foreach ($candidates as $mlid) { - $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc(); + if (isset($parent_candidates[$mlid])) { + $parent = $parent_candidates[$mlid]; + } + else { + $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc(); + } if ($parent) { return $parent; } diff --git a/includes/password.inc b/includes/password.inc index 93d34f81f373a5318ccc2e08e2f66a921cf70961..c0761da6907fc7c3723d8f5488ab8f075e699f67 100644 --- a/includes/password.inc +++ b/includes/password.inc @@ -18,7 +18,7 @@ * increase by 1 every Drupal version in order to counteract increases in the * speed and power of computers available to crack the hashes. */ -define('DRUPAL_HASH_COUNT', 14); +define('DRUPAL_HASH_COUNT', 15); /** * The minimum allowed log2 number of iterations for password stretching. diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc index 7df1f9dc6b23a8e4bc3daac7f7ddb626174be5ee..3c88f3d8f73200090107618f55c7795a5ceff54b 100644 --- a/includes/stream_wrappers.inc +++ b/includes/stream_wrappers.inc @@ -341,7 +341,11 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface * Base implementation of chmod(). */ function chmod($mode) { - return @chmod($this->getLocalPath(), $mode); + $output = @chmod($this->getLocalPath(), $mode); + // We are modifying the underlying file here, so we have to clear the stat + // cache so that PHP understands that URI has changed too. + clearstatcache(); + return $output; } /** diff --git a/misc/ajax.js b/misc/ajax.js index fb03e2b30a4ea1d2013ade6fb9f42e37a666d6d1..830c8aa1c98e0baeeff8385fbe9e486594e2f75f 100644 --- a/misc/ajax.js +++ b/misc/ajax.js @@ -182,10 +182,17 @@ Drupal.ajax = function (base, element, element_settings) { // can be triggered through keyboard input as well as e.g. a mousedown // action. if (element_settings.keypress) { - $(element_settings.element).keypress(function (event) { + $(ajax.element).keypress(function (event) { return ajax.keypressResponse(this, event); }); } + + // If necessary, prevent the browser default action of an additional event. + // For example, prevent the browser default action of a click, even if the + // AJAX behavior binds to mousedown. + if (element_settings.prevent) { + $(ajax.element).bind(element_settings.prevent, false); + } }; /** diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info index c0063fe536e8cb4bae9f0739797f0892dc13f9e9..c8330219cc4ca33fe48863868c89c0ac4c28f916 100644 --- a/modules/aggregator/aggregator.info +++ b/modules/aggregator/aggregator.info @@ -7,8 +7,8 @@ files[] = aggregator.test configure = admin/config/services/aggregator/settings stylesheets[all][] = aggregator.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info index aab1b40133e6484a71d8ba72f607e27c01512af3..dbbda05bad521c4bbb10245b73d86c711f5de177 100644 --- a/modules/aggregator/tests/aggregator_test.info +++ b/modules/aggregator/tests/aggregator_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/block/block.info b/modules/block/block.info index 0c6c4ba644414188d4322897fe48b713b83a0a84..d6594b49a625065ea6359d96b1f18f943ebde1aa 100644 --- a/modules/block/block.info +++ b/modules/block/block.info @@ -6,8 +6,8 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/block/block.module b/modules/block/block.module index 6b3b23afba82ed72bb44a4db37686552c6f771cc..b2a3f05225bc9896c7de329b633629f0ed78adde 100644 --- a/modules/block/block.module +++ b/modules/block/block.module @@ -612,7 +612,8 @@ function block_theme_initialize($theme) { $has_blocks = (bool) db_query_range('SELECT 1 FROM {block} WHERE theme = :theme', 0, 1, array(':theme' => $theme))->fetchField(); if (!$has_blocks) { $default_theme = variable_get('theme_default', 'bartik'); - $regions = system_region_list($theme); + // Apply only to new theme's visible regions. + $regions = system_region_list($theme, REGIONS_VISIBLE); $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $block) { // If the region isn't supported by the theme, assign the block to the theme's default region. diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info index 87df447a36bae8c76460ce56b46de57c75300226..deb418460f25dcc7bdc115fb5a1e5719070d7030 100644 --- a/modules/block/tests/block_test.info +++ b/modules/block/tests/block_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/blog/blog.info b/modules/blog/blog.info index c154b86ead3c80119fd00aebd36fcc538303dda7..a70e7ba081be851ca57713638d9c81a1af90d331 100644 --- a/modules/blog/blog.info +++ b/modules/blog/blog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/book/book.info b/modules/book/book.info index 15ff031ce27242896485b6fc14844bce1cea747a..08857e37070424ff890668cfe8f67abc37e4671d 100644 --- a/modules/book/book.info +++ b/modules/book/book.info @@ -7,8 +7,8 @@ files[] = book.test configure = admin/content/book/settings stylesheets[all][] = book.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/book/book.module b/modules/book/book.module index de9561fecf1e90dc4134d31fc67d25431431d904..beb17214c9fa9fe638348cadc711f1ff978d442e 100644 --- a/modules/book/book.module +++ b/modules/book/book.module @@ -617,6 +617,8 @@ function _book_update_outline($node) { 'bid' => $node->book['bid'], )) ->execute(); + // Reset the cache of stored books. + drupal_static_reset('book_get_books'); } else { if ($node->book['bid'] != db_query("SELECT bid FROM {book} WHERE nid = :nid", array( @@ -624,6 +626,8 @@ function _book_update_outline($node) { ))->fetchField()) { // Update the bid for this page and all children. book_update_bid($node->book); + // Reset the cache of stored books. + drupal_static_reset('book_get_books'); } } @@ -895,6 +899,7 @@ function book_node_delete($node) { db_delete('book') ->condition('mlid', $node->book['mlid']) ->execute(); + drupal_static_reset('book_get_books'); } } diff --git a/modules/color/color.info b/modules/color/color.info index ee2b286692f3d0c922b7c5043b997f28f9898dd1..bbd87fc1dc70de18697839daef058491014b7731 100644 --- a/modules/color/color.info +++ b/modules/color/color.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = color.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/comment/comment.info b/modules/comment/comment.info index c948e32db9654143ce609ec7a1e178fe901a5581..acc4291d6fe21a8010235fe65659e20273097060 100644 --- a/modules/comment/comment.info +++ b/modules/comment/comment.info @@ -9,8 +9,8 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 8d0c3d3621fb04d174d998deebb905b41744b31d..c17c5a6beaff3390e097df6f1a56682e78768f53 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -2161,7 +2161,14 @@ function comment_submit($comment) { // 1) Filter it into HTML // 2) Strip out all HTML tags // 3) Convert entities back to plain-text. - $comment->subject = truncate_utf8(trim(decode_entities(strip_tags(check_markup($comment->comment_body[LANGUAGE_NONE][0]['value'], $comment->comment_body[LANGUAGE_NONE][0]['format'])))), 29, TRUE); + $comment_body = $comment->comment_body[LANGUAGE_NONE][0]; + if (isset($comment_body['format'])) { + $comment_text = check_markup($comment_body['value'], $comment_body['format']); + } + else { + $comment_text = check_plain($comment_body['value']); + } + $comment->subject = truncate_utf8(trim(decode_entities(strip_tags($comment_text))), 29, TRUE); // Edge cases where the comment body is populated only by HTML tags will // require a default subject. if ($comment->subject == '') { @@ -2681,6 +2688,10 @@ function comment_rdf_mapping() { */ function comment_file_download_access($field, $entity_type, $entity) { if ($entity_type == 'comment') { - return user_access('access comments') && $entity->status == COMMENT_PUBLISHED || user_access('administer comments'); + if (user_access('access comments') && $entity->status == COMMENT_PUBLISHED || user_access('administer comments')) { + $node = node_load($entity->nid); + return node_access('view', $node); + } + return FALSE; } } diff --git a/modules/comment/comment.test b/modules/comment/comment.test index 770e01d4a5fe49f1ab92f7e62f246ea3a3bf855b..c9478f4917cfc7798a23402414488013ea4a630c 100644 --- a/modules/comment/comment.test +++ b/modules/comment/comment.test @@ -251,6 +251,56 @@ class CommentHelperCase extends DrupalWebTestCase { return $match[2]; } + + /** + * Tests new comment marker. + */ + public function testCommentNewCommentsIndicator() { + // Test if the right links are displayed when no comment is present for the + // node. + $this->drupalLogin($this->admin_user); + $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN)); + $this->drupalGet('node'); + $this->assertNoLink(t('@count comments', array('@count' => 0))); + $this->assertNoLink(t('@count new comments', array('@count' => 0))); + $this->assertLink(t('Read more')); + $count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper')); + $this->assertTrue(count($count) == 1, t('One child found')); + + // Create a new comment. This helper function may be run with different + // comment settings so use comment_save() to avoid complex setup. + $comment = (object) array( + 'cid' => NULL, + 'nid' => $this->node->nid, + 'node_type' => $this->node->type, + 'pid' => 0, + 'uid' => $this->loggedInUser->uid, + 'status' => COMMENT_PUBLISHED, + 'subject' => $this->randomName(), + 'hostname' => ip_address(), + 'language' => LANGUAGE_NONE, + 'comment_body' => array(LANGUAGE_NONE => array($this->randomName())), + ); + comment_save($comment); + $this->drupalLogout(); + + // Log in with 'web user' and check comment links. + $this->drupalLogin($this->web_user); + $this->drupalGet('node'); + $this->assertLink(t('1 new comment')); + $this->clickLink(t('1 new comment')); + $this->assertRaw('<a id="new"></a>', t('Found "new" marker.')); + $this->assertTrue($this->xpath('//a[@id=:new]/following-sibling::a[1][@id=:comment_id]', array(':new' => 'new', ':comment_id' => 'comment-1')), t('The "new" anchor is positioned at the right comment.')); + + // Test if "new comment" link is correctly removed. + $this->drupalGet('node'); + $this->assertLink(t('1 comment')); + $this->assertLink(t('Read more')); + $this->assertNoLink(t('1 new comment')); + $this->assertNoLink(t('@count new comments', array('@count' => 0))); + $count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper')); + $this->assertTrue(count($count) == 2, print_r($count, TRUE)); + } } class CommentInterfaceTest extends CommentHelperCase { @@ -1912,4 +1962,19 @@ class CommentFieldsTest extends CommentHelperCase { $this->postComment($book_node, $this->randomName(), $this->randomName()); $this->postComment($poll_node, $this->randomName(), $this->randomName()); } + + /** + * Test that comment module works correctly with plain text format. + */ + function testCommentFormat() { + // Disable text processing for comments. + $this->drupalLogin($this->admin_user); + $edit = array('instance[settings][text_processing]' => 0); + $this->drupalPost('admin/structure/types/manage/article/comment/fields/comment_body', $edit, t('Save settings')); + + // Post a comment without an explicit subject. + $this->drupalLogin($this->web_user); + $edit = array('comment_body[und][0][value]' => $this->randomName(8)); + $this->drupalPost('node/' . $this->node->nid, $edit, t('Save')); + } } diff --git a/modules/contact/contact.info b/modules/contact/contact.info index 9a10e2851589ae48711608409c841607b7016ba7..5f0c59f16de7dcc9e91de24139f6365f1e44ada4 100644 --- a/modules/contact/contact.info +++ b/modules/contact/contact.info @@ -6,8 +6,8 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info index 65066d7913aff3c73c5d81930fd38b0df8c3f3f0..e059ffa088e38ab9758843c2fda39f38ac45d93a 100644 --- a/modules/contextual/contextual.info +++ b/modules/contextual/contextual.info @@ -4,8 +4,8 @@ package = Core version = VERSION core = 7.x -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info index b2d2c4d88bff774148bead4814ec47ef8cc32b60..e8d7ae673887eb90c082f0514fadfee9c3ecd00b 100644 --- a/modules/dashboard/dashboard.info +++ b/modules/dashboard/dashboard.info @@ -7,8 +7,8 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc index 963e6f8ebfbad6ce2b32918864b9faac186fdc60..0655e75644a110943228a50f16aa596a4879d4c8 100644 --- a/modules/dblog/dblog.admin.inc +++ b/modules/dblog/dblog.admin.inc @@ -10,6 +10,8 @@ * * Messages are truncated at 56 chars. Full-length message could be viewed at * the message details page. + * + * @ingroup logging_severity_levels */ function dblog_overview() { $filter = dblog_build_filter_query(); diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info index f8c213d63a78f9cc26cd4458a8cc8601384e15f3..a369f3258c8e6d1d93bdee15253feaa80d81bc28 100644 --- a/modules/dblog/dblog.info +++ b/modules/dblog/dblog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test index 5717455ef8f464d9f582791d57b92c7ae974b786..ca844a361c215ef561ed1bdaa5306f0114d94b32 100644 --- a/modules/dblog/dblog.test +++ b/modules/dblog/dblog.test @@ -528,6 +528,8 @@ class DBLogTestCase extends DrupalWebTestCase { * CSS class attribute. * @return * The watchdog severity constant or NULL if not found. + * + * @ingroup logging_severity_levels */ protected function getSeverityConstant($class) { // Reversed array from dblog_overview(). diff --git a/modules/field/field.api.php b/modules/field/field.api.php index ba44c7356675d0ab11a527fda0aa5a5415d8faca..3287dd555e0b36b9975cd63d5f5f1102c2174cdb 100644 --- a/modules/field/field.api.php +++ b/modules/field/field.api.php @@ -1132,7 +1132,7 @@ function hook_field_attach_form($entity_type, $entity, &$form, &$form_state, $la * * See field_attach_load() for details and arguments. */ -function hook_field_attach_load($entity_type, &$entities, $age, $options) { +function hook_field_attach_load($entity_type, $entities, $age, $options) { // @todo Needs function body. } @@ -1580,7 +1580,7 @@ function hook_field_storage_details_alter(&$details, $field) { * non-deleted fields. If unset or FALSE, only non-deleted fields should be * loaded. */ -function hook_field_storage_load($entity_type, &$entities, $age, $fields, $options) { +function hook_field_storage_load($entity_type, $entities, $age, $fields, $options) { $field_info = field_info_field_by_ids(); $load_current = $age == FIELD_LOAD_CURRENT; diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc index 845f041098534d8aca50abbe6fe36c0e4a85dc2e..66d93e96320d31a2305c8dac55e433b21fc0b495 100644 --- a/modules/field/field.form.inc +++ b/modules/field/field.form.inc @@ -373,7 +373,7 @@ function field_default_form_errors($entity_type, $entity, $field, $instance, $la * to return just the changed part of the form. */ function field_add_more_submit($form, &$form_state) { - $button = $form_state['clicked_button']; + $button = $form_state['triggering_element']; // Go one level up in the form, to the widgets container. $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1)); @@ -398,7 +398,7 @@ function field_add_more_submit($form, &$form_state) { * @see field_add_more_submit() */ function field_add_more_js($form, $form_state) { - $button = $form_state['clicked_button']; + $button = $form_state['triggering_element']; // Go one level up in the form, to the widgets container. $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1)); diff --git a/modules/field/field.info b/modules/field/field.info index a00088886b20429c54daf6c349b88efd56e7d621..661d18413ee845ee4a0ca4540f0dafe535ba68a8 100644 --- a/modules/field/field.info +++ b/modules/field/field.info @@ -10,8 +10,8 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info index 48e9c59c3adafc712623f9644b1342bf65656aef..95e8bb71bfc0368aff80d0d3f614823cdebd8cea 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.module b/modules/field/modules/field_sql_storage/field_sql_storage.module index 6f49167ec0061129207803a05dbff567354c03b4..10bae64b59728ca30b1e64fe8c1b983de1e719fb 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.module +++ b/modules/field/modules/field_sql_storage/field_sql_storage.module @@ -468,7 +468,6 @@ function field_sql_storage_field_storage_purge($entity_type, $entity, $field, $i * Implements hook_field_storage_query(). */ function field_sql_storage_field_storage_query(EntityFieldQuery $query) { - $groups = array(); if ($query->age == FIELD_LOAD_CURRENT) { $tablename_function = '_field_sql_storage_tablename'; $id_key = 'entity_id'; @@ -499,26 +498,12 @@ function field_sql_storage_field_storage_query(EntityFieldQuery $query) { } } - // Add field conditions. - foreach ($query->fieldConditions as $key => $condition) { - $table_alias = $table_aliases[$key]; - $field = $condition['field']; - // Add the specified condition. - $sql_field = "$table_alias." . _field_sql_storage_columnname($field['field_name'], $condition['column']); - $query->addCondition($select_query, $sql_field, $condition); - // Add delta / language group conditions. - foreach (array('delta', 'language') as $column) { - if (isset($condition[$column . '_group'])) { - $group_name = $condition[$column . '_group']; - if (!isset($groups[$column][$group_name])) { - $groups[$column][$group_name] = $table_alias; - } - else { - $select_query->where("$table_alias.$column = " . $groups[$column][$group_name] . ".$column"); - } - } - } - } + // Add field conditions. We need a fresh grouping cache. + drupal_static_reset('_field_sql_storage_query_field_conditions'); + _field_sql_storage_query_field_conditions($query, $select_query, $query->fieldConditions, $table_aliases, '_field_sql_storage_columnname'); + + // Add field meta conditions. + _field_sql_storage_query_field_conditions($query, $select_query, $query->fieldMetaConditions, $table_aliases, '_field_sql_storage_query_columnname'); if (isset($query->deleted)) { $select_query->condition("$field_base_table.deleted", (int) $query->deleted); @@ -591,6 +576,51 @@ function _field_sql_storage_query_join_entity(SelectQuery $select_query, $entity return $entity_base_table; } +/** + * Adds field (meta) conditions to the given query objects respecting groupings. + * + * @param EntityFieldQuery $query + * The field query object to be processed. + * @param SelectQuery $select_query + * The SelectQuery that should get grouping conditions. + * @param condtions + * The conditions to be added. + * @param $table_aliases + * An associative array of table aliases keyed by field index. + * @param $column_callback + * A callback that should return the column name to be used for the field + * conditions. Accepts a field name and a field column name as parameters. + */ +function _field_sql_storage_query_field_conditions(EntityFieldQuery $query, SelectQuery $select_query, $conditions, $table_aliases, $column_callback) { + $groups = &drupal_static(__FUNCTION__, array()); + foreach ($conditions as $key => $condition) { + $table_alias = $table_aliases[$key]; + $field = $condition['field']; + // Add the specified condition. + $sql_field = "$table_alias." . $column_callback($field['field_name'], $condition['column']); + $query->addCondition($select_query, $sql_field, $condition); + // Add delta / language group conditions. + foreach (array('delta', 'language') as $column) { + if (isset($condition[$column . '_group'])) { + $group_name = $condition[$column . '_group']; + if (!isset($groups[$column][$group_name])) { + $groups[$column][$group_name] = $table_alias; + } + else { + $select_query->where("$table_alias.$column = " . $groups[$column][$group_name] . ".$column"); + } + } + } + } +} + +/** + * Field meta condition column callback. + */ +function _field_sql_storage_query_columnname($field_name, $column) { + return $column; +} + /** * Implements hook_field_storage_delete_revision(). * diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info index 6d3a1f71ca62c9a6478f1f73d2365dc36b90a897..2905a0a14ccc8bf932b62d098309f9486bbb8d45 100644 --- a/modules/field/modules/list/list.info +++ b/modules/field/modules/list/list.info @@ -7,8 +7,8 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/list/list.module b/modules/field/modules/list/list.module index 608679bbb5f958e07dd22f555fdbee2366f06a49..2518ebcfc29c1960a635a732e3c547da16822a6c 100644 --- a/modules/field/modules/list/list.module +++ b/modules/field/modules/list/list.module @@ -343,7 +343,7 @@ function list_allowed_values_string($values) { function list_field_update_forbid($field, $prior_field, $has_data) { if ($field['module'] == 'list' && $has_data) { // Forbid any update that removes allowed values with actual data. - $lost_keys = array_diff(array_keys($field['settings']['allowed_values']), array_keys($prior_field['settings']['allowed_values'])); + $lost_keys = array_diff(array_keys($prior_field['settings']['allowed_values']), array_keys($field['settings']['allowed_values'])); if (_list_values_in_use($field, $lost_keys)) { throw new FieldUpdateForbiddenException(t('Cannot update a list field to not include keys with existing data.')); } diff --git a/modules/field/modules/list/tests/list.test b/modules/field/modules/list/tests/list.test index 941d2b4cb02d8df66bb4e0cc36e4e2ec06f40adc..dec09560f8761eeccc31b5aa646815ebd618ba65 100644 --- a/modules/field/modules/list/tests/list.test +++ b/modules/field/modules/list/tests/list.test @@ -55,6 +55,23 @@ class ListFieldTestCase extends FieldTestCase { $this->assertTrue(!empty($form[$this->field_name][$langcode][2]), t('Option 2 exists')); $this->assertTrue(!empty($form[$this->field_name][$langcode][3]), t('Option 3 exists')); + // Use one of the values in an actual entity, and check that this value + // cannot be removed from the list. + $entity = field_test_create_stub_entity(); + $entity->{$this->field_name}[$langcode][0] = array('value' => 1); + field_test_entity_save($entity); + $this->field['settings']['allowed_values'] = array(2 => 'Two'); + try { + field_update_field($this->field); + $this->fail(t('Cannot update a list field to not include keys with existing data.')); + } + catch (FieldException $e) { + $this->pass(t('Cannot update a list field to not include keys with existing data.')); + } + // Empty the value, so that we can actually remove the option. + $entity->{$this->field_name}[$langcode] = array(); + field_test_entity_save($entity); + // Removed options do not appear. $this->field['settings']['allowed_values'] = array(2 => 'Two'); field_update_field($this->field); diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info index 69ab5276a0f26c84da142a43b1571b16dd97d3b6..52d03ff3b9e7d38c430ccde31e8ad999cbe5916b 100644 --- a/modules/field/modules/list/tests/list_test.info +++ b/modules/field/modules/list/tests/list_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info index 608bcdafedb1fafb2369613003ccdcfae5c2cdca..248010337d74e33292c3bd16d44242b96911c0bb 100644 --- a/modules/field/modules/number/number.info +++ b/modules/field/modules/number/number.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info index 84a8351efdfe5b098629ba978337b25eb6bd4b4f..fa1b32f36bed0d2aaf344192e3053a269a730b81 100644 --- a/modules/field/modules/options/options.info +++ b/modules/field/modules/options/options.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info index 518cf9345f74e8ac36a4209054f669395028a050..ce426a0c4e4a20e19bd21414dcb164035609bf14 100644 --- a/modules/field/modules/text/text.info +++ b/modules/field/modules/text/text.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test index b42fed7e09894d352b3ecdd27431234e6ae77f72..59369370efcc355e87fe5855b2d5d79f1afe98a3 100644 --- a/modules/field/modules/text/text.test +++ b/modules/field/modules/text/text.test @@ -464,7 +464,7 @@ class TextTranslationTestCase extends DrupalWebTestCase { $node = $this->drupalGetNodeByTitle($edit['title']); $this->drupalGet("node/$node->nid/translate"); $this->clickLink(t('add translation')); - $this->assertFieldByXPath("//textarea[@name='body[fr][0][value]']", $body, t('The textfield widget is populated.')); + $this->assertFieldByXPath("//textarea[@name='body[$langcode][0][value]']", $body, t('The textfield widget is populated.')); } /** @@ -484,17 +484,17 @@ class TextTranslationTestCase extends DrupalWebTestCase { ); // Create an article with the first body input format set to "Full HTML". - $langcode = 'en'; $title = $this->randomName(); $edit = array( 'title' => $title, - 'language' => $langcode, + 'language' => 'en', ); $this->drupalPost('node/add/article', $edit, t('Save')); // Populate the body field: the first item gets the "Full HTML" input // format, the second one "Filtered HTML". $formats = array('full_html', 'filtered_html'); + $langcode = LANGUAGE_NONE; foreach ($body as $delta => $value) { $edit = array( "body[$langcode][$delta][value]" => $value, diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info index dc1b41c9f438cdaff0bf084f866d10111b9375cc..349814aeab35faa2e0e096768754e9e5ed23f6b9 100644 --- a/modules/field/tests/field_test.info +++ b/modules/field/tests/field_test.info @@ -6,8 +6,8 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc index 96beb13347c4804ce7f558a7188839b7c5b5737e..b594faca3d81ac98b22b55dcda2d8959c165ff6e 100644 --- a/modules/field_ui/field_ui.admin.inc +++ b/modules/field_ui/field_ui.admin.inc @@ -509,6 +509,10 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle '#cell_attributes' => array('colspan' => 3), '#prefix' => '<div class="add-new-placeholder"> </div>', ), + 'translatable' => array( + '#type' => 'value', + '#value' => FALSE, + ), ); } @@ -753,7 +757,7 @@ function field_ui_field_overview_form_submit($form, &$form_state) { $field = array( 'field_name' => $values['field_name'], 'type' => $values['type'], - 'translatable' => TRUE, + 'translatable' => $values['translatable'], ); $instance = array( 'field_name' => $field['field_name'], diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info index e84d8eed438fc061f68e8a6639c43586833b7c7f..bf5f535e72f5d038ec822614e71fcbdeb3609312 100644 --- a/modules/field_ui/field_ui.info +++ b/modules/field_ui/field_ui.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = field_ui.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module index 7355e879bc11ae353db20a7660a0978ed7cf003b..27ef3c2d7ded82e31dd2f6c4c93b119f9d134828 100644 --- a/modules/field_ui/field_ui.module +++ b/modules/field_ui/field_ui.module @@ -358,7 +358,7 @@ function field_ui_form_node_type_form_alter(&$form, $form_state) { * Redirect to manage fields form. */ function field_ui_form_node_type_form_submit($form, &$form_state) { - if ($form_state['clicked_button']['#parents'][0] === 'save_continue') { + if ($form_state['triggering_element']['#parents'][0] === 'save_continue') { $form_state['redirect'] = _field_ui_bundle_admin_path('node', $form_state['values']['type']) .'/fields'; } } diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test index 5d2ff9bfa5d96216210d9106b840821715afb581..9ff6c17203f55749aab5c4b23c92d984a9b50926 100644 --- a/modules/field_ui/field_ui.test +++ b/modules/field_ui/field_ui.test @@ -613,7 +613,8 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { // Render a cloned node, so that we do not alter the original. $clone = clone $node; - $output = drupal_render(node_view($clone, $view_mode)); + $element = node_view($clone, $view_mode); + $output = drupal_render($element); $this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '<hr />'. $output); // Assign content so that DrupalWebTestCase functions can be used. diff --git a/modules/file/file.info b/modules/file/file.info index b3a1dc0b887875a97ca57560f80818379f3239aa..d91af6a1c9e0a5d4bfbaf7c156debc4a6b302bdf 100644 --- a/modules/file/file.info +++ b/modules/file/file.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = tests/file.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/file/file.module b/modules/file/file.module index 3e4525119611cf49c3ff46f864e6a0a72989cf13..83de0f622aeeade27aec8837420f2d769cf480aa 100644 --- a/modules/file/file.module +++ b/modules/file/file.module @@ -533,7 +533,7 @@ function file_managed_file_validate(&$element, &$form_state) { // If referencing an existing file, only allow if there are existing // references. This prevents unmanaged files from being deleted if this // item were to be deleted. - $clicked_button = end($form_state['clicked_button']['#parents']); + $clicked_button = end($form_state['triggering_element']['#parents']); if ($clicked_button != 'remove_button' && !empty($element['fid']['#value'])) { if ($file = file_load($element['fid']['#value'])) { if ($file->status == FILE_STATUS_PERMANENT) { diff --git a/modules/file/tests/file.test b/modules/file/tests/file.test index ea8c5c67bb9958feb6fb5b19d779651144ac4b0c..0e5f97d84bb39b273e475a8ab023f791e3460b59 100644 --- a/modules/file/tests/file.test +++ b/modules/file/tests/file.test @@ -12,7 +12,16 @@ class FileFieldTestCase extends DrupalWebTestCase { protected $admin_user; function setUp() { - parent::setUp('file', 'file_module_test'); + // Since this is a base class for many test cases, support the same + // flexibility that DrupalWebTestCase::setUp() has for the modules to be + // passed in as either an array or a variable number of string arguments. + $modules = func_get_args(); + if (isset($modules[0]) && is_array($modules[0])) { + $modules = $modules[0]; + } + $modules[] = 'file'; + $modules[] = 'file_module_test'; + parent::setUp($modules); $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access')); $this->drupalLogin($this->admin_user); } @@ -112,7 +121,7 @@ class FileFieldTestCase extends DrupalWebTestCase { /** * Upload a file to a node. */ - function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE) { + function uploadNodeFile($file, $field_name, $nid_or_type, $new_revision = TRUE, $extras = array()) { $langcode = LANGUAGE_NONE; $edit = array( "title" => $this->randomName(), @@ -124,7 +133,8 @@ class FileFieldTestCase extends DrupalWebTestCase { } else { // Add a new node. - $node = $this->drupalCreateNode(array('type' => $nid_or_type)); + $extras['type'] = $nid_or_type; + $node = $this->drupalCreateNode($extras); $nid = $node->nid; // Save at least one revision to better simulate a real site. $this->drupalCreateNode(get_object_vars($node)); @@ -530,6 +540,7 @@ class FileFieldWidgetTestCase extends FileFieldTestCase { 'title' => $this->randomName(), ); $this->drupalPost('node/add/article', $edit, t('Save')); + $node = $this->drupalGetNodeByTitle($edit['title']); // Add a comment with a file. $text_file = $this->getTestFile('text'); @@ -559,6 +570,18 @@ class FileFieldWidgetTestCase extends FileFieldTestCase { $this->drupalLogout(); $this->drupalGet(file_create_url($comment_file->uri)); $this->assertResponse(403, t('Confirmed that access is denied for the file without the needed permission.')); + + // Unpublishes node. + $this->drupalLogin($this->admin_user); + $edit = array( + 'status' => FALSE, + ); + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + + // Ensures normal user can no longer download the file. + $this->drupalLogin($user); + $this->drupalGet(file_create_url($comment_file->uri)); + $this->assertResponse(403, t('Confirmed that access is denied for the file without the needed permission.')); } } @@ -1006,21 +1029,19 @@ class FileTokenReplaceTestCase extends FileFieldTestCase { // Load the node and the file. $node = node_load($nid, NULL, TRUE); - $file = (object) $node->{$field_name}[LANGUAGE_NONE][0]; - $file->description = 'File description.'; + $file = file_load($node->{$field_name}[LANGUAGE_NONE][0]['fid']); // Generate and test sanitized tokens. $tests = array(); $tests['[file:fid]'] = $file->fid; $tests['[file:name]'] = check_plain($file->filename); - $tests['[file:description]'] = filter_xss($file->description); - $tests['[file:path]'] = filter_xss($file->uri); - $tests['[file:mime]'] = filter_xss($file->filemime); + $tests['[file:path]'] = check_plain($file->uri); + $tests['[file:mime]'] = check_plain($file->filemime); $tests['[file:size]'] = format_size($file->filesize); - $tests['[file:url]'] = url(file_create_url($file->uri), $url_options); + $tests['[file:url]'] = check_plain(file_create_url($file->uri)); $tests['[file:timestamp]'] = format_date($file->timestamp, 'medium', '', NULL, $language->language); $tests['[file:timestamp:short]'] = format_date($file->timestamp, 'short', '', NULL, $language->language); - $tests['[file:owner]'] = $this->admin_user->name; + $tests['[file:owner]'] = check_plain(format_username($this->admin_user)); $tests['[file:owner:uid]'] = $file->uid; // Test to make sure that we generated something for each token. @@ -1033,7 +1054,6 @@ class FileTokenReplaceTestCase extends FileFieldTestCase { // Generate and test unsanitized tokens. $tests['[file:name]'] = $file->filename; - $tests['[file:description]'] = $file->description; $tests['[file:path]'] = $file->uri; $tests['[file:mime]'] = $file->filemime; $tests['[file:size]'] = format_size($file->filesize); @@ -1044,3 +1064,46 @@ class FileTokenReplaceTestCase extends FileFieldTestCase { } } } + +/** + * Test class to test file access on private nodes. + */ +class FilePrivateTestCase extends FileFieldTestCase { + public static function getInfo() { + return array( + 'name' => 'Private file test', + 'description' => 'Uploads a test to a private node and checks access.', + 'group' => 'File', + ); + } + + function setUp() { + parent::setUp('node_access_test'); + node_access_rebuild(); + variable_set('node_access_test_private', TRUE); + } + + /** + * Uploads a file to a private node, then tests that access is allowed and denied when appropriate. + */ + function testPrivateFile() { + // Use 'page' instead of 'article', so that the 'article' image field does + // not conflict with this test. If in the future the 'page' type gets its + // own default file or image field, this test can be made more robust by + // using a custom node type. + $type_name = 'page'; + $field_name = strtolower($this->randomName()); + $this->createFileField($field_name, $type_name, array('uri_scheme' => 'private')); + + $test_file = $this->getTestFile('text'); + $nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => TRUE)); + $node = node_load($nid, NULL, TRUE); + $node_file = (object) $node->{$field_name}[LANGUAGE_NONE][0]; + // Ensure the file can be downloaded. + $this->drupalGet(file_create_url($node_file->uri)); + $this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the shipped file.')); + $this->drupalLogOut(); + $this->drupalGet(file_create_url($node_file->uri)); + $this->assertNoResponse(200, t('Confirmed that access is denied for the file without the needed permission.')); + } +} diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info index 80b5d649ee92816f5b7c89b4ff6e34c73928860d..a51ea6900f3d6b8688dd445c6ce32136d1811e02 100644 --- a/modules/file/tests/file_module_test.info +++ b/modules/file/tests/file_module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/filter/filter.info b/modules/filter/filter.info index 049577c0b9babf1eb40f0f14dd016affbd69f895..33fe235d424ebed17585b5a7a07aa87498c72de3 100644 --- a/modules/filter/filter.info +++ b/modules/filter/filter.info @@ -7,8 +7,8 @@ files[] = filter.test required = TRUE configure = admin/config/content/formats -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/filter/filter.test b/modules/filter/filter.test index a3d1bde40573aeb6555e1f9fe6e48405a0c97ba9..67d08333dc7d98d0084871564ae457410355c0d8 100644 --- a/modules/filter/filter.test +++ b/modules/filter/filter.test @@ -792,7 +792,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase { */ function testLineBreakFilter() { // Setup dummy filter object. - $filter = new stdClass; + $filter = new stdClass(); $filter->callback = '_filter_autop'; // Since the line break filter naturally needs plenty of newlines in test @@ -1156,7 +1156,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase { */ function testHtmlEscapeFilter() { // Setup dummy filter object. - $filter = new stdClass; + $filter = new stdClass(); $filter->callback = '_filter_html_escape'; $tests = array( @@ -1174,7 +1174,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase { */ function testUrlFilter() { // Setup dummy filter object. - $filter = new stdClass; + $filter = new stdClass(); $filter->callback = '_filter_url'; $filter->settings = array( 'filter_url_length' => 496, @@ -1509,7 +1509,7 @@ www.example.com with a newline in comments --> */ function testUrlFilterContent() { // Setup dummy filter object. - $filter = new stdClass; + $filter = new stdClass(); $filter->settings = array( 'filter_url_length' => 496, ); diff --git a/modules/forum/forum.info b/modules/forum/forum.info index 00f5fce7f2daf6d7fbd98fb8e3ee81ba8b6f4778..85e7daca610f4a5f83a2b0cf402ecc833e03ef35 100644 --- a/modules/forum/forum.info +++ b/modules/forum/forum.info @@ -9,8 +9,8 @@ files[] = forum.test configure = admin/structure/forum stylesheets[all][] = forum.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/help/help.info b/modules/help/help.info index e944227ef9148564ef988b2a1103f45aebe8c413..b6db9d2e2c0449c6f1ae440daad0457d39af06c5 100644 --- a/modules/help/help.info +++ b/modules/help/help.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = help.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/image/image.info b/modules/image/image.info index 401cd05035b9eaad02f236a8cb9559fe1a3aad6d..830c0a1962687c7241decd8bd05af47b67710fcb 100644 --- a/modules/image/image.info +++ b/modules/image/image.info @@ -7,8 +7,8 @@ dependencies[] = file files[] = image.test configure = admin/config/media/image-styles -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/image/tests/image_module_test.info b/modules/image/tests/image_module_test.info index ffa11f00d6577e8e95fff32a614e16b5b497a243..7d851117ee9aee8291cb8d5286a0f50be7176d13 100644 --- a/modules/image/tests/image_module_test.info +++ b/modules/image/tests/image_module_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = image_module_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/locale/locale-rtl.css b/modules/locale/locale-rtl.css new file mode 100644 index 0000000000000000000000000000000000000000..aaf1988dd17d0ea777536ade858af113e232e967 --- /dev/null +++ b/modules/locale/locale-rtl.css @@ -0,0 +1,12 @@ + +#locale-translation-filter-form .form-item-language, +#locale-translation-filter-form .form-item-translation, +#locale-translation-filter-form .form-item-group { + float: right; + padding-left: .8em; + padding-right: 0; +} +#locale-translation-filter-form .form-actions { + float: right; + padding: 3ex 1em 0 0; +} diff --git a/modules/locale/locale.css b/modules/locale/locale.css index 1d875a2bf4bb007ba3cb5eca734316452b448938..38112b50607114d61c623257e9a22a739d1502fd 100644 --- a/modules/locale/locale.css +++ b/modules/locale/locale.css @@ -21,14 +21,12 @@ width: 100%; } #locale-translation-filter-form .form-actions { - float: left; - padding: 3ex 0 0 1em; + float: left; /* LTR */ + padding: 3ex 0 0 1em; /* LTR */ } - .language-switcher-locale-session a.active { color: #0062A0; } - .language-switcher-locale-session a.session-active { color: #000000; } diff --git a/modules/locale/locale.info b/modules/locale/locale.info index 7489d33417aa2795f1c62119e0c787975dedd949..6a62bb7fec868f35eea3e35c5f94f3d41c641d3a 100644 --- a/modules/locale/locale.info +++ b/modules/locale/locale.info @@ -6,8 +6,8 @@ core = 7.x files[] = locale.test configure = admin/config/regional/language -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/locale/locale.test b/modules/locale/locale.test index 42a6dbc48063e34adc90df51f88707e0e5d05df3..3ae6d91a5c80199860ceb328d4778ed5c5b8701d 100644 --- a/modules/locale/locale.test +++ b/modules/locale/locale.test @@ -2137,6 +2137,11 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase { ); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.')); + + // Make node body translatable. + $field = field_info_field('body'); + $field['translatable'] = TRUE; + field_update_field($field); } /** diff --git a/modules/locale/tests/locale_test.info b/modules/locale/tests/locale_test.info index 41b5cb99c6bd2b032d1de92b4afe31c132a589dd..f966df08d70b61b817afa59d81db7f287beb000a 100644 --- a/modules/locale/tests/locale_test.info +++ b/modules/locale/tests/locale_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/menu/menu.info b/modules/menu/menu.info index 4ab447a390ddfaa7c01e8b8c4f1f63c424cc3aee..88eab9657c2f9a17c451498520068b13f1e0aca9 100644 --- a/modules/menu/menu.info +++ b/modules/menu/menu.info @@ -6,8 +6,8 @@ core = 7.x files[] = menu.test configure = admin/structure/menu -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/menu/menu.install b/modules/menu/menu.install index 717c5e7126b8141c432dd6603531b914f089ed81..13cb3cb50415e6e96a150490eedee74ef836ee42 100644 --- a/modules/menu/menu.install +++ b/modules/menu/menu.install @@ -108,6 +108,58 @@ function menu_update_7000() { } } +/** + * Rename "Primary Links" and "Secondary Links" to their Drupal 7 equivalents. + */ +function menu_update_7001() { + // Migrate D6 menu_primary_links_source to D7 menu_main_links_source (without + // renaming). + if (variable_get('menu_primary_links_source') !== NULL) { + variable_set('menu_main_links_source', variable_get('menu_primary_links_source')); + variable_del('menu_primary_links_source'); + } + + // Rename each menu, and any settings that refer to the old menu name. + $rename = array( + 'primary-links' => array('main-menu', 'Main menu'), + 'secondary-links' => array('secondary-menu', 'Secondary menu'), + ); + foreach ($rename as $from_menu => $to) { + list($to_menu, $to_title) = $to; + // Rename the menu, and links in the menu. + db_update('menu_custom') + ->fields(array('menu_name' => $to_menu, 'title' => $to_title)) + ->condition('menu_name', $from_menu) + ->execute(); + db_update('menu_links') + ->fields(array('menu_name' => $to_menu)) + ->condition('menu_name', $from_menu) + ->execute(); + + // Update any content type that used this menu as a default menu. + // Note: these variables may be unset/default, in which case we leave them + // alone. See menu_update_7000() + foreach (_update_7000_node_get_types() as $type => $type_object) { + $menu_options = variable_get('menu_options_' . $type); + if ($menu_options !== NULL) { + variable_set('menu_options_' . $type, str_replace($from_menu, $to_menu, $menu_options)); + if (variable_get('menu_parent_' . $type) == $from_menu . ':0') { + variable_set('menu_parent_' . $type, $to_menu . ':0'); + } + } + } + + // Update the "source for primary links" and "source for secondary links" to + // follow. + if (variable_get('menu_main_links_source') == $from_menu) { + variable_set('menu_main_links_source', $to_menu); + } + if (variable_get('menu_secondary_links_source') == $from_menu) { + variable_set('menu_secondary_links_source', $to_menu); + } + } +} + /** * @} End of "defgroup updates-7.x-extra" * The next series of updates should start at 8000. diff --git a/modules/node/node.api.php b/modules/node/node.api.php index 90ffd8b7fbc8e87040663a64341a84b6c9b4b8bc..bc2eb65b1733f6a3ec3bcdc471a0d7f522cd6b77 100644 --- a/modules/node/node.api.php +++ b/modules/node/node.api.php @@ -1022,7 +1022,7 @@ function hook_node_type_delete($info) { */ function hook_delete($node) { db_delete('mytable') - ->condition('nid', $nid->nid) + ->condition('nid', $node->nid) ->execute(); } diff --git a/modules/node/node.info b/modules/node/node.info index c33a80ebaf97f927e5f4467b4cadcaa1638c9433..bb9b933d9cf31eeac1c4381092262990b2f60aae 100644 --- a/modules/node/node.info +++ b/modules/node/node.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/structure/types stylesheets[all][] = node.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/node/node.install b/modules/node/node.install index 852c1117b11e4e04fd650b1eb7c18b8ece73e039..2498091fc533896ac2e885235a5d50e6ffc41d8c 100644 --- a/modules/node/node.install +++ b/modules/node/node.install @@ -476,7 +476,7 @@ function _update_7000_node_get_types() { $extra_types = array_diff($all_types, array_keys($node_types)); foreach ($extra_types as $type) { - $type_object = new stdClass; + $type_object = new stdClass(); $type_object->type = $type; // In Drupal 6, whether you have a body field or not is a flag in the node @@ -610,7 +610,6 @@ function node_update_7006(&$sandbox) { 'module' => 'text', 'cardinality' => 1, 'entity_types' => array('node'), - 'translatable' => TRUE, ); _update_7000_field_create_field($body_field); @@ -628,6 +627,8 @@ function node_update_7006(&$sandbox) { 'entity_type' => 'node', 'bundle' => $node_type->type, 'label' => $node_type->body_label, + 'description' => isset($node_type->description) ? $node_type->description : '', + 'required' => (isset($node_type->min_word_count) && $node_type->min_word_count > 0) ? 1 : 0, 'widget' => array( 'type' => 'text_textarea_with_summary', 'settings' => array( diff --git a/modules/node/node.module b/modules/node/node.module index 66e93c737b91a5a61dfd75e5c1a5a634ac907d06..6c32a279900fd6556f092bdf1667f154d7e266d9 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -558,7 +558,6 @@ function node_add_body_field($type, $label = 'Body') { 'field_name' => 'body', 'type' => 'text_with_summary', 'entity_types' => array('node'), - 'translatable' => TRUE, ); $field = field_create_field($field); } @@ -1404,11 +1403,13 @@ function node_show($node, $message = FALSE) { drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))), PASS_THROUGH); } + // For markup consistency with other pages, use node_view_multiple() rather than node_view(). + $nodes = node_view_multiple(array($node->nid => $node), 'full'); + // Update the history table, stating that this user viewed this node. node_tag_new($node); - // For markup consistency with other pages, use node_view_multiple() rather than node_view(). - return node_view_multiple(array($node->nid => $node), 'full'); + return $nodes; } /** @@ -2159,7 +2160,7 @@ function node_block_save($delta = '', $edit = array()) { } /** - * Find the most recent nodes that are available to the current user. + * Finds the most recently changed nodes that are available to the current user. * * @param $number * (optional) The maximum number of nodes to find. Defaults to 10. @@ -2415,7 +2416,10 @@ function node_block_list_alter(&$blocks) { } /** - * A generic function for generating RSS feeds from a set of nodes. + * Generates and prints an RSS feed. + * + * Generates an RSS feed from an array of node IDs, and prints it with an HTTP + * header, with Content Type set to RSS/XML. * * @param $nids * An array of node IDs (nid). Defaults to FALSE so empty feeds can be @@ -3337,6 +3341,9 @@ function node_access_acquire_grants($node, $delete = TRUE) { * node_access can use this function when doing mass updates due to widespread * permission changes. * + * Note: Don't call this function directly from a contributed module. Call + * node_access_acquire_grants() instead. + * * @param $node * The $node being written to. All that is necessary is that it contains a * nid. diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info index f87752008da54b181f22676d456dc34de6e72814..0c4815d302f6816df714f848f5837e58f66371a1 100644 --- a/modules/node/tests/node_access_test.info +++ b/modules/node/tests/node_access_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/node/tests/node_access_test.install b/modules/node/tests/node_access_test.install index 3535ab1997e2be6bda5f7b9d688795521b7631c7..1f33d51bac5a65f9ef4c82fa21c76b2dc59d9084 100644 --- a/modules/node/tests/node_access_test.install +++ b/modules/node/tests/node_access_test.install @@ -40,45 +40,3 @@ function node_access_test_schema() { return $schema; } -<?php - -/** - * @file - * Install, update and uninstall functions for the node_access_test module. - */ - -/** - * Implements hook_schema(). - */ -function node_access_test_schema() { - $schema['node_access_test'] = array( - 'description' => 'The base table for node_access_test.', - 'fields' => array( - 'nid' => array( - 'description' => 'The {node}.nid this record affects.', - 'type' => 'int', - 'unsigned' => TRUE, - 'not null' => TRUE, - 'default' => 0, - ), - 'private' => array( - 'description' => 'Boolean indicating whether the node is private (visible to administrator) or not (visible to non-administrators).', - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - ), - ), - 'indexes' => array( - 'nid' => array('nid'), - ), - 'primary key' => array('nid'), - 'foreign keys' => array( - 'versioned_node' => array( - 'table' => 'node', - 'columns' => array('nid' => 'nid'), - ), - ), - ); - - return $schema; -} \ No newline at end of file diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info index 3ad8497133ff6c2ddc87139a4214632f5dd94a55..1499a40ba827ab97d763adbd0f912000392e1769 100644 --- a/modules/node/tests/node_test.info +++ b/modules/node/tests/node_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info index b30b64b9601023d6f5be3dc7fc40c93c6d245cf4..c49c0b95ecebcbeab541c0f482f6f6e3a9153883 100644 --- a/modules/node/tests/node_test_exception.info +++ b/modules/node/tests/node_test_exception.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/openid/openid.info b/modules/openid/openid.info index 8f7e176b57ad574fc9fcc329bd67f9f45b118e91..5f3f9152d798a74df510762666e69c8c00d76036 100644 --- a/modules/openid/openid.info +++ b/modules/openid/openid.info @@ -5,8 +5,8 @@ package = Core core = 7.x files[] = openid.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info index a40013ba027685ed72874e5655672166a91d78eb..8652d3a0ec1be43ff67287e6107a350800491c83 100644 --- a/modules/openid/tests/openid_test.info +++ b/modules/openid/tests/openid_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = openid hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info index 1688b0d441ceff320cf9b5e5c223ca3857c18f7a..85dbaccd7853a45fa3d569a343d832e9835378de 100644 --- a/modules/overlay/overlay.info +++ b/modules/overlay/overlay.info @@ -4,8 +4,8 @@ package = Core version = VERSION core = 7.x -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/path/path.info b/modules/path/path.info index ab494d3e6ddeae56a131040987df43dbda76be71..8fcdd55c72ed4c8c05a3d56b684d096597c080c1 100644 --- a/modules/path/path.info +++ b/modules/path/path.info @@ -6,8 +6,8 @@ core = 7.x files[] = path.test configure = admin/config/search/path -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/path/path.test b/modules/path/path.test index 4112e5f6b1f207a72b6a3c18dfabeba8cfc94611..f42ec81be08cc95b101cecf534fb654e0b42b785 100644 --- a/modules/path/path.test +++ b/modules/path/path.test @@ -279,8 +279,9 @@ class PathLanguageTestCase extends DrupalWebTestCase { $this->drupalGet('node/' . $english_node->nid . '/translate'); $this->clickLink(t('add translation')); $edit = array(); + $langcode = LANGUAGE_NONE; $edit["title"] = $this->randomName(); - $edit["body[fr][0][value]"] = $this->randomName(); + $edit["body[$langcode][0][value]"] = $this->randomName(); $french_alias = $this->randomName(); $edit['path[alias]'] = $french_alias; $this->drupalPost(NULL, $edit, t('Save')); diff --git a/modules/php/php.info b/modules/php/php.info index 162c5fbe5c13724f5cbc903a2560541933001bb0..9526982763da52e18375ea9aab9cad67fe8e5b23 100644 --- a/modules/php/php.info +++ b/modules/php/php.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = php.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/poll/poll.info b/modules/poll/poll.info index f53726e442234294ae5a0c0c7617648f6a5c83bd..e5e3017cc0c2a509ec70d2bc5ef221daeb0d77fa 100644 --- a/modules/poll/poll.info +++ b/modules/poll/poll.info @@ -6,8 +6,8 @@ core = 7.x files[] = poll.test stylesheets[all][] = poll.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/poll/poll.module b/modules/poll/poll.module index f45b8bda7863ca9f5c27b3eb906d1b4431c780d7..861969573df542ef4fa88ceffaa496a6ea7bbca9 100644 --- a/modules/poll/poll.module +++ b/modules/poll/poll.module @@ -485,6 +485,10 @@ function poll_load($nodes) { foreach ($nodes as $node) { $poll = db_query("SELECT runtime, active FROM {poll} WHERE nid = :nid", array(':nid' => $node->nid))->fetchObject(); + if (empty($poll)) { + $poll = new stdClass(); + } + // Load the appropriate choices into the $poll object. $poll->choice = db_select('poll_choice', 'c') ->addTag('translatable') diff --git a/modules/profile/profile.info b/modules/profile/profile.info index 59c28cb88c276988a865f07951c766adf5a3cef4..dc61b8394000112af2fcc9062e84252398fef4ec 100644 --- a/modules/profile/profile.info +++ b/modules/profile/profile.info @@ -11,8 +11,8 @@ configure = admin/config/people/profile ; See user_system_info_alter(). hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/profile/profile.module b/modules/profile/profile.module index 2374fe8ea0712448523774b9e5baca3c0446c7b7..8cac6d797ff7caf81363649c74d315684ef11fe6 100644 --- a/modules/profile/profile.module +++ b/modules/profile/profile.module @@ -544,6 +544,7 @@ function template_preprocess_profile_block(&$variables) { // Supply filtered version of $fields that have values. foreach ($variables['fields'] as $field) { if ($field->value) { + $variables['profile'][$field->name] = new stdClass(); $variables['profile'][$field->name]->title = check_plain($field->title); $variables['profile'][$field->name]->value = $field->value; $variables['profile'][$field->name]->type = $field->type; diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info index 029ff2cec45c84912a555bba0f3a06f9231c1cbf..416b3838a4e04c28486a9eae4107149403636392 100644 --- a/modules/rdf/rdf.info +++ b/modules/rdf/rdf.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = rdf.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info index a0ff30ba34583f6dbeaaaaf58cad54a8a24a8f1a..00bd9256c00face01c0e3519d1e87fc6dba649e6 100644 --- a/modules/rdf/tests/rdf_test.info +++ b/modules/rdf/tests/rdf_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/search/search.admin.inc b/modules/search/search.admin.inc index afa02defb4b099764296e0ae4e204fab14f1c28b..d93c85288329b67eadfb2279fa8dab1e45316dca 100644 --- a/modules/search/search.admin.inc +++ b/modules/search/search.admin.inc @@ -143,7 +143,7 @@ function search_admin_settings($form) { */ function search_admin_settings_validate($form, &$form_state) { // Check whether we selected a valid default. - if ($form_state['clicked_button']['#value'] != t('Reset to defaults')) { + if ($form_state['triggering_element']['#value'] != t('Reset to defaults')) { $new_modules = array_filter($form_state['values']['search_active_modules']); $default = $form_state['values']['search_default_module']; if (!in_array($default, $new_modules, TRUE)) { @@ -164,7 +164,7 @@ function search_admin_settings_submit($form, &$form_state) { } $current_modules = variable_get('search_active_modules', array('node', 'user')); // Check whether we are resetting the values. - if ($form_state['clicked_button']['#value'] == t('Reset to defaults')) { + if ($form_state['triggering_element']['#value'] == t('Reset to defaults')) { $new_modules = array('node', 'user'); } else { diff --git a/modules/search/search.api.php b/modules/search/search.api.php index 557a56e51a5c457e6b8332eeee83e7b14c2f17e9..8d6e2399ffb91c4d1a9def9916420798be41ffb4 100644 --- a/modules/search/search.api.php +++ b/modules/search/search.api.php @@ -107,6 +107,10 @@ function hook_search_reset() { /** * Report the status of indexing. * + * The core search module only invokes this hook on active modules. + * Implementing modules do not need to check whether they are active when + * calculating their return values. + * * @return * An associative array with the key-value pairs: * - 'remaining': The number of items left to index. diff --git a/modules/search/search.info b/modules/search/search.info index b0032763feefb5bb7feaf0f976bca76bc05a1c32..249b0bedfd6089f644a6a6f6d59e54af4cb2653d 100644 --- a/modules/search/search.info +++ b/modules/search/search.info @@ -8,8 +8,8 @@ files[] = search.test configure = admin/config/search/settings stylesheets[all][] = search.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/search/tests/search_embedded_form.info b/modules/search/tests/search_embedded_form.info index de81aaec684cd7b336231d1152a4cd2cd0e805e6..d2f00ac68336315d45f131cd028bb5b0025eeaa3 100644 --- a/modules/search/tests/search_embedded_form.info +++ b/modules/search/tests/search_embedded_form.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/search/tests/search_embedded_form.module b/modules/search/tests/search_embedded_form.module index c0058f74d06aa08ddfbed867673635cef13c8ab8..484579674576c1ca75de011b59e1314d22371cf0 100644 --- a/modules/search/tests/search_embedded_form.module +++ b/modules/search/tests/search_embedded_form.module @@ -65,5 +65,6 @@ function search_embedded_form_form_submit($form, &$form_state) { * Adds the test form to search results. */ function search_embedded_form_preprocess_search_result(&$variables) { - $variables['snippet'] .= drupal_render(drupal_get_form('search_embedded_form_form')); + $form = drupal_get_form('search_embedded_form_form'); + $variables['snippet'] .= drupal_render($form); } diff --git a/modules/search/tests/search_extra_type.info b/modules/search/tests/search_extra_type.info index 32adacc9634f8a099925ebba1ee8aecb71582cc8..06d86c5a98aa570c5b661e8d04518ae4654d1352 100644 --- a/modules/search/tests/search_extra_type.info +++ b/modules/search/tests/search_extra_type.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info index 39728aa38c18eca6b06a11161f9123cac3bd7515..4eb2dbbd5adc79a17d4ba28153fd7e9963da3438 100644 --- a/modules/shortcut/shortcut.info +++ b/modules/shortcut/shortcut.info @@ -6,8 +6,8 @@ core = 7.x files[] = shortcut.test configure = admin/config/user-interface/shortcut -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/shortcut/shortcut.install b/modules/shortcut/shortcut.install index 9dbab806db37fad6ae22e11494eaadb0ee53355d..60ee6be8ddf02a14072edaded0c989b8056b264c 100644 --- a/modules/shortcut/shortcut.install +++ b/modules/shortcut/shortcut.install @@ -25,6 +25,13 @@ function shortcut_install() { 'weight' => -19, ), ); + // If Drupal is being installed, rebuild the menu before saving the shortcut + // set, to make sure the links defined above can be correctly saved. (During + // installation, the menu might not have been built at all yet, or it might + // have been built but without the node module's links in it.) + if (drupal_installation_attempted()) { + menu_rebuild(); + } shortcut_set_save($shortcut_set); } diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info index 42257dc38a05aa5660d86189e29d4a8cee1fdf8a..b0273281a260fa1c45d090dc71e28289a7a3672f 100644 --- a/modules/simpletest/simpletest.info +++ b/modules/simpletest/simpletest.info @@ -48,8 +48,8 @@ files[] = tests/upgrade/upgrade.taxonomy.test files[] = tests/upgrade/upgrade.upload.test files[] = tests/upgrade/upgrade.user.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info index 701d0a2095e5a41d73420ab682e9b317b3bbcd76..1400405870fe4d093c33b2109fd5e035c747e31d 100644 --- a/modules/simpletest/tests/actions_loop_test.info +++ b/modules/simpletest/tests/actions_loop_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info index a21904619e8657d3775b7467f5eb782d589cc4ca..5aecc800559e386ab3f49fbede9fd3de887bff4b 100644 --- a/modules/simpletest/tests/ajax_forms_test.info +++ b/modules/simpletest/tests/ajax_forms_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info index 5cddb491ef83ba0677582a54a21311fab737d442..82d4fa825cf3931385429b606d84831294c7656c 100644 --- a/modules/simpletest/tests/ajax_test.info +++ b/modules/simpletest/tests/ajax_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info index 602a4fd3474d7ef869cb8a8308997b91c0ae5d92..89e701c8640ddb61704462b445e788681a0d0014 100644 --- a/modules/simpletest/tests/batch_test.info +++ b/modules/simpletest/tests/batch_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info index 97ec552d6382af6cacaac50a138f2fffde3945f6..c11e1baba7bb180531d10e46c0daa720b2b68c95 100644 --- a/modules/simpletest/tests/common_test.info +++ b/modules/simpletest/tests/common_test.info @@ -7,8 +7,8 @@ stylesheets[all][] = common_test.css stylesheets[print][] = common_test.print.css hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info index 7893409d3e9e78ec7ce42a18033833fb0f720771..a6409a2c00ba0c18c4682d16e5296b54f554ad28 100644 --- a/modules/simpletest/tests/database_test.info +++ b/modules/simpletest/tests/database_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 52228081f7a8d8ea6e33cd1588d577be53836dba..44be97a8b9476878a4c1c2496a9f7df1315a2abe 100644 --- a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index a170f8c7207ed3cf066e34aa3300f0bc2c28bef1..255dc9fff1d201326a28d43b52999629284ef03b 100644 --- a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info index e977f7e6034427c394621ae9ff77ebdeec9ca4ed..f9b884e5509663b627a5a5372921bb556aaacb13 100644 --- a/modules/simpletest/tests/entity_cache_test.info +++ b/modules/simpletest/tests/entity_cache_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = entity_cache_test_dependency hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info index 0dfe6eb3d198c397ff4bd5026ce8d37069c7a5bb..ba4aa15f75046e11d2a3824e11f2dc08fe496881 100644 --- a/modules/simpletest/tests/entity_cache_test_dependency.info +++ b/modules/simpletest/tests/entity_cache_test_dependency.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/entity_crud_hook_test.info b/modules/simpletest/tests/entity_crud_hook_test.info index b4d8bedf1aa01fa3fcd3775baf616424f7cbe0eb..174cbf3ebd2e9370a1506453c4c836e008e5ec40 100644 --- a/modules/simpletest/tests/entity_crud_hook_test.info +++ b/modules/simpletest/tests/entity_crud_hook_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/entity_query.test b/modules/simpletest/tests/entity_query.test index d28d5a35c9361fb88ddb92f88462ec90d064f026..0fe8106ef6c141d1425ecb86d65f94c605732667 100644 --- a/modules/simpletest/tests/entity_query.test +++ b/modules/simpletest/tests/entity_query.test @@ -1049,6 +1049,133 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase { $this->assertTrue($pass, t("Can't query the universe.")); } + /** + * Tests field meta conditions. + */ + function testEntityFieldQueryMetaConditions() { + // Make a test field translatable. + $this->fields[0]['translatable'] = TRUE; + field_update_field($this->fields[0]); + field_test_entity_info_translatable('test_entity', TRUE); + drupal_static_reset('field_available_languages'); + + // Create more items with different languages. + $entity = new stdClass(); + $entity->ftid = 1; + $entity->ftvid = 1; + $entity->fttype = 'test_bundle'; + $j = 0; + + foreach (array(LANGUAGE_NONE, 'en') as $langcode) { + for ($i = 0; $i < 4; $i++) { + $entity->{$this->field_names[0]}[$langcode][$i]['value'] = $i + $j; + } + $j += 4; + } + + field_attach_update('test_entity', $entity); + + // Test delta field meta condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldDeltaCondition($this->fields[0], 0, '>'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + ), t('Test with a delta meta condition.')); + + // Test language field meta condition. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!='); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + ), t('Test with a language meta condition.')); + + // Test delta grouping. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'group') + ->fieldDeltaCondition($this->fields[0], 1, '<', 'group'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + ), t('Test with a grouped delta meta condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'group') + ->fieldDeltaCondition($this->fields[0], 1, '>=', 'group'); + $this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta meta condition (empty result set).')); + + // Test language grouping. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', NULL, 'group') + ->fieldLanguageCondition($this->fields[0], 'en', '!=', NULL, 'group'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + ), t('Test with a grouped language meta condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', NULL, 'group') + ->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', NULL, 'group'); + $this->assertEntityFieldQuery($query, array(), t('Test with a grouped language meta condition (empty result set).')); + + // Test delta and language grouping. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language') + ->fieldDeltaCondition($this->fields[0], 1, '<', 'delta', 'language') + ->fieldLanguageCondition($this->fields[0], 'en', '!=', 'delta', 'language'); + $this->assertEntityFieldQuery($query, array( + array('test_entity', 1), + ), t('Test with a grouped delta + language meta condition.')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language') + ->fieldDeltaCondition($this->fields[0], 1, '>=', 'delta', 'language') + ->fieldLanguageCondition($this->fields[0], 'en', '!=', 'delta', 'language'); + $this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, delta condition unsatisifed).')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language') + ->fieldDeltaCondition($this->fields[0], 1, '<', 'delta', 'language') + ->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', 'delta', 'language'); + $this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, language condition unsatisifed).')); + + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity', '=') + ->fieldCondition($this->fields[0], 'value', 0, '=', 'delta', 'language') + ->fieldDeltaCondition($this->fields[0], 1, '>=', 'delta', 'language') + ->fieldLanguageCondition($this->fields[0], LANGUAGE_NONE, '!=', 'delta', 'language'); + $this->assertEntityFieldQuery($query, array(), t('Test with a grouped delta + language meta condition (empty result set, both conditions unsatisifed).')); + + // Test grouping with another field to ensure that grouping cache is reset + // properly. + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'test_entity_bundle', '=') + ->fieldCondition($this->fields[1], 'shape', 'circle', '=', 'delta', 'language') + ->fieldCondition($this->fields[1], 'color', 'blue', '=', 'delta', 'language') + ->fieldDeltaCondition($this->fields[1], 1, '=', 'delta', 'language') + ->fieldLanguageCondition($this->fields[1], LANGUAGE_NONE, '=', 'delta', 'language'); + $this->assertEntityFieldQuery($query, array( + array('test_entity_bundle', 5), + ), t('Test grouping cache.')); + } + /** * Tests the routing feature of EntityFieldQuery. */ diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info index 9a0566d00f27b30122a007cf54b2d0048202f7db..24796d83e55154dd6b9f5dd81869f6fa81f374f2 100644 --- a/modules/simpletest/tests/error_test.info +++ b/modules/simpletest/tests/error_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test index dc12b1b7395371b423abf9e74d1b3352f61100ad..9dbe5464fc1e8b754daeabe24fbcaa8cdb46f344 100644 --- a/modules/simpletest/tests/file.test +++ b/modules/simpletest/tests/file.test @@ -196,10 +196,13 @@ class FileTestCase extends DrupalWebTestCase { * @return * File object. */ - function createFile($filepath = NULL, $contents = NULL, $scheme = 'public') { + function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) { if (!isset($filepath)) { $filepath = $this->randomName(); } + if (!isset($scheme)) { + $scheme = file_default_scheme(); + } $filepath = $scheme . '://' . $filepath; if (!isset($contents)) { @@ -427,7 +430,7 @@ class FileValidatorTest extends DrupalWebTestCase { // Maximum size. if (image_get_toolkit()) { // Copy the image so that the original doesn't get resized. - copy(drupal_realpath('misc/druplicon.png'), 'temporary://druplicon.png'); + copy('misc/druplicon.png', 'temporary://druplicon.png'); $this->image->uri = 'temporary://druplicon.png'; $errors = file_validate_image_resolution($this->image, '10x5'); @@ -437,7 +440,7 @@ class FileValidatorTest extends DrupalWebTestCase { $this->assertTrue($info['width'] <= 10, t('Image scaled to correct width.'), 'File'); $this->assertTrue($info['height'] <= 5, t('Image scaled to correct height.'), 'File'); - drupal_unlink(drupal_realpath('temporary://druplicon.png')); + drupal_unlink('temporary://druplicon.png'); } else { // TODO: should check that the error is returned if no toolkit is available. @@ -531,17 +534,33 @@ class FileUnmanagedSaveDataTest extends FileTestCase { $filepath = file_unmanaged_save_data($contents); $this->assertTrue($filepath, t('Unnamed file saved correctly.')); $this->assertEqual(file_uri_scheme($filepath), file_default_scheme(), t("File was placed in Drupal's files directory.")); - $this->assertEqual($contents, file_get_contents(drupal_realpath($filepath)), t('Contents of the file are correct.')); + $this->assertEqual($contents, file_get_contents($filepath), t('Contents of the file are correct.')); // Provide a filename. $filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE); $this->assertTrue($filepath, t('Unnamed file saved correctly.')); $this->assertEqual('asdf.txt', basename($filepath), t('File was named correctly.')); - $this->assertEqual($contents, file_get_contents(drupal_realpath($filepath)), t('Contents of the file are correct.')); + $this->assertEqual($contents, file_get_contents($filepath), t('Contents of the file are correct.')); $this->assertFilePermissions($filepath, variable_get('file_chmod_file', 0664)); } } +/** + * Tests the file_unmanaged_save_data() function on remote filesystems. + */ +class RemoteFileUnmanagedSaveDataTest extends FileUnmanagedSaveDataTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} + /** * Test the file_save_upload() function. */ @@ -862,6 +881,22 @@ class FileSaveUploadTest extends FileHookTestCase { } } +/** + * Test the file_save_upload() function on remote filesystems. + */ +class RemoteFileSaveUploadTest extends FileSaveUploadTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} + /** * Directory related tests. */ @@ -879,7 +914,7 @@ class FileDirectoryTest extends FileTestCase { */ function testFileCheckDirectoryHandling() { // A directory to operate on. - $directory = file_stream_wrapper_get_instance_by_scheme(file_default_scheme())->getDirectoryPath() . '/' . $this->randomName() . '/' . $this->randomName(); + $directory = file_default_scheme() . '://' . $this->randomName() . '/' . $this->randomName(); $this->assertFalse(is_dir($directory), t('Directory does not exist prior to testing.')); // Non-existent directory. @@ -985,6 +1020,22 @@ class FileDirectoryTest extends FileTestCase { } } +/** + * Directory related tests. + */ +class RemoteFileDirectoryTest extends FileDirectoryTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} + /** * Tests the file_scan_directory() function. */ @@ -1114,6 +1165,21 @@ class FileScanDirectoryTest extends FileTestCase { } } +/** + * Tests the file_scan_directory() function on remote filesystems. + */ +class RemoteFileScanDirectoryTest extends FileScanDirectoryTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} /** * Deletion related tests. @@ -1160,6 +1226,21 @@ class FileUnmanagedDeleteTest extends FileTestCase { } } +/** + * Deletion related tests on remote filesystems. + */ +class RemoteFileUnmanagedDeleteTest extends FileUnmanagedDeleteTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} /** * Deletion related tests. @@ -1237,6 +1318,21 @@ class FileUnmanagedDeleteRecursiveTest extends FileTestCase { } } +/** + * Deletion related tests on remote filesystems. + */ +class RemoteFileUnmanagedDeleteRecursiveTest extends FileUnmanagedDeleteRecursiveTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} /** * Unmanaged move related tests. @@ -1310,6 +1406,21 @@ class FileUnmanagedMoveTest extends FileTestCase { } } +/** + * Unmanaged move related tests on remote filesystems. + */ +class RemoteFileUnmanagedMoveTest extends FileUnmanagedMoveTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} /** * Unmanaged copy related tests. @@ -1399,6 +1510,22 @@ class FileUnmanagedCopyTest extends FileTestCase { } } +/** + * Unmanaged copy related tests on remote filesystems. + */ +class RemoteFileUnmanagedCopyTest extends FileUnmanagedCopyTest { + public static function getInfo() { + $info = parent::getInfo(); + $info['group'] = 'File API (remote)'; + return $info; + } + + function setUp() { + parent::setUp('file_test'); + variable_set('file_default_scheme', 'dummy-remote'); + } +} + /** * Deletion related tests. */ diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info index d258299b08118b454b8e7d44a9913b2760aede8d..ee5e07d6abcb8cd83e5e0bb1f69e493ee1c5d928 100644 --- a/modules/simpletest/tests/file_test.info +++ b/modules/simpletest/tests/file_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = file_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/file_test.module b/modules/simpletest/tests/file_test.module index 2865a1fa3c143665ec99f8d6c89d742c0e91ae26..b3c43e071bb4ae067f10a69d8bc860a43ae40638 100644 --- a/modules/simpletest/tests/file_test.module +++ b/modules/simpletest/tests/file_test.module @@ -37,6 +37,11 @@ function file_test_stream_wrappers() { 'class' => 'DrupalDummyStreamWrapper', 'description' => t('Dummy wrapper for simpletest.'), ), + 'dummy-remote' => array( + 'name' => t('Dummy files (remote)'), + 'class' => 'DrupalDummyRemoteStreamWrapper', + 'description' => t('Dummy wrapper for simpletest (remote).'), + ), ); } @@ -442,3 +447,15 @@ class DrupalDummyStreamWrapper extends DrupalLocalStreamWrapper { } } +/** + * Helper class for testing the stream wrapper registry. + * + * Dummy remote stream wrapper implementation (dummy-remote://). + * + * Basically just the public scheme but not returning a local file for realpath. + */ +class DrupalDummyRemoteStreamWrapper extends DrupalPublicStreamWrapper { + function realpath() { + return FALSE; + } +} diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info index a77a6f5005e4e5b3a8b5f5b3845a9137b7e1fbc9..825f82b8a1a8915c25513e9070c1188436128298 100644 --- a/modules/simpletest/tests/filter_test.info +++ b/modules/simpletest/tests/filter_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info index 29cb7fe844a29674e6a841fe46860adeeed61c7c..d36a3ae9b4b7fa4b1cab3dfe9f6d516622b2ca09 100644 --- a/modules/simpletest/tests/form_test.info +++ b/modules/simpletest/tests/form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info index 7919f23ccb92b9dad045e48d9ed244c496fb4ee5..a4b405d02bbddf15a64e1937060c90b234db8920 100644 --- a/modules/simpletest/tests/image_test.info +++ b/modules/simpletest/tests/image_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/mail.test b/modules/simpletest/tests/mail.test index 8a7b152d9d32eee7ae47c9ef8b5fb9c77f4e0cf1..a6c7b40e5ef3b2eb46fb79be440ddf39ddb3787c 100644 --- a/modules/simpletest/tests/mail.test +++ b/modules/simpletest/tests/mail.test @@ -1,6 +1,7 @@ <?php /** + * @file * Test the Drupal mailing system. */ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { @@ -63,3 +64,355 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { } } +/** + * Unit tests for drupal_html_to_text(). + */ +class DrupalHtmlToTextTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'HTML to text conversion', + 'description' => 'Tests drupal_html_to_text().', + 'group' => 'Mail', + ); + } + + /** + * Converts a string to its PHP source equivalent for display in test messages. + * + * @param $text + * The text string to convert. + * + * @return + * An HTML representation of the text string that, when displayed in a + * browser, represents the PHP source code equivalent of $text. + */ + function stringToHtml($text) { + return '"' . + str_replace( + array("\n", ' '), + array('\n', ' '), + check_plain($text) + ) . '"'; + } + + /** + * Helper function for testing drupal_html_to_text(). + * + * @param $html + * The source HTML string to be converted. + * @param $text + * The expected result of converting $html to text. + * @param $message + * A text message to display in the assertion message. + * @param $allowed_tags + * (optional) An array of allowed tags, or NULL to default to the full + * set of tags supported by drupal_html_to_text(). + */ + function assertHtmlToText($html, $text, $message, $allowed_tags = NULL) { + preg_match_all('/<([a-z0-6]+)/', drupal_strtolower($html), $matches); + $tested_tags = implode(', ', array_unique($matches[1])); + $message .= ' (' . $tested_tags . ')'; + $result = drupal_html_to_text($html, $allowed_tags); + $pass = $this->assertEqual($result, $text, check_plain($message)); + $verbose = 'html = <pre>' . $this->stringToHtml($html) + . '</pre><br />' . 'result = <pre>' . $this->stringToHtml($result) + . '</pre><br />' . 'expected = <pre>' . $this->stringToHtml($text) + . '</pre>'; + $this->verbose($verbose); + if (!$pass) { + $this->pass("Previous test verbose info:<br />$verbose"); + } + } + + /** + * Test all supported tags of drupal_html_to_text(). + */ + function testTags() { + global $base_path, $base_url; + $tests = array( + // @todo Trailing linefeeds should be trimmed. + '<a href = "http://drupal.org">Drupal.org</a>' => "Drupal.org [1]\n\n[1] http://drupal.org\n", + // @todo Footer urls should be absolute. + "<a href = \"$base_path\">Homepage</a>" => "Homepage [1]\n\n[1] $base_url/\n", + '<address>Drupal</address>' => "Drupal\n", + // @todo The <address> tag is currently not supported. + '<address>Drupal</address><address>Drupal</address>' => "DrupalDrupal\n", + '<b>Drupal</b>' => "*Drupal*\n", + // @todo There should be a space between the '>' and the text. + '<blockquote>Drupal</blockquote>' => ">Drupal\n", + '<blockquote>Drupal</blockquote><blockquote>Drupal</blockquote>' => ">Drupal\n>Drupal\n", + '<br />Drupal<br />Drupal<br /><br />Drupal' => "Drupal\nDrupal\nDrupal\n", + '<br/>Drupal<br/>Drupal<br/><br/>Drupal' => "Drupal\nDrupal\nDrupal\n", + // @todo There should be two line breaks before the paragraph. + '<br/>Drupal<br/>Drupal<br/><br/>Drupal<p>Drupal</p>' => "Drupal\nDrupal\nDrupal\nDrupal\n\n", + '<div>Drupal</div>' => "Drupal\n", + // @todo The <div> tag is currently not supported. + '<div>Drupal</div><div>Drupal</div>' => "DrupalDrupal\n", + '<em>Drupal</em>' => "/Drupal/\n", + '<h1>Drupal</h1>' => "======== DRUPAL ==============================================================\n\n", + '<h1>Drupal</h1><p>Drupal</p>' => "======== DRUPAL ==============================================================\n\nDrupal\n\n", + '<h2>Drupal</h2>' => "-------- DRUPAL --------------------------------------------------------------\n\n", + '<h2>Drupal</h2><p>Drupal</p>' => "-------- DRUPAL --------------------------------------------------------------\n\nDrupal\n\n", + '<h3>Drupal</h3>' => ".... Drupal\n\n", + '<h3>Drupal</h3><p>Drupal</p>' => ".... Drupal\n\nDrupal\n\n", + '<h4>Drupal</h4>' => ".. Drupal\n\n", + '<h4>Drupal</h4><p>Drupal</p>' => ".. Drupal\n\nDrupal\n\n", + '<h5>Drupal</h5>' => "Drupal\n\n", + '<h5>Drupal</h5><p>Drupal</p>' => "Drupal\n\nDrupal\n\n", + '<h6>Drupal</h6>' => "Drupal\n\n", + '<h6>Drupal</h6><p>Drupal</p>' => "Drupal\n\nDrupal\n\n", + '<hr />Drupal<hr />' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\n", + '<hr/>Drupal<hr/>' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\n", + '<hr/>Drupal<hr/><p>Drupal</p>' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\nDrupal\n\n", + '<i>Drupal</i>' => "/Drupal/\n", + '<p>Drupal</p>' => "Drupal\n\n", + '<p>Drupal</p><p>Drupal</p>' => "Drupal\n\nDrupal\n\n", + '<strong>Drupal</strong>' => "*Drupal*\n", + // @todo Tables are currently not supported. + '<table><tr><td>Drupal</td><td>Drupal</td></tr><tr><td>Drupal</td><td>Drupal</td></tr></table>' => "DrupalDrupalDrupalDrupal\n", + '<table><tr><td>Drupal</td></tr></table><p>Drupal</p>' => "Drupal\nDrupal\n\n", + // @todo The <u> tag is currently not supported. + '<u>Drupal</u>' => "Drupal\n", + '<ul><li>Drupal</li></ul>' => " * Drupal\n\n", + '<ul><li>Drupal <em>Drupal</em> Drupal</li></ul>' => " * Drupal /Drupal/ Drupal\n\n", + // @todo Lines containing nothing but spaces should be trimmed. + '<ul><li>Drupal</li><li><ol><li>Drupal</li><li>Drupal</li></ol></li></ul>' => " * Drupal\n * 1) Drupal\n 2) Drupal\n \n\n", + '<ul><li>Drupal</li><li><ol><li>Drupal</li></ol></li><li>Drupal</li></ul>' => " * Drupal\n * 1) Drupal\n \n * Drupal\n\n", + '<ul><li>Drupal</li><li>Drupal</li></ul>' => " * Drupal\n * Drupal\n\n", + '<ul><li>Drupal</li></ul><p>Drupal</p>' => " * Drupal\n\nDrupal\n\n", + '<ol><li>Drupal</li></ol>' => " 1) Drupal\n\n", + '<ol><li>Drupal</li><li><ul><li>Drupal</li><li>Drupal</li></ul></li></ol>' => " 1) Drupal\n 2) * Drupal\n * Drupal\n \n\n", + '<ol><li>Drupal</li><li>Drupal</li></ol>' => " 1) Drupal\n 2) Drupal\n\n", + '<ol>Drupal</ol>' => "Drupal\n\n", + '<ol><li>Drupal</li></ol><p>Drupal</p>' => " 1) Drupal\n\nDrupal\n\n", + '<dl><dt>Drupal</dt></dl>' => "Drupal\n\n", + '<dl><dt>Drupal</dt><dd>Drupal</dd></dl>' => "Drupal\n Drupal\n\n", + '<dl><dt>Drupal</dt><dd>Drupal</dd><dt>Drupal</dt><dd>Drupal</dd></dl>' => "Drupal\n Drupal\nDrupal\n Drupal\n\n", + '<dl><dt>Drupal</dt><dd>Drupal</dd></dl><p>Drupal</p>' => "Drupal\n Drupal\n\nDrupal\n\n", + '<dl><dt>Drupal<dd>Drupal</dl>' => "Drupal\n Drupal\n\n", + '<dl><dt>Drupal</dt></dl><p>Drupal</p>' => "Drupal\n\nDrupal\n\n", + // @todo Again, lines containing only spaces should be trimmed. + '<ul><li>Drupal</li><li><dl><dt>Drupal</dt><dd>Drupal</dd><dt>Drupal</dt><dd>Drupal</dd></dl></li><li>Drupal</li></ul>' => " * Drupal\n * Drupal\n Drupal\n Drupal\n Drupal\n \n * Drupal\n\n", + // Tests malformed HTML tags. + '<br>Drupal<br>Drupal' => "Drupal\nDrupal\n", + '<hr>Drupal<hr>Drupal' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\nDrupal\n", + '<ol><li>Drupal<li>Drupal</ol>' => " 1) Drupal\n 2) Drupal\n\n", + '<ul><li>Drupal <em>Drupal</em> Drupal</ul></ul>' => " * Drupal /Drupal/ Drupal\n\n", + '<ul><li>Drupal<li>Drupal</ol>' => " * Drupal\n * Drupal\n\n", + '<ul><li>Drupal<li>Drupal</ul>' => " * Drupal\n * Drupal\n\n", + '<ul>Drupal</ul>' => "Drupal\n\n", + 'Drupal</ul></ol></dl><li>Drupal' => "Drupal\n * Drupal\n", + '<dl>Drupal</dl>' => "Drupal\n\n", + '<dl>Drupal</dl><p>Drupal</p>' => "Drupal\n\nDrupal\n\n", + '<dt>Drupal</dt>' => "Drupal\n", + // Tests some unsupported HTML tags. + '<html>Drupal</html>' => "Drupal\n", + // @todo Perhaps the contents of <script> tags should be dropped. + '<script type="text/javascript">Drupal</script>' => "Drupal\n", + ); + + foreach ($tests as $html => $text) { + $this->assertHtmlToText($html, $text, 'Supported tags'); + } + } + + /** + * Test $allowed_tags argument of drupal_html_to_text(). + */ + function testDrupalHtmlToTextArgs() { + // The second parameter of drupal_html_to_text() overrules the allowed tags. + $this->assertHtmlToText( + 'Drupal <b>Drupal</b> Drupal', + "Drupal *Drupal* Drupal\n", + 'Allowed <b> tag found', + array('b') + ); + $this->assertHtmlToText( + 'Drupal <h1>Drupal</h1> Drupal', + "Drupal Drupal Drupal\n", + 'Disallowed <h1> tag not found', + array('b') + ); + + $this->assertHtmlToText( + 'Drupal <p><em><b>Drupal</b></em><p> Drupal', + "Drupal Drupal Drupal\n", + 'Disallowed <p>, <em>, and <b> tags not found', + array('a', 'br', 'h1') + ); + + $this->assertHtmlToText( + '<html><body>Drupal</body></html>', + "Drupal\n", + 'Unsupported <html> and <body> tags not found', + array('html', 'body') + ); + } + + /** + * Test that whitespace is collapsed. + */ + function testDrupalHtmltoTextCollapsesWhitespace() { + $input = "<p>Drupal Drupal\n\nDrupal<pre>Drupal Drupal\n\nDrupal</pre>Drupal Drupal\n\nDrupal</p>"; + // @todo The whitespace should be collapsed. + $collapsed = "Drupal Drupal\n\nDrupalDrupal Drupal\n\nDrupalDrupal Drupal\n\nDrupal\n\n"; + $this->assertHtmlToText( + $input, + $collapsed, + 'Whitespace is collapsed', + array('p') + ); + } + + /** + * Test that text separated by block-level tags in HTML get separated by + * (at least) a newline in the plaintext version. + */ + function testDrupalHtmlToTextBlockTagToNewline() { + $input = '[text]' + . '<blockquote>[blockquote]</blockquote>' + . '<br />[br]' + . '<dl><dt>[dl-dt]</dt>' + . '<dt>[dt]</dt>' + . '<dd>[dd]</dd>' + . '<dd>[dd-dl]</dd></dl>' + . '<h1>[h1]</h1>' + . '<h2>[h2]</h2>' + . '<h3>[h3]</h3>' + . '<h4>[h4]</h4>' + . '<h5>[h5]</h5>' + . '<h6>[h6]</h6>' + . '<hr />[hr]' + . '<ol><li>[ol-li]</li>' + . '<li>[li]</li>' + . '<li>[li-ol]</li></ol>' + . '<p>[p]</p>' + . '<ul><li>[ul-li]</li>' + . '<li>[li-ul]</li></ul>' + . '[text]'; + $output = drupal_html_to_text($input); + $pass = $this->assertFalse( + preg_match('/\][^\n]*\[/s', $output), + 'Block-level HTML tags should force newlines' + ); + if (!$pass) { + $this->verbose($this->stringToHtml($output)); + } + $output_upper = drupal_strtoupper($output); + $upper_input = drupal_strtoupper($input); + $upper_output = drupal_html_to_text($upper_input); + $pass = $this->assertEqual( + $upper_output, + $output_upper, + 'Tag recognition should be case-insensitive' + ); + if (!$pass) { + $this->verbose( + $upper_output + . '<br />should be equal to <br />' + . $output_upper + ); + } + } + + /** + * Test that headers are properly separated from surrounding text. + */ + function testHeaderSeparation() { + $html = 'Drupal<h1>Drupal</h1>Drupal'; + // @todo There should be more space above the header than below it. + $text = "Drupal\n======== DRUPAL ==============================================================\n\nDrupal\n"; + $this->assertHtmlToText($html, $text, + 'Text before and after <h1> tag'); + $html = '<p>Drupal</p><h1>Drupal</h1>Drupal'; + // @todo There should be more space above the header than below it. + $text = "Drupal\n\n======== DRUPAL ==============================================================\n\nDrupal\n"; + $this->assertHtmlToText($html, $text, + 'Paragraph before and text after <h1> tag'); + $html = 'Drupal<h1>Drupal</h1><p>Drupal</p>'; + // @todo There should be more space above the header than below it. + $text = "Drupal\n======== DRUPAL ==============================================================\n\nDrupal\n\n"; + $this->assertHtmlToText($html, $text, + 'Text before and paragraph after <h1> tag'); + $html = '<p>Drupal</p><h1>Drupal</h1><p>Drupal</p>'; + $text = "Drupal\n\n======== DRUPAL ==============================================================\n\nDrupal\n\n"; + $this->assertHtmlToText($html, $text, + 'Paragraph before and after <h1> tag'); + } + + /** + * Test that footnote references are properly generated. + */ + function testFootnoteReferences() { + global $base_path, $base_url; + $source = '<a href="http://www.example.com/node/1">Host and path</a>' + . '<br /><a href="http://www.example.com">Host, no path</a>' + . '<br /><a href="' . $base_path . 'node/1">Path, no host</a>' + . '<br /><a href="node/1">Relative path</a>'; + // @todo Footnote urls should be absolute. + $tt = "Host and path [1]" + . "\nHost, no path [2]" + // @todo The following two references should be combined. + . "\nPath, no host [3]" + . "\nRelative path [4]" + . "\n" + . "\n[1] http://www.example.com/node/1" + . "\n[2] http://www.example.com" + // @todo The following two references should be combined. + . "\n[3] $base_url/node/1" + . "\n[4] node/1\n"; + $this->assertHtmlToText($source, $tt, 'Footnotes'); + } + + /** + * Test that combinations of paragraph breaks, line breaks, linefeeds, + * and spaces are properly handled. + */ + function testDrupalHtmlToTextParagraphs() { + $tests = array(); + $tests[] = array( + 'html' => "<p>line 1<br />\nline 2<br />line 3\n<br />line 4</p><p>paragraph</p>", + // @todo Trailing line breaks should be trimmed. + 'text' => "line 1\nline 2\nline 3\nline 4\n\nparagraph\n\n", + ); + $tests[] = array( + 'html' => "<p>line 1<br /> line 2</p> <p>line 4<br /> line 5</p> <p>0</p>", + // @todo Trailing line breaks should be trimmed. + 'text' => "line 1\nline 2\n\nline 4\nline 5\n\n0\n\n", + ); + foreach ($tests as $test) { + $this->assertHtmlToText($test['html'], $test['text'], 'Paragraph breaks'); + } + } + + /** + * Tests that drupal_html_to_text() wraps before 1000 characters. + * + * RFC 3676 says, "The Text/Plain media type is the lowest common + * denominator of Internet email, with lines of no more than 998 characters." + * + * RFC 2046 says, "SMTP [RFC-821] allows a maximum of 998 octets before the + * next CRLF sequence." + * + * RFC 821 says, "The maximum total length of a text line including the + * <CRLF> is 1000 characters." + */ + function testVeryLongLineWrap() { + $input = 'Drupal<br /><p>' . str_repeat('x', 2100) . '</><br />Drupal'; + $output = drupal_html_to_text($input); + // This awkward construct comes from includes/mail.inc lines 8-13. + $eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS); + // We must use strlen() rather than drupal_strlen() in order to count + // octets rather than characters. + $line_length_limit = 1000 - drupal_strlen($eol); + $maximum_line_length = 0; + foreach (explode($eol, $output) as $line) { + // We must use strlen() rather than drupal_strlen() in order to count + // octets rather than characters. + $maximum_line_length = max($maximum_line_length, strlen($line . $eol)); + } + $verbose = 'Maximum line length found was ' . $maximum_line_length . ' octets.'; + // @todo This should assert that $maximum_line_length <= 1000. + $this->pass($verbose); + } +} diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test index 5642fcee0e07edf0f24ddcde7d6c23589939b413..c0a79d4c233be96b63d01964f17984682ee199b7 100644 --- a/modules/simpletest/tests/menu.test +++ b/modules/simpletest/tests/menu.test @@ -394,6 +394,14 @@ class MenuRouterTestCase extends DrupalWebTestCase { $this->assertEqual($link['plid'], $plid, t('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid))); } + /** + * Test menu_get_item() with empty ancestors. + */ + function testMenuGetItemNoAncestors() { + variable_set('menu_masks', array()); + $this->drupalGet(''); + } + /** * Test menu_set_item(). */ diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info index 480b741a7351dfc6cc108e735bc7354fc071e425..87728df6765dc77449ce889b48d7426b5b419f3a 100644 --- a/modules/simpletest/tests/menu_test.info +++ b/modules/simpletest/tests/menu_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info index 328307afc1adf084ff54489ccf34506fd532bdf6..c7a7aaa30aa295b1f0ec3fb4dfd4c2f8ea6deabb 100644 --- a/modules/simpletest/tests/module_test.info +++ b/modules/simpletest/tests/module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info index 5fb5dd04be55a1ce08b04c1d1f055dcf54cb2fb9..f0de5df8d4dc260fa2ede4dc7fa4502b9da5521f 100644 --- a/modules/simpletest/tests/requirements1_test.info +++ b/modules/simpletest/tests/requirements1_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/requirements2_test.info b/modules/simpletest/tests/requirements2_test.info index 1952c423c930cd82125da3cec33c0defddcc6ad5..4386779ab6b545e7ef79b784756930f50e270180 100644 --- a/modules/simpletest/tests/requirements2_test.info +++ b/modules/simpletest/tests/requirements2_test.info @@ -7,8 +7,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info index 38e28a635ab8f67ed7dc3596390a9cd40bcd71f9..acdb06f547854a5f6d0e6c200bba1b3b73854d2d 100644 --- a/modules/simpletest/tests/session_test.info +++ b/modules/simpletest/tests/session_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info index c6353303ae2831da000ab0027b17b4a151006af6..df4cf74dcac83b709b69454b50944ea664a916d5 100644 --- a/modules/simpletest/tests/system_dependencies_test.info +++ b/modules/simpletest/tests/system_dependencies_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = _missing_dependency -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/system_test.info b/modules/simpletest/tests/system_test.info index 9e1bed97a7a8a925a1453ce840d020656967431c..a4d29cd13bb9d01f81b2d28d0592a93df3c270e1 100644 --- a/modules/simpletest/tests/system_test.info +++ b/modules/simpletest/tests/system_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = system_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info index 376a5bb322b47bd5e82da96296728f7ba2feb81e..e3e66e0ff47abd39dd7139cfefc91bcd77edf41c 100644 --- a/modules/simpletest/tests/taxonomy_test.info +++ b/modules/simpletest/tests/taxonomy_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = taxonomy -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info index 721e469aad250cb1eff6dc3d5e0db0848cca555a..bd3a0bf86bdade49042998361f1a32886275b045 100644 --- a/modules/simpletest/tests/theme_test.info +++ b/modules/simpletest/tests/theme_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info index da04d6c10b77a324fdb81bf3435f073dffd1a9e5..808c126e24ccfe1235aa3f8c77018a69ce8a4949 100644 --- a/modules/simpletest/tests/update_test_1.info +++ b/modules/simpletest/tests/update_test_1.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info index da04d6c10b77a324fdb81bf3435f073dffd1a9e5..808c126e24ccfe1235aa3f8c77018a69ce8a4949 100644 --- a/modules/simpletest/tests/update_test_2.info +++ b/modules/simpletest/tests/update_test_2.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info index da04d6c10b77a324fdb81bf3435f073dffd1a9e5..808c126e24ccfe1235aa3f8c77018a69ce8a4949 100644 --- a/modules/simpletest/tests/update_test_3.info +++ b/modules/simpletest/tests/update_test_3.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/upgrade/drupal-6.menu.database.php b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php index d10c4eec41381912a3e1fb08af2bcc087ce4fc5a..f5c588af7c9aa046698cc9eb9aeb96a4a3cbd5df 100644 --- a/modules/simpletest/tests/upgrade/drupal-6.menu.database.php +++ b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php @@ -7,4 +7,123 @@ db_insert('variable')->fields(array( 'name' => 'menu_default_node_menu', 'value' => 's:15:"secondary-links";', )) +->values(array( + 'name' => 'menu_primary_links_source', + 'value' => 's:15:"secondary-links";', +)) +->values(array( + 'name' => 'menu_secondary_links_source', + 'value' => 's:13:"primary-links";', +)) +->execute(); + +// Add some links to the menus. +db_insert('menu_links')->fields(array( + 'menu_name', + 'mlid', + 'plid', + 'link_path', + 'router_path', + 'link_title', + 'options', + 'module', + 'hidden', + 'external', + 'has_children', + 'expanded', + 'weight', + 'depth', + 'customized', + 'p1', + 'p2', + 'p3', + 'p4', + 'p5', + 'p6', + 'p7', + 'p8', + 'p9', + 'updated', +)) +->values(array( + 'menu_name' => 'navigation', + 'mlid' => '201', + 'plid' => '0', + 'link_path' => 'node/add', + 'router_path' => 'node/add', + 'link_title' => 'nodeadd-navigation', + 'options' => 'a:0:{}', + 'module' => 'menu', + 'hidden' => '0', + 'external' => '0', + 'has_children' => '1', + 'expanded' => '0', + 'weight' => '1', + 'depth' => '1', + 'customized' => '0', + 'p1' => '201', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', +)) +->values(array( + 'menu_name' => 'primary-links', + 'mlid' => '204', + 'plid' => '0', + 'link_path' => 'node/add', + 'router_path' => 'node/add', + 'link_title' => 'nodeadd-primary', + 'options' => 'a:0:{}', + 'module' => 'menu', + 'hidden' => '0', + 'external' => '0', + 'has_children' => '1', + 'expanded' => '0', + 'weight' => '1', + 'depth' => '1', + 'customized' => '0', + 'p1' => '204', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', +)) +->values(array( + 'menu_name' => 'secondary-links', + 'mlid' => '205', + 'plid' => '0', + 'link_path' => 'node/add', + 'router_path' => 'node/add', + 'link_title' => 'nodeadd-secondary', + 'options' => 'a:0:{}', + 'module' => 'menu', + 'hidden' => '0', + 'external' => '0', + 'has_children' => '1', + 'expanded' => '0', + 'weight' => '1', + 'depth' => '1', + 'customized' => '0', + 'p1' => '205', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', +)) ->execute(); diff --git a/modules/simpletest/tests/upgrade/upgrade.menu.test b/modules/simpletest/tests/upgrade/upgrade.menu.test index beb20277ac52518cc9d1767850a6394e5a38d8e3..5a17a1947e7bd7077e341cfa4965ac29f85aa0c8 100644 --- a/modules/simpletest/tests/upgrade/upgrade.menu.test +++ b/modules/simpletest/tests/upgrade/upgrade.menu.test @@ -29,16 +29,50 @@ class MenuUpgradePathTestCase extends UpgradePathTestCase { public function testMenuUpgrade() { $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); - // Test the migration of "Default menu for content" setting to individual node types. - $this->drupalGet("admin/structure/types/manage/page/edit"); + // Test the migration of "Default menu for content" setting to individual + // node types. + $this->drupalGet('admin/structure/types/manage/page/edit'); $this->assertNoFieldChecked('edit-menu-options-management', 'Management menu is not selected as available menu'); $this->assertNoFieldChecked('edit-menu-options-navigation', 'Navigation menu is not selected as available menu'); - $this->assertNoFieldChecked('edit-menu-options-primary-links', 'Primary Links menu is not selected as available menu'); - $this->assertFieldChecked('edit-menu-options-secondary-links', 'Secondary Links menu is selected as available menu'); + $this->assertNoFieldChecked('edit-menu-options-main-menu', 'Main menu is not selected as available menu'); + $this->assertFieldChecked('edit-menu-options-secondary-menu', 'Secondary menu is selected as available menu'); $this->assertNoFieldChecked('edit-menu-options-user-menu', 'User menu is not selected as available menu'); - $this->assertOptionSelected('edit-menu-parent', 'secondary-links:0', 'Secondary links is selected as default parent item'); + $this->assertOptionSelected('edit-menu-parent', 'secondary-menu:0', 'Secondary menu is selected as default parent item'); $this->assertEqual(variable_get('menu_default_node_menu'), NULL, 'Redundant variable menu_default_node_menu has been removed'); + // Verify Primary/Secondary Links have been renamed. + $this->drupalGet('admin/structure/menu'); + $this->assertNoLinkByHref('admin/structure/menu/manage/primary-links'); + $this->assertLinkByHref('admin/structure/menu/manage/main-menu'); + $this->assertNoLinkByHref('admin/structure/menu/manage/secondary-links'); + $this->assertLinkByHref('admin/structure/menu/manage/secondary-menu'); + + // Verify the existence of all system-defined (default) menus. + foreach (menu_list_system_menus() as $menu_name => $title) { + $this->assertLinkByHref('admin/structure/menu/manage/' . $menu_name, 0, 'Found default menu: ' . $title); + } + + // Verify a few known links are still present, plus the ones created here. + $test_menus = array( + 'navigation' => array('Add content', 'nodeadd-navigation'), + 'management' => array('Administration', 'Account settings'), + 'user-menu' => array('My account', 'Log out'), + 'main-menu' => array('nodeadd-primary'), + 'secondary-menu' => array('nodeadd-secondary'), + ); + + foreach ($test_menus as $menu_name => $links) { + $this->drupalGet('admin/structure/menu/manage/' . $menu_name); + $this->assertResponse(200, 'Access menu management for ' . $menu_name); + foreach ($links as $link_text) { + $this->assertLink(t($link_text)); + } + } + + // Check the "source for primary/secondary links" setting. + $this->drupalGet('admin/structure/menu/settings'); + $this->assertOptionSelected('edit-menu-main-links-source', 'secondary-menu'); + $this->assertOptionSelected('edit-menu-secondary-links-source', 'main-menu'); } } diff --git a/modules/simpletest/tests/upgrade/upgrade.node.test b/modules/simpletest/tests/upgrade/upgrade.node.test index 163dbef5e9db58a71ae0c3aa057b29639ccffa7e..cd44790c72883ca4b0bd66ba1b47b14c68f7c8b9 100644 --- a/modules/simpletest/tests/upgrade/upgrade.node.test +++ b/modules/simpletest/tests/upgrade/upgrade.node.test @@ -27,6 +27,11 @@ class NodeBodyUpgradePathTestCase extends UpgradePathTestCase { */ public function testNodeBodyUpgrade() { $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + + $instance = field_info_instance('node', 'body', 'story'); + $this->assertIdentical($instance['required'], 0, 'The required setting was preserved during the upgrade path.'); + $this->assertTrue($instance['description'], 'The description was preserved during the upgrade path'); + $this->drupalGet("content/1263769200"); $this->assertText('node body (broken) - 37'); diff --git a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test index dadb98e5acd994d2966cd59af6d06152ad905666..37de087752188e0e26abaef25d81c8fe692ba82e 100644 --- a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test +++ b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test @@ -68,6 +68,12 @@ class UpgradePathTaxonomyTestCase extends UpgradePathTestCase { sort($inst_keys); $this->assertEqual($voc_keys, $inst_keys, t('Node type page has instances for every vocabulary.')); + // Ensure instance variables are getting through. + foreach ($instances as $instance) { + $this->assertTrue(isset($instance['required']), 'The required setting was preserved during the upgrade path.'); + $this->assertTrue($instance['description'], 'The description was preserved during the upgrade path'); + } + // Node type 'story' was not explicitly in $vocabulary->nodes but // each node of type 'story' was associated to one or more terms. // Check that the node type 'story' has been associated only to diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info index ce07be55efbbca3e062cd7e196cbde30615dd65a..2bcfc981d4603ead2040c5114fae815bf6161ec0 100644 --- a/modules/simpletest/tests/url_alter_test.info +++ b/modules/simpletest/tests/url_alter_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info index e30d855d784999068716e9a0de250512ce869c58..ac6df954a4e9705bdf3bf6f065ed9e2cfdaeafa7 100644 --- a/modules/simpletest/tests/xmlrpc_test.info +++ b/modules/simpletest/tests/xmlrpc_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info index 9746a7926433aa41ad049e5dd29b8800ed7376c4..02c27eae191b89618dcf1b40b0b01db40e564853 100644 --- a/modules/statistics/statistics.info +++ b/modules/statistics/statistics.info @@ -6,8 +6,8 @@ core = 7.x files[] = statistics.test configure = admin/config/system/statistics -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info index e8806a9e263eece15b68b8883aba095201cb4114..9183fe4ee09ff41cc02164e712de836e6ab39231 100644 --- a/modules/syslog/syslog.info +++ b/modules/syslog/syslog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = syslog.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/system/image.gd.inc b/modules/system/image.gd.inc index a3f76d4a629f385ecfd1592dcb702734033ed86c..39f86dc30e6cbbc980a1a5adc24f3a53350139e1 100644 --- a/modules/system/image.gd.inc +++ b/modules/system/image.gd.inc @@ -346,7 +346,7 @@ function image_gd_create_tmp(stdClass $image, $width, $height) { */ function image_gd_get_info(stdClass $image) { $details = FALSE; - $data = getimagesize(drupal_realpath($image->source)); + $data = getimagesize($image->source); if (isset($data) && is_array($data)) { $extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png'); diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 9e7d69dd3aed5d6a6a6abecef02fa05c3b1157a2..0d3a8d7a8140a8a94077f480919a4acf643d791d 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -1757,7 +1757,7 @@ function system_file_system_settings() { '#title' => t('Private file system path'), '#default_value' => variable_get('file_private_path', ''), '#maxlength' => 255, - '#description' => t('A local file system path where private files will be stored. This directory must exist and be writable by Drupal. This directory should not be accessible over the web.'), + '#description' => t('An existing local file system path for storing private files. It should be writable by Drupal and not accessible over the web. See the online handbook for <a href="@handbook">more information about securing private files</a>.', array('@handbook' => 'http://drupal.org/handbook/modules/file')), '#after_build' => array('system_check_directory'), ); diff --git a/modules/system/system.api.php b/modules/system/system.api.php index 4005389004dd95c707db56afc67b3ec8da41a36c..179f1231162d2c03b38aa9ec71dc8aa015d8cb12 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -1972,8 +1972,8 @@ function hook_permission() { * containing information about the hook. Each array may contain the * following elements: * - variables: (required if "render element" not present) An array of - * variables that this theme hook uses. This value allows the theme layer to - * properly utilize templates. Each array key represents the name of the + * variables that this theme hook uses. This value allows the theme layer + * to properly utilize templates. Each array key represents the name of the * variable and the value will be used as the default value if it is not * given when theme() is called. Template implementations receive these * arguments as variables in the template file. Function implementations @@ -1989,20 +1989,20 @@ function hook_permission() { * preprocess function (as needed) is actually loaded; this makes it * possible to split theme functions out into separate files quite easily. * - path: Override the path of the file to be used. Ordinarily the module or - * theme path will be used, but if the file will not be in the default path, - * include it here. This path should be relative to the Drupal root + * theme path will be used, but if the file will not be in the default + * path, include it here. This path should be relative to the Drupal root * directory. - * - template: If specified, this theme implementation is a template, and this - * is the template file without an extension. Do not put .tpl.php on this - * file; that extension will be added automatically by the default rendering - * engine (which is PHPTemplate). If 'path', above, is specified, the - * template should also be in this path. - * - function: If specified, this will be the function name to invoke for this - * implementation. If neither file nor function is specified, a default - * function name will be assumed. For example, if a module registers - * the 'node' theme hook, 'theme_node' will be assigned to its function. - * If the chameleon theme registers the node hook, it will be assigned - * 'chameleon_node' as its function. + * - template: If specified, this theme implementation is a template, and + * this is the template file without an extension. Do not put .tpl.php on + * this file; that extension will be added automatically by the default + * rendering engine (which is PHPTemplate). If 'path', above, is specified, + * the template should also be in this path. + * - function: If specified, this will be the function name to invoke for + * this implementation. If neither 'template' nor 'function' is specified, + * a default function name will be assumed. For example, if a module + * registers the 'node' theme hook, 'theme_node' will be assigned to its + * function. If the chameleon theme registers the node hook, it will be + * assigned 'chameleon_node' as its function. * - pattern: A regular expression pattern to be used to allow this theme * implementation to have a dynamic name. The convention is to use __ to * differentiate the dynamic portion of the theme. For example, to allow @@ -2017,11 +2017,11 @@ function hook_permission() { * a theme this will be filled in as phptemplate_preprocess and * phptemplate_preprocess_HOOK as well as themename_preprocess and * themename_preprocess_HOOK. - * - override preprocess functions: Set to TRUE when a theme does NOT want the - * standard preprocess functions to run. This can be used to give a theme - * FULL control over how variables are set. For example, if a theme wants - * total control over how certain variables in the page.tpl.php are set, - * this can be set to true. Please keep in mind that when this is used + * - override preprocess functions: Set to TRUE when a theme does NOT want + * the standard preprocess functions to run. This can be used to give a + * theme FULL control over how variables are set. For example, if a theme + * wants total control over how certain variables in the page.tpl.php are + * set, this can be set to true. Please keep in mind that when this is used * by a theme, that theme becomes responsible for making sure necessary * variables are set. * - type: (automatically derived) Where the theme hook is defined: @@ -2687,22 +2687,21 @@ function hook_file_delete($file) { * NULL. * * @see file_download() - * @see upload_file_download() */ function hook_file_download($uri) { // Check if the file is controlled by the current module. if (!file_prepare_directory($uri)) { $uri = FALSE; } - $result = db_query("SELECT f.* FROM {file_managed} f INNER JOIN {upload} u ON f.fid = u.fid WHERE uri = :uri", array('uri' => $uri)); - foreach ($result as $file) { - if (!user_access('view uploaded files')) { + if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) { + if (!user_access('access user profiles')) { + // Access to the file is denied. return -1; } - return array( - 'Content-Type' => $file->filemime, - 'Content-Length' => $file->filesize, - ); + else { + $info = image_get_info($uri); + return array('Content-Type' => $info['mime_type']); + } } } diff --git a/modules/system/system.info b/modules/system/system.info index fbb452feb49454a4984ba53a20ab195cb85071e8..a3c517cb08bfdead0d496202a0f4478c4df09bad 100644 --- a/modules/system/system.info +++ b/modules/system/system.info @@ -12,8 +12,8 @@ files[] = system.test required = TRUE configure = admin/config/system -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/system/system.install b/modules/system/system.install index e067444604dce39df4909e36e21847f6f758a748..e55c7cf3aa7e6d7f8c6fe2e8c0c31dca293a6e46 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -2263,6 +2263,9 @@ function system_update_7042() { // provided any meaningful unique constraint ('pid' is a primary key). db_add_index('url_alias', 'source_language_pid', array('source', 'language', 'pid')); db_add_index('url_alias', 'alias_language_pid', array('alias', 'language', 'pid')); + + // Now that the URL aliases are correct, we can rebuild the whitelist. + drupal_path_alias_whitelist_rebuild(); } /** diff --git a/modules/system/system.module b/modules/system/system.module index c3b4a1e3915e71e6f4116b5e799d787ea9234c6f..8fc0ffa4309ad01d428f7dfebcf0eeda22099071 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -3018,6 +3018,7 @@ function system_cron() { ->fields(array( 'expire' => 0, )) + ->condition('expire', 0, '<>') ->condition('expire', REQUEST_TIME, '<') ->execute(); } diff --git a/modules/system/system.test b/modules/system/system.test index 0fe0bc05718dd24e93dab0257c4cda1bbfb5b919..8a29ce531d8d89cf988df014278fc055a90ea44e 100644 --- a/modules/system/system.test +++ b/modules/system/system.test @@ -1824,7 +1824,6 @@ class TokenReplaceTestCase extends DrupalWebTestCase { // Set a few site variables. variable_set('site_name', '<strong>Drupal<strong>'); variable_set('site_slogan', '<blink>Slogan</blink>'); - variable_set('site_mission', '<em>Mission</em>'); // Generate and test sanitized tokens. $tests = array(); diff --git a/modules/system/system.tokens.inc b/modules/system/system.tokens.inc index 27d7dfdb0745023056f0060513376fd553d09d4f..56ddf298804a9a24702864fdfc5a98c07bdd9afa 100644 --- a/modules/system/system.tokens.inc +++ b/modules/system/system.tokens.inc @@ -88,10 +88,6 @@ function system_token_info() { 'name' => t("File name"), 'description' => t("The name of the file on disk."), ); - $file['description'] = array( - 'name' => t("Description"), - 'description' => t("An optional human-readable description of the file."), - ); $file['path'] = array( 'name' => t("Path"), 'description' => t("The location of the file relative to Drupal root."), @@ -228,10 +224,6 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a $replacements[$original] = $sanitize ? check_plain($file->filename) : $file->filename; break; - case 'description': - $replacements[$original] = $sanitize ? check_plain($file->description) : $file->description; - break; - case 'path': $replacements[$original] = $sanitize ? check_plain($file->uri) : $file->uri; break; @@ -255,7 +247,8 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a case 'owner': $account = user_load($file->uid); - $replacements[$original] = $sanitize ? check_plain($account->name) : $account->name; + $name = format_username($account); + $replacements[$original] = $sanitize ? check_plain($name) : $name; break; } } diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc index d83f5d367536532fd6e762ab5db1f6d10044c8e8..a236cfed1d827de480c4f87dd386b08e2ca86200 100644 --- a/modules/taxonomy/taxonomy.admin.inc +++ b/modules/taxonomy/taxonomy.admin.inc @@ -209,7 +209,7 @@ function taxonomy_form_vocabulary_validate($form, &$form_state) { * @see taxonomy_form_vocabulary_validate() */ function taxonomy_form_vocabulary_submit($form, &$form_state) { - if ($form_state['clicked_button']['#value'] == t('Delete')) { + if ($form_state['triggering_element']['#value'] == t('Delete')) { // Rebuild the form to confirm vocabulary deletion. $form_state['rebuild'] = TRUE; $form_state['confirm_delete'] = TRUE; @@ -434,7 +434,7 @@ function taxonomy_overview_terms($form, &$form_state, $vocabulary) { * @see taxonomy_overview_terms() */ function taxonomy_overview_terms_submit($form, &$form_state) { - if ($form_state['clicked_button']['#value'] == t('Reset to alphabetical')) { + if ($form_state['triggering_element']['#value'] == t('Reset to alphabetical')) { // Execute the reset action. if ($form_state['values']['reset_alphabetical'] === TRUE) { return taxonomy_vocabulary_confirm_reset_alphabetical_submit($form, $form_state); @@ -674,9 +674,6 @@ function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary = if (isset($form_state['confirm_delete'])) { return array_merge($form, taxonomy_term_confirm_delete($form, $form_state, $term->tid)); } - elseif (isset($form_state['confirm_parents'])) { - return array_merge($form, taxonomy_term_confirm_parents($form, $form_state, $vocabulary)); - } $form['name'] = array( '#type' => 'textfield', @@ -801,7 +798,7 @@ function taxonomy_form_term_validate($form, &$form_state) { * @see taxonomy_form_term() */ function taxonomy_form_term_submit($form, &$form_state) { - if ($form_state['clicked_button']['#value'] == t('Delete')) { + if ($form_state['triggering_element']['#value'] == t('Delete')) { // Execute the term deletion. if ($form_state['values']['delete'] === TRUE) { return taxonomy_term_confirm_delete_submit($form, $form_state); @@ -811,12 +808,6 @@ function taxonomy_form_term_submit($form, &$form_state) { $form_state['confirm_delete'] = TRUE; return; } - // Rebuild the form to confirm enabling multiple parents. - elseif ($form_state['clicked_button']['#value'] == t('Save') && count($form_state['values']['parent']) > 1 && $form['#vocabulary']->hierarchy < 2) { - $form_state['rebuild'] = TRUE; - $form_state['confirm_parents'] = TRUE; - return; - } $term = taxonomy_form_term_submit_build_taxonomy_term($form, $form_state); @@ -872,25 +863,6 @@ function taxonomy_form_term_submit_build_taxonomy_term($form, &$form_state) { return $term; } -/** - * Form builder for the confirmation of multiple term parents. - * - * @ingroup forms - * @see taxonomy_form_term() - */ -function taxonomy_term_confirm_parents($form, &$form_state, $vocabulary) { - foreach (element_children($form_state['values']) as $key) { - $form[$key] = array( - '#type' => 'value', - '#value' => $form_state['values'][$key], - ); - } - $question = t('Set multiple term parents?'); - $description = '<p>' . t("Adding multiple parents to a term will cause the %vocabulary vocabulary to look for multiple parents on every term. Because multiple parents are not supported when using the drag and drop outline interface, drag and drop will be disabled if you enable this option. If you choose to have multiple parents, you will only be able to set parents by using the term edit form.", array('%vocabulary' => $vocabulary->name)) . '</p>'; - $description .= '<p>' . t("You may re-enable the drag and drop interface at any time by reducing multiple parents to a single parent for the terms in this vocabulary.") . '</p>'; - return confirm_form($form, $question, drupal_get_destination(), $description, t('Set multiple parents')); -} - /** * Form builder for the term delete form. * diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info index 2dea11899e2eb9a368fad542fc62a80073a45d6c..231550d224aaf2201a97b4b34c439c79b1af4648 100644 --- a/modules/taxonomy/taxonomy.info +++ b/modules/taxonomy/taxonomy.info @@ -8,8 +8,8 @@ files[] = taxonomy.module files[] = taxonomy.test configure = admin/structure/taxonomy -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install index 56b7e01c6e95c734145dcd083642731bd44d3de2..68fbc7804a99922d6b00b432c6c9b7c5b3c48686 100644 --- a/modules/taxonomy/taxonomy.install +++ b/modules/taxonomy/taxonomy.install @@ -438,6 +438,7 @@ function taxonomy_update_7004() { 'entity_type' => 'node', 'settings' => array(), 'description' => $vocabulary->help, + 'required' => $vocabulary->required, 'widget' => array(), 'display' => array( 'default' => array( diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc index 3aed29011eabafe229809e4570a2cbd32722919c..0cca252d7e2a7d512ac15036ab03f8214f569502 100644 --- a/modules/taxonomy/taxonomy.pages.inc +++ b/modules/taxonomy/taxonomy.pages.inc @@ -110,7 +110,7 @@ function taxonomy_autocomplete($field_name, $tags_typed = '') { ->execute() ->fetchAllKeyed(); - $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : ''; + $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : ''; $term_matches = array(); foreach ($tags_return as $tid => $name) { @@ -119,9 +119,7 @@ function taxonomy_autocomplete($field_name, $tags_typed = '') { if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { $n = '"' . str_replace('"', '""', $name) . '"'; } - else { - $term_matches[$prefix . $n] = check_plain($name); - } + $term_matches[$prefix . $n] = check_plain($name); } } diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index 97cfe448ff4ee27b4fc97e042f2cf629427fd04e..aa7cc2e44a68943f66c446aa3835274301f65ffa 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -580,7 +580,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { field_create_instance($instance); $terms = array( $this->randomName(), - $this->randomName(), + $this->randomName() . ', ' . $this->randomName(), $this->randomName(), ); @@ -590,7 +590,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { $edit["body[$langcode][0][value]"] = $this->randomName(); // Insert the terms in a comma separated list. Vocabulary 1 is a // free-tagging field created by the default profile. - $edit[$instance['field_name'] . "[$langcode]"] = implode(', ', $terms); + $edit[$instance['field_name'] . "[$langcode]"] = drupal_implode_tags($terms); // Preview and verify the terms appear but are not created. $this->drupalPost('node/add/page', $edit, t('Preview')); @@ -611,9 +611,9 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { } // Get the created terms. - list($term1, $term2, $term3) = taxonomy_get_tree($this->vocabulary->vid); + list($term1, $term2, $term3) = array_values(taxonomy_term_load_multiple(FALSE)); - // Delete one term. + // Delete term 1. $this->drupalPost('taxonomy/term/' . $term1->tid . '/edit', array(), t('Delete')); $this->drupalPost(NULL, NULL, t('Delete')); $term_names = array($term2->name, $term3->name); @@ -627,10 +627,17 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { } $this->assertNoText($term1->name, t('The deleted term %name does not appear on the node page.', array('%name' => $term1->name))); - // Test autocomplete on term 2. + // Test autocomplete on term 2 - it contains a comma, so expect the key to + // be quoted. $input = substr($term2->name, 0, 3); $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input); - $this->assertRaw('{"' . $term2->name . '":"' . $term2->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term2->name))); + $this->assertRaw('{"\"' . $term2->name . '\"":"' . $term2->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term2->name))); + + // Test autocomplete on term 3 - it is alphanumeric only, so no extra + // quoting. + $input = substr($term3->name, 0, 3); + $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input); + $this->assertRaw('{"' . $term3->name . '":"' . $term3->name . '"}', t('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term3->name))); } /** @@ -760,6 +767,35 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { $this->assertEqual($terms[2]->parents, array($term2->tid), t('Term 3 is still a child of term 2.').var_export($terms[1]->tid,1)); } + /** + * Test saving a term with multiple parents through the UI. + */ + function testTermMultipleParentsInterface() { + // Add a new term to the vocabulary so that we can have multiple parents. + $parent = $this->createTerm($this->vocabulary); + + // Add a new term with multiple parents. + $edit = array( + 'name' => $this->randomName(12), + 'description[value]' => $this->randomName(100), + 'parent[]' => array(0, $parent->tid), + ); + // Save the new term. + $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add', $edit, t('Save')); + + // Check that the term was successfully created. + $terms = taxonomy_get_term_by_name($edit['name']); + $term = reset($terms); + $this->assertNotNull($term, t('Term found in database')); + $this->assertEqual($edit['name'], $term->name, t('Term name was successfully saved.')); + $this->assertEqual($edit['description[value]'], $term->description, t('Term description was successfully saved.')); + // Check that the parent tid is still there. The other parent (<root>) is + // not added by taxonomy_get_parents(). + $parents = taxonomy_get_parents($term->tid); + $parent = reset($parents); + $this->assertEqual($edit['parent[]'][1], $parent->tid, t('Term parents were successfully saved.')); + } + /** * Test taxonomy_get_term_by_name(). */ diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info index 798d24a7ed00d789570b423a96e325a6d8691d29..381d4dd4306576bc7406ad5263fd00b57f712cf1 100644 --- a/modules/toolbar/toolbar.info +++ b/modules/toolbar/toolbar.info @@ -4,8 +4,8 @@ core = 7.x package = Core version = VERSION -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info index db7549bba5ad022c21ee6f71fb5112408432da13..f93264831b74d40bfcf84573c2518db536f58f9b 100644 --- a/modules/tracker/tracker.info +++ b/modules/tracker/tracker.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = tracker.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info index 467f4935f6c6bb486bd3e9088315f3a51d43de38..39bda0d08fe840c627b91789cb110544678554f1 100644 --- a/modules/translation/tests/translation_test.info +++ b/modules/translation/tests/translation_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/translation/translation.info b/modules/translation/translation.info index d7cd35fdc1fab7bdd3f2aaa1f54ac277c7831a81..5ce3c1429e376358f182d42dc2ab9a6ed7798ffd 100644 --- a/modules/translation/translation.info +++ b/modules/translation/translation.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = translation.test -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/translation/translation.test b/modules/translation/translation.test index 54b53d9fdc4e6856820a5333e94503b66a425093..fe320a9354577f6018b9b90f305133648173aeac 100644 --- a/modules/translation/translation.test +++ b/modules/translation/translation.test @@ -108,9 +108,9 @@ class TranslationTestCase extends DrupalWebTestCase { // Update original and mark translation as outdated. $node_body = $this->randomName(); - $node->body[$node->language][0]['value'] = $node_body; + $node->body[LANGUAGE_NONE][0]['value'] = $node_body; $edit = array(); - $edit["body[$node->language][0][value]"] = $node_body; + $edit["body[$langcode][0][value]"] = $node_body; $edit['translation[retranslate]'] = TRUE; $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); $this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_title)), t('Original node updated.')); @@ -121,7 +121,7 @@ class TranslationTestCase extends DrupalWebTestCase { // Update translation and mark as updated. $edit = array(); - $edit["body[$node_translation->language][0][value]"] = $this->randomName(); + $edit["body[$langcode][0][value]"] = $this->randomName(); $edit['translation[status]'] = FALSE; $this->drupalPost('node/' . $node_translation->nid . '/edit', $edit, t('Save')); $this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_translation_title)), t('Translated node updated.')); @@ -131,7 +131,7 @@ class TranslationTestCase extends DrupalWebTestCase { $this->drupalGet('node/add/page'); $this->assertFieldByXPath('//select[@name="language"]//option', 'it', t('Italian (disabled) is available in language selection.')); $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it'); - $this->assertRaw($translation_it->body['it'][0]['value'], t('Content created in Italian (disabled).')); + $this->assertRaw($translation_it->body[LANGUAGE_NONE][0]['value'], t('Content created in Italian (disabled).')); // Confirm that language neutral is an option for translators when there are // disabled languages. @@ -349,9 +349,10 @@ class TranslationTestCase extends DrupalWebTestCase { function createTranslation($node, $title, $body, $language) { $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language))); - $body_key = "body[$language][0][value]"; + $langcode = LANGUAGE_NONE; + $body_key = "body[$langcode][0][value]"; $this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated."); - $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[$node->language][0]['value'], "Original body value correctly populated."); + $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[LANGUAGE_NONE][0]['value'], "Original body value correctly populated."); $edit = array(); $edit["title"] = $title; diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info index 406a1af1b9930625e2e0c8b20eba44a8879b081b..67fe0749370c3e921a766c63be161b62a5a36796 100644 --- a/modules/trigger/tests/trigger_test.info +++ b/modules/trigger/tests/trigger_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info index 8c4605497de451dcbf4f071953cf1032a1755077..88e1afc10ce45a0fff01ae83d2e5605a9a02a7b8 100644 --- a/modules/trigger/trigger.info +++ b/modules/trigger/trigger.info @@ -6,8 +6,8 @@ core = 7.x files[] = trigger.test configure = admin/structure/trigger -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info index dd1becd4f38ff6c0ddab10bbb056f570c263d745..d39efaf3ee1b4f8aca72b3af1ba8eb6ee2c6f500 100644 --- a/modules/update/tests/aaa_update_test.info +++ b/modules/update/tests/aaa_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info index f6ed550d1f7be47a29be822040b2d0e53313a7a2..2bd0175a4344b8b2cfa92bb03dfafa46e6e8cf83 100644 --- a/modules/update/tests/bbb_update_test.info +++ b/modules/update/tests/bbb_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info index a5190effcefda510a331949f4cceef08432efece..f715441e232a837a49bdb24219b526a961d90095 100644 --- a/modules/update/tests/ccc_update_test.info +++ b/modules/update/tests/ccc_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info index 0f0d649e365ebb6f27b0a3fc9667642bc1cc1fb8..effe5538e9483f4e800a7032ab606c95be5cf636 100644 --- a/modules/update/tests/update_test.info +++ b/modules/update/tests/update_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/update/update.info b/modules/update/update.info index 2b53994b8dbc285268705a2630659d1abcbcaca3..51aacf44207851d629f1c15b181414f0b72a42a3 100644 --- a/modules/update/update.info +++ b/modules/update/update.info @@ -6,8 +6,8 @@ core = 7.x files[] = update.test configure = admin/reports/updates/settings -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info index 8e9af847d153d631390b47f01fc9da0dd86c4437..a38e3b88f322c048efbdd402a4e4adb29d2cce7b 100644 --- a/modules/user/tests/user_form_test.info +++ b/modules/user/tests/user_form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/user/user-rtl.css b/modules/user/user-rtl.css index 5a1442c1c5104f68da55bac4014ee126777c69c5..642c9434716a8e26e132f13a031ab8aa0b9731a4 100644 --- a/modules/user/user-rtl.css +++ b/modules/user/user-rtl.css @@ -4,6 +4,12 @@ padding-right: 1.5em; } +#user-admin-roles .form-item-name { + float: right; + margin-left: 1em; + margin-right: 0; +} + /** * Password strength indicator. */ diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc index 0596bde4c1c387c8575a8810f6dd84a7778708ae..0044b18a451abc7601150ea327f144a6b3e01e1b 100644 --- a/modules/user/user.admin.inc +++ b/modules/user/user.admin.inc @@ -712,7 +712,12 @@ function user_admin_permissions($form, $form_state, $rid = NULL) { // Have to build checkboxes here after checkbox arrays are built foreach ($role_names as $rid => $name) { - $form['checkboxes'][$rid] = array('#type' => 'checkboxes', '#options' => $options, '#default_value' => isset($status[$rid]) ? $status[$rid] : array()); + $form['checkboxes'][$rid] = array( + '#type' => 'checkboxes', + '#options' => $options, + '#default_value' => isset($status[$rid]) ? $status[$rid] : array(), + '#attributes' => array('class' => array('rid-' . $rid)), + ); $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE); } diff --git a/modules/user/user.css b/modules/user/user.css index d6ed7c366ba0f0796b0a2137c09e70baed3ca96d..079ec38abb1b91a3e8e6316513504ab72029f9f8 100644 --- a/modules/user/user.css +++ b/modules/user/user.css @@ -22,8 +22,8 @@ clear: both; } #user-admin-roles .form-item-name { - float: left; - margin-right: 1em; + float: left; /* LTR */ + margin-right: 1em; /* LTR */ } /** diff --git a/modules/user/user.info b/modules/user/user.info index 27f473502984decd8885c0b6fa876e0d1352215e..04f0f7b773c56e4ad8a2a1788a4a7ec41051b301 100644 --- a/modules/user/user.info +++ b/modules/user/user.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/config/people stylesheets[all][] = user.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/modules/user/user.module b/modules/user/user.module index 84430b2f799f7dd896b5610bbe38358c10ec062e..044ad4698822f8a91efa5e435ce7637665455820 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -74,10 +74,26 @@ function user_help($path, $arg) { } /** - * Invokes hook_user() in every module. + * Invokes a user hook in every module. * * We cannot use module_invoke() for this, because the arguments need to * be passed by reference. + * + * @param $type + * A text string that controls which user hook to invoke. Valid choices are: + * - cancel: Invokes hook_user_cancel(). + * - insert: Invokes hook_user_insert(). + * - login: Invokes hook_user_login(). + * - presave: Invokes hook_user_presave(). + * - update: Invokes hook_user_update(). + * @param $edit + * An associative array variable containing form values to be passed + * as the first parameter of the hook function. + * @param $account + * The user account object to be passed as the second parameter of the hook + * function. + * @param $category + * The category of user information being acted upon. */ function user_module_invoke($type, &$edit, $account, $category = NULL) { foreach (module_implements('user_' . $type) as $module) { @@ -2287,6 +2303,27 @@ function user_cancel_url($account) { return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE)); } +/** + * Creates a unique hash value for use in time-dependent per-user URLs. + * + * This hash is normally used to build a unique and secure URL that is sent to + * the user by email for purposes such as resetting the user's password. In + * order to validate the URL, the same hash can be generated again, from the + * same information, and compared to the hash value from the URL. The URL + * normally contains both the time stamp and the numeric user ID. The login + * name and hashed password are retrieved from the database as necessary. For a + * usage example, see user_cancel_url() and user_cancel_confirm(). + * + * @param $password + * The hashed user account password value. + * @param $timestamp + * A unix timestamp. + * @param $login + * The user account login name. + * + * @return + * A string that is safe for use in URLs and SQL statements. + */ function user_pass_rehash($password, $timestamp, $login) { return drupal_hmac_base64($timestamp . $login, drupal_get_hash_salt() . $password); } diff --git a/modules/user/user.permissions.js b/modules/user/user.permissions.js index 4ef576cd44a0bc51c07ba2342aeb1adb0b5b236d..988820e12db79a8d6697b773d97305c36b32a060 100644 --- a/modules/user/user.permissions.js +++ b/modules/user/user.permissions.js @@ -5,34 +5,64 @@ */ Drupal.behaviors.permissions = { attach: function (context) { - $('table#permissions:not(.permissions-processed)').each(function () { + var self = this; + $('table#permissions').once('permissions', function () { + // On a site with many roles and permissions, this behavior initially has + // to perform thousands of DOM manipulations to inject checkboxes and hide + // them. By detaching the table from the DOM, all operations can be + // performed without triggering internal layout and re-rendering processes + // in the browser. + var $table = $(this); + if ($table.prev().length) { + var $ancestor = $table.prev(), method = 'after'; + } + else { + var $ancestor = $table.parent(), method = 'append'; + } + $table.detach(); + // Create dummy checkboxes. We use dummy checkboxes instead of reusing // the existing checkboxes here because new checkboxes don't alter the // submitted form. If we'd automatically check existing checkboxes, the // permission table would be polluted with redundant entries. This // is deliberate, but desirable when we automatically check them. - $(':checkbox', this).not('[name^="2["]').not('[name^="1["]').each(function () { - $(this).addClass('real-checkbox'); - $('<input type="checkbox" class="dummy-checkbox" disabled="disabled" checked="checked" />') - .attr('title', Drupal.t("This permission is inherited from the authenticated user role.")) - .insertAfter(this) - .hide(); - }); + var $dummy = $('<input type="checkbox" class="dummy-checkbox" disabled="disabled" checked="checked" />') + .attr('title', Drupal.t("This permission is inherited from the authenticated user role.")) + .hide(); - // Helper function toggles all dummy checkboxes based on the checkboxes' - // state. If the "authenticated user" checkbox is checked, the checked - // and disabled checkboxes are shown, the real checkboxes otherwise. - var toggle = function () { - $(this).closest('tr') - .find('.real-checkbox')[this.checked ? 'hide' : 'show']().end() - .find('.dummy-checkbox')[this.checked ? 'show' : 'hide'](); - }; + $('input[type=checkbox]', this).not('.rid-2, .rid-1').addClass('real-checkbox').each(function () { + $dummy.clone().insertAfter(this); + }); // Initialize the authenticated user checkbox. - $(':checkbox[name^="2["]', this) - .click(toggle) - .each(function () { toggle.call(this); }); - }).addClass('permissions-processed'); + $('input[type=checkbox].rid-2', this) + .bind('click.permissions', self.toggle) + // .triggerHandler() cannot be used here, as it only affects the first + // element. + .each(self.toggle); + + // Re-insert the table into the DOM. + $ancestor[method]($table); + }); + }, + + /** + * Toggles all dummy checkboxes based on the checkboxes' state. + * + * If the "authenticated user" checkbox is checked, the checked and disabled + * checkboxes are shown, the real checkboxes otherwise. + */ + toggle: function () { + var authCheckbox = this, $row = $(this).closest('tr'); + // jQuery performs too many layout calculations for .hide() and .show(), + // leading to a major page rendering lag on sites with many roles and + // permissions. Therefore, we toggle visibility directly. + $row.find('.real-checkbox').each(function () { + this.style.display = (authCheckbox.checked ? 'none' : ''); + }); + $row.find('.dummy-checkbox').each(function () { + this.style.display = (authCheckbox.checked ? '' : 'none'); + }); } }; diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info index b5b1187a41ec8318273a83f8ac155b0abe8b949f..29311297ce7a4fe470172fcac6499927e86fbb6a 100644 --- a/profiles/minimal/minimal.info +++ b/profiles/minimal/minimal.info @@ -6,8 +6,8 @@ dependencies[] = block dependencies[] = dblog files[] = minimal.profile -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info index 9008fea963f65e1067d321ae431ace0111347d01..daa49fafefc85a4bbd6076862d408f67c07bf6ec 100644 --- a/profiles/standard/standard.info +++ b/profiles/standard/standard.info @@ -25,8 +25,8 @@ dependencies[] = file dependencies[] = rdf files[] = standard.profile -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install index 70829064d1bc3c929f20c3c112bbc0957e1e752d..5d447177fb26261c51fd7e3b3017fbd9ddc0ca46 100644 --- a/profiles/standard/standard.install +++ b/profiles/standard/standard.install @@ -327,7 +327,6 @@ function standard_install() { 'field_name' => 'field_image', 'type' => 'image', 'cardinality' => 1, - 'translatable' => TRUE, 'locked' => FALSE, 'indexes' => array('fid' => array('fid')), 'settings' => array( diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 52228081f7a8d8ea6e33cd1588d577be53836dba..44be97a8b9476878a4c1c2496a9f7df1315a2abe 100644 --- a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 277349d7e8f9275733e7f878ef95ae84417a9416..85ca1bfde4be4b85259f1760662e344b3672ce2f 100644 --- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -8,8 +8,8 @@ version = VERSION core = 6.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/profiles/testing/testing.info b/profiles/testing/testing.info index 4f6271c4e9936b9f204165135fb33bb01b7a929f..6723a1044e118c1be7c227b097391eac7c0d17a8 100644 --- a/profiles/testing/testing.info +++ b/profiles/testing/testing.info @@ -4,8 +4,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/scripts/generate-d6-content.sh b/scripts/generate-d6-content.sh index bba61caee066d757611d6c2343c925a5ac1a8112..5079c2338526b46a774eb31765f0cc98a1097dbd 100644 --- a/scripts/generate-d6-content.sh +++ b/scripts/generate-d6-content.sh @@ -100,7 +100,7 @@ module_load_include('inc', 'node', 'node.pages'); for ($i = 0; $i < 24; $i++) { $uid = intval($i / 8) + 3; $user = user_load($uid); - $node = new stdClass; + $node = new stdClass(); $node->uid = $uid; $node->type = $i < 12 ? 'page' : 'story'; $node->sticky = 0; @@ -148,7 +148,7 @@ for ($i = 0; $i < 24; $i++) { for ($i = 0; $i < 12; $i++) { $uid = intval($i / 4) + 3; $user = user_load($uid); - $node = new stdClass; + $node = new stdClass(); $node->uid = $uid; $node->type = 'poll'; $node->sticky = 0; @@ -187,7 +187,7 @@ for ($i = 0; $i < 12; $i++) { $uid = 6; $user = user_load($uid); -$node = new stdClass; +$node = new stdClass(); $node->uid = $uid; $node->type = 'broken'; $node->sticky = 0; diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index db34924c986a365f1ecfe0956f5f9aec53fad945..02e897e41763089e60c0850d88b150780a3b287d 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -16,10 +16,10 @@ if ($args['help'] || $count == 0) { exit; } -if ($args['execute-batch']) { +if ($args['execute-test']) { // Masquerade as Apache for running tests. simpletest_script_init("Apache"); - simpletest_script_execute_batch(); + simpletest_script_run_one_test($args['test-id'], $args['execute-test']); } else { // Run administrative functions as CLI. @@ -67,8 +67,6 @@ if ($args['list']) { exit; } -$test_list = simpletest_script_get_test_list(); - // Try to allocate unlimited time to run the tests. drupal_set_time_limit(0); @@ -78,7 +76,7 @@ simpletest_script_reporter_init(); $test_id = db_insert('simpletest_test_id')->useDefaults(array('test_id'))->execute(); // Execute tests. -simpletest_script_command($args['concurrency'], $test_id, implode(",", $test_list)); +simpletest_script_execute_batch($test_id, simpletest_script_get_test_list()); // Retrieve the last database prefix used for testing and the last test class // that was run from. Use the information to read the lgo file in case any @@ -99,6 +97,9 @@ if ($args['xml']) { // Cleanup our test results. simpletest_clean_results_table($test_id); +// Test complete, exit. +exit; + /** * Print help text. */ @@ -130,9 +131,7 @@ All arguments are long options. --concurrency [num] - Run tests in parallel, up to [num] tests at a time. This requires - the Process Control Extension (PCNTL) to be compiled in PHP, not - supported under Windows. + Run tests in parallel, up to [num] tests at a time. --all Run all available tests. @@ -193,8 +192,8 @@ function simpletest_script_parse_args() { 'verbose' => FALSE, 'test_names' => array(), // Used internally. - 'test-id' => NULL, - 'execute-batch' => FALSE, + 'test-id' => 0, + 'execute-test' => '', 'xml' => '', ); @@ -236,10 +235,6 @@ function simpletest_script_parse_args() { simpletest_script_print_error("--concurrency must be a strictly positive integer."); exit; } - elseif ($args['concurrency'] > 1 && !function_exists('pcntl_fork')) { - simpletest_script_print_error("Parallel test execution requires the Process Control extension to be compiled in PHP. See http://php.net/manual/en/intro.pcntl.php for more information."); - exit; - } return array($args, $count); } @@ -310,93 +305,96 @@ function simpletest_script_init($server_software) { /** * Execute a batch of tests. */ -function simpletest_script_execute_batch() { +function simpletest_script_execute_batch($test_id, $test_classes) { global $args; - if (!isset($args['test-id'])) { - simpletest_script_print_error("--execute-batch should not be called interactively."); - exit; - } - if ($args['concurrency'] == 1) { - // Fallback to mono-threaded execution. - if (count($args['test_names']) > 1) { - foreach ($args['test_names'] as $test_class) { - // Execute each test in its separate Drupal environment. - simpletest_script_command(1, $args['test-id'], $test_class); + // Multi-process execution. + $children = array(); + while (!empty($test_classes) || !empty($children)) { + while (count($children) < $args['concurrency']) { + if (empty($test_classes)) { + break; } - exit; - } - else { - // Execute an individual test. - $test_class = array_shift($args['test_names']); - drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); - simpletest_script_run_one_test($args['test-id'], $test_class); - exit; - } - } - else { - // Multi-threaded execution. - $children = array(); - while (!empty($args['test_names']) || !empty($children)) { - // Fork children safely since Drupal is not bootstrapped yet. - while (count($children) < $args['concurrency']) { - if (empty($args['test_names'])) break; - - $child = array(); - $child['test_class'] = $test_class = array_shift($args['test_names']); - $child['pid'] = pcntl_fork(); - if (!$child['pid']) { - // This is the child process, bootstrap and execute the test. - drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); - simpletest_script_run_one_test($args['test-id'], $test_class); - exit; - } - else { - // Register our new child. - $children[] = $child; - } + + // Fork a child process. + $test_class = array_shift($test_classes); + $command = simpletest_script_command($test_id, $test_class); + $process = proc_open($command, array(), $pipes, NULL, NULL, array('bypass_shell' => TRUE)); + + if (!is_resource($process)) { + echo "Unable to fork test process. Aborting.\n"; + exit; } - // Wait for children every 200ms. - usleep(200000); + // Register our new child. + $children[] = array( + 'process' => $process, + 'class' => $test_class, + 'pipes' => $pipes, + ); + } - // Check if some children finished. - foreach ($children as $cid => $child) { - if (pcntl_waitpid($child['pid'], $status, WUNTRACED | WNOHANG)) { - // This particular child exited. - unset($children[$cid]); + // Wait for children every 200ms. + usleep(200000); + + // Check if some children finished. + foreach ($children as $cid => $child) { + $status = proc_get_status($child['process']); + if (empty($status['running'])) { + // The child exited, unregister it. + proc_close($child['process']); + if ($status['exitcode']) { + echo 'FATAL ' . $test_class . ': test runner returned a non-zero error code (' . $status['exitcode'] . ').' . "\n"; } + unset($children[$cid]); } } - exit; } } /** - * Run a single test (assume a Drupal bootstrapped environment). + * Bootstrap Drupal and run a single test. */ function simpletest_script_run_one_test($test_id, $test_class) { - $test = new $test_class($test_id); - $test->run(); - $info = $test->getInfo(); + try { + // Bootstrap Drupal. + drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + + $test = new $test_class($test_id); + $test->run(); + $info = $test->getInfo(); + + $had_fails = (isset($test->results['#fail']) && $test->results['#fail'] > 0); + $had_exceptions = (isset($test->results['#exception']) && $test->results['#exception'] > 0); + $status = ($had_fails || $had_exceptions ? 'fail' : 'pass'); + simpletest_script_print($info['name'] . ' ' . _simpletest_format_summary_line($test->results) . "\n", simpletest_script_color_code($status)); - $status = ((isset($test->results['#fail']) && $test->results['#fail'] > 0) - || (isset($test->results['#exception']) && $test->results['#exception'] > 0) ? 'fail' : 'pass'); - simpletest_script_print($info['name'] . ' ' . _simpletest_format_summary_line($test->results) . "\n", simpletest_script_color_code($status)); + // Finished, kill this runner. + exit(0); + } + catch (Exception $e) { + echo (string) $e; + exit(1); + } } /** - * Execute a command to run batch of tests in separate process. + * Return a command used to run a test in a separate process. + * + * @param $test_id + * The current test ID. + * @param $test_class + * The name of the test class to run. */ -function simpletest_script_command($concurrency, $test_id, $tests) { +function simpletest_script_command($test_id, $test_class) { global $args, $php; - $command = "$php ./scripts/{$args['script']} --url {$args['url']}"; + $command = escapeshellarg($php) . ' ' . escapeshellarg('./scripts/' . $args['script']) . ' --url ' . escapeshellarg($args['url']); if ($args['color']) { $command .= ' --color'; } - $command .= " --php " . escapeshellarg($php) . " --concurrency $concurrency --test-id $test_id --execute-batch $tests"; - passthru($command); + $command .= " --php " . escapeshellarg($php) . " --test-id $test_id --execute-test $test_class"; + return $command; } /** diff --git a/themes/bartik/bartik.info b/themes/bartik/bartik.info index 8ebd6c8319d6fd62fa1993a76a8d935bd7d006af..ebfd800d78602e167a9d77109c189b109f6ee0a5 100644 --- a/themes/bartik/bartik.info +++ b/themes/bartik/bartik.info @@ -34,8 +34,8 @@ regions[footer] = Footer settings[shortcut_module_link] = 0 -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/garland/garland.info b/themes/garland/garland.info index 8e805840d3c1772bd34fb692c345c1c266ffb1a1..dfcf444fdc420f9c982da269d0b558d450808a56 100644 --- a/themes/garland/garland.info +++ b/themes/garland/garland.info @@ -7,8 +7,8 @@ stylesheets[all][] = style.css stylesheets[print][] = print.css settings[garland_width] = fluid -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/seven/seven.info b/themes/seven/seven.info index de5f3fb62b40491bbc51c489132cc94ec6b7066f..ac33f5a141f2df4268f0c45ee80f2fa2764cd3fa 100644 --- a/themes/seven/seven.info +++ b/themes/seven/seven.info @@ -13,8 +13,8 @@ regions[page_bottom] = Page bottom regions[sidebar_first] = First sidebar regions_hidden[] = sidebar_first -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/stark/stark.info b/themes/stark/stark.info index e27d53d64401e3504a8f63fa6d4be00e819b98cd..013eb235231fbc2310580ff200cb5796b7aa79fb 100644 --- a/themes/stark/stark.info +++ b/themes/stark/stark.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x stylesheets[all][] = layout.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/tests/test_theme/test_theme.info b/themes/tests/test_theme/test_theme.info index 0a791d48576315b6fc48084bc3ecd32210c77030..7af270dfa5902843ecfcfcfe3cacbd2e6832245d 100644 --- a/themes/tests/test_theme/test_theme.info +++ b/themes/tests/test_theme/test_theme.info @@ -15,8 +15,8 @@ hidden = TRUE ; file within the theme folder. stylesheets[all][] = system.base.css -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/tests/update_test_basetheme/update_test_basetheme.info b/themes/tests/update_test_basetheme/update_test_basetheme.info index cc800fa8e90f70a209378ff19ecac0149a46ab16..f2e43a2cdea2de49d9084fa60086114e2fe4baee 100644 --- a/themes/tests/update_test_basetheme/update_test_basetheme.info +++ b/themes/tests/update_test_basetheme/update_test_basetheme.info @@ -3,8 +3,8 @@ description = Test theme which acts as a base theme for other test subthemes. core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879" diff --git a/themes/tests/update_test_subtheme/update_test_subtheme.info b/themes/tests/update_test_subtheme/update_test_subtheme.info index 0265dc5497290509cf53feb3b991d921a613af2d..e5e4c46f42785b671e40bff1b17959f5e264c837 100644 --- a/themes/tests/update_test_subtheme/update_test_subtheme.info +++ b/themes/tests/update_test_subtheme/update_test_subtheme.info @@ -4,8 +4,8 @@ core = 7.x base theme = update_test_basetheme hidden = TRUE -; Information added by drupal.org packaging script on 2011-06-30 -version = "7.4" +; Information added by drupal.org packaging script on 2011-07-28 +version = "7.7" project = "drupal" -datestamp = "1309397516" +datestamp = "1311813879"