is 1000 characters."
- */
- function testVeryLongLineWrap() {
- $input = 'Drupal' . str_repeat('x', 2100) . '> 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
deleted file mode 100644
index f5d7d290..00000000
--- a/modules/simpletest/tests/menu.test
+++ /dev/null
@@ -1,1740 +0,0 @@
-drupalGet($goto);
- }
- // Compare paths with actual breadcrumb.
- $parts = $this->getParts();
- $pass = TRUE;
- foreach ($trail as $path => $title) {
- $url = url($path);
- $part = array_shift($parts);
- $pass = ($pass && $part['href'] === $url && $part['text'] === check_plain($title));
- }
- // No parts must be left, or an expected "Home" will always pass.
- $pass = ($pass && empty($parts));
-
- $this->assertTrue($pass, format_string('Breadcrumb %parts found on @path.', array(
- '%parts' => implode(' » ', $trail),
- '@path' => $this->getUrl(),
- )));
-
- // Additionally assert page title, if given.
- if (isset($page_title)) {
- $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)));
- }
-
- // Additionally assert active trail in a menu tree output, if given.
- if ($tree) {
- end($tree);
- $active_link_path = key($tree);
- $active_link_title = array_pop($tree);
- $xpath = '';
- if ($tree) {
- $i = 0;
- foreach ($tree as $link_path => $link_title) {
- $part_xpath = (!$i ? '//' : '/following-sibling::ul/descendant::');
- $part_xpath .= 'li[contains(@class, :class)]/a[contains(@href, :href) and contains(text(), :title)]';
- $part_args = array(
- ':class' => 'active-trail',
- ':href' => url($link_path),
- ':title' => $link_title,
- );
- $xpath .= $this->buildXPathQuery($part_xpath, $part_args);
- $i++;
- }
- $elements = $this->xpath($xpath);
- $this->assertTrue(!empty($elements), 'Active trail to current page was found in menu tree.');
-
- // Append prefix for active link asserted below.
- $xpath .= '/following-sibling::ul/descendant::';
- }
- else {
- $xpath .= '//';
- }
- $xpath_last_active = ($last_active ? 'and contains(@class, :class-active)' : '');
- $xpath .= 'li[contains(@class, :class-trail)]/a[contains(@href, :href) ' . $xpath_last_active . 'and contains(text(), :title)]';
- $args = array(
- ':class-trail' => 'active-trail',
- ':class-active' => 'active',
- ':href' => url($active_link_path),
- ':title' => $active_link_title,
- );
- $elements = $this->xpath($xpath, $args);
- $this->assertTrue(!empty($elements), format_string('Active link %title was found in menu tree, including active trail links %tree.', array(
- '%title' => $active_link_title,
- '%tree' => implode(' » ', $tree),
- )));
- }
- }
-
- /**
- * Returns the breadcrumb contents of the current page in the internal browser.
- */
- protected function getParts() {
- $parts = array();
- $elements = $this->xpath('//div[@class="breadcrumb"]/a');
- if (!empty($elements)) {
- foreach ($elements as $element) {
- $parts[] = array(
- 'text' => (string) $element,
- 'href' => (string) $element['href'],
- 'title' => (string) $element['title'],
- );
- }
- }
- return $parts;
- }
-}
-
-class MenuRouterTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Menu router',
- 'description' => 'Tests menu router and hook_menu() functionality.',
- 'group' => 'Menu',
- );
- }
-
- function setUp() {
- // Enable dummy module that implements hook_menu.
- parent::setUp('menu_test');
- // Make the tests below more robust by explicitly setting the default theme
- // and administrative theme that they expect.
- theme_enable(array('bartik'));
- variable_set('theme_default', 'bartik');
- variable_set('admin_theme', 'seven');
- }
-
- /**
- * Test title callback set to FALSE.
- */
- function testTitleCallbackFalse() {
- $this->drupalGet('node');
- $this->assertText('A title with @placeholder', 'Raw text found on the page');
- $this->assertNoText(t('A title with @placeholder', array('@placeholder' => 'some other text')), 'Text with placeholder substitutions not found.');
- }
-
- /**
- * Tests page title of MENU_CALLBACKs.
- */
- function testTitleMenuCallback() {
- // Verify that the menu router item title is not visible.
- $this->drupalGet('');
- $this->assertNoText(t('Menu Callback Title'));
- // Verify that the menu router item title is output as page title.
- $this->drupalGet('menu_callback_title');
- $this->assertText(t('Menu Callback Title'));
- }
-
- /**
- * Test the theme callback when it is set to use an administrative theme.
- */
- function testThemeCallbackAdministrative() {
- $this->drupalGet('menu-test/theme-callback/use-admin-theme');
- $this->assertText('Custom theme: seven. Actual theme: seven.', 'The administrative theme can be correctly set in a theme callback.');
- $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page.");
- }
-
- /**
- * Test that the theme callback is properly inherited.
- */
- function testThemeCallbackInheritance() {
- $this->drupalGet('menu-test/theme-callback/use-admin-theme/inheritance');
- $this->assertText('Custom theme: seven. Actual theme: seven. Theme callback inheritance is being tested.', 'Theme callback inheritance correctly uses the administrative theme.');
- $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page.");
- }
-
- /**
- * Test that 'page callback', 'file' and 'file path' keys are properly
- * inherited from parent menu paths.
- */
- function testFileInheritance() {
- $this->drupalGet('admin/config/development/file-inheritance');
- $this->assertText('File inheritance test description', 'File inheritance works.');
- }
-
- /**
- * Test path containing "exotic" characters.
- */
- function testExoticPath() {
- $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
- "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
- "éøïвβä¸åœ‹æ›¸Ûž"; // Characters from various non-ASCII alphabets.
- $this->drupalGet($path);
- $this->assertRaw('This is menu_test_callback().');
- }
-
- /**
- * Test the theme callback when the site is in maintenance mode.
- */
- function testThemeCallbackMaintenanceMode() {
- variable_set('maintenance_mode', TRUE);
-
- // For a regular user, the fact that the site is in maintenance mode means
- // we expect the theme callback system to be bypassed entirely.
- $this->drupalGet('menu-test/theme-callback/use-admin-theme');
- $this->assertRaw('bartik/css/style.css', "The maintenance theme's CSS appears on the page.");
-
- // An administrator, however, should continue to see the requested theme.
- $admin_user = $this->drupalCreateUser(array('access site in maintenance mode'));
- $this->drupalLogin($admin_user);
- $this->drupalGet('menu-test/theme-callback/use-admin-theme');
- $this->assertText('Custom theme: seven. Actual theme: seven.', 'The theme callback system is correctly triggered for an administrator when the site is in maintenance mode.');
- $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page.");
- }
-
- /**
- * Make sure the maintenance mode can be bypassed using hook_menu_site_status_alter().
- *
- * @see hook_menu_site_status_alter().
- */
- function testMaintenanceModeLoginPaths() {
- variable_set('maintenance_mode', TRUE);
-
- $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')));
- $this->drupalLogout();
- $this->drupalGet('node');
- $this->assertText($offline_message);
- $this->drupalGet('menu_login_callback');
- $this->assertText('This is menu_login_callback().', t('Maintenance mode can be bypassed through hook_login_paths().'));
- }
-
- /**
- * Test that an authenticated user hitting 'user/login' gets redirected to
- * 'user' and 'user/register' gets redirected to the user edit page.
- */
- function testAuthUserUserLogin() {
- $loggedInUser = $this->drupalCreateUser(array());
- $this->drupalLogin($loggedInUser);
-
- $this->drupalGet('user/login');
- // Check that we got to 'user'.
- $this->assertTrue($this->url == url('user', array('absolute' => TRUE)), "Logged-in user redirected to q=user on accessing q=user/login");
-
- // user/register should redirect to user/UID/edit.
- $this->drupalGet('user/register');
- $this->assertTrue($this->url == url('user/' . $this->loggedInUser->uid . '/edit', array('absolute' => TRUE)), "Logged-in user redirected to q=user/UID/edit on accessing q=user/register");
- }
-
- /**
- * Test the theme callback when it is set to use an optional theme.
- */
- function testThemeCallbackOptionalTheme() {
- // Request a theme that is not enabled.
- $this->drupalGet('menu-test/theme-callback/use-stark-theme');
- $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that is not enabled is requested.');
- $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page.");
-
- // Now enable the theme and request it again.
- theme_enable(array('stark'));
- $this->drupalGet('menu-test/theme-callback/use-stark-theme');
- $this->assertText('Custom theme: stark. Actual theme: stark.', 'The theme callback system uses an optional theme once it has been enabled.');
- $this->assertRaw('stark/layout.css', "The optional theme's CSS appears on the page.");
- }
-
- /**
- * Test the theme callback when it is set to use a theme that does not exist.
- */
- function testThemeCallbackFakeTheme() {
- $this->drupalGet('menu-test/theme-callback/use-fake-theme');
- $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when a theme that does not exist is requested.');
- $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page.");
- }
-
- /**
- * Test the theme callback when no theme is requested.
- */
- function testThemeCallbackNoThemeRequested() {
- $this->drupalGet('menu-test/theme-callback/no-theme-requested');
- $this->assertText('Custom theme: NONE. Actual theme: bartik.', 'The theme callback system falls back on the default theme when no theme is requested.');
- $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page.");
- }
-
- /**
- * Test that hook_custom_theme() can control the theme of a page.
- */
- function testHookCustomTheme() {
- // Trigger hook_custom_theme() to dynamically request the Stark theme for
- // the requested page.
- variable_set('menu_test_hook_custom_theme_name', 'stark');
- theme_enable(array('stark'));
-
- // Visit a page that does not implement a theme callback. The above request
- // should be honored.
- $this->drupalGet('menu-test/no-theme-callback');
- $this->assertText('Custom theme: stark. Actual theme: stark.', 'The result of hook_custom_theme() is used as the theme for the current page.');
- $this->assertRaw('stark/layout.css', "The Stark theme's CSS appears on the page.");
- }
-
- /**
- * Test that the theme callback wins out over hook_custom_theme().
- */
- function testThemeCallbackHookCustomTheme() {
- // Trigger hook_custom_theme() to dynamically request the Stark theme for
- // the requested page.
- variable_set('menu_test_hook_custom_theme_name', 'stark');
- theme_enable(array('stark'));
-
- // The menu "theme callback" should take precedence over a value set in
- // hook_custom_theme().
- $this->drupalGet('menu-test/theme-callback/use-admin-theme');
- $this->assertText('Custom theme: seven. Actual theme: seven.', 'The result of hook_custom_theme() does not override what was set in a theme callback.');
- $this->assertRaw('seven/style.css', "The Seven theme's CSS appears on the page.");
- }
-
- /**
- * Tests for menu_link_maintain().
- */
- function testMenuLinkMaintain() {
- $admin_user = $this->drupalCreateUser(array('administer site configuration'));
- $this->drupalLogin($admin_user);
-
- // Create three menu items.
- menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1');
- menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/1', 'Menu link #1-1');
- menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/2', 'Menu link #2');
-
- // Move second link to the main-menu, to test caching later on.
- db_update('menu_links')
- ->fields(array('menu_name' => 'main-menu'))
- ->condition('link_title', 'Menu link #1-1')
- ->condition('customized', 0)
- ->condition('module', 'menu_test')
- ->execute();
- menu_cache_clear('main-menu');
-
- // Load front page.
- $this->drupalGet('node');
- $this->assertLink(t('Menu link #1'), 0, 'Found menu link #1');
- $this->assertLink(t('Menu link #1-1'), 0, 'Found menu link #1-1');
- $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2');
-
- // Rename all links for the given path.
- menu_link_maintain('menu_test', 'update', 'menu_test_maintain/1', 'Menu link updated');
- // Load a different page to be sure that we have up to date information.
- $this->drupalGet('menu_test_maintain/1');
- $this->assertLink(t('Menu link updated'), 0, 'Found updated menu link');
- $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1');
- $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1-1');
- $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2');
-
- // Delete all links for the given path.
- menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/1', '');
- // Load a different page to be sure that we have up to date information.
- $this->drupalGet('menu_test_maintain/2');
- $this->assertNoLink(t('Menu link updated'), 0, 'Not found deleted menu link');
- $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1');
- $this->assertNoLink(t('Menu link #1'), 0, 'Not found menu link #1-1');
- $this->assertLink(t('Menu link #2'), 0, 'Found menu link #2');
- }
-
- /**
- * Test menu_get_names().
- */
- function testMenuGetNames() {
- // Create three menu items.
- for ($i = 0; $i < 3; $i++) {
- $menu_link = array(
- 'link_title' => 'Menu link #' . $i,
- 'link_path' => 'menu_test/' . $i,
- 'module' => 'menu_test',
- 'menu_name' => 'menu_test_' . $i,
- );
- menu_link_save($menu_link);
- }
-
- drupal_static_reset('menu_get_names');
-
- // Verify that the menu names are correctly reported by menu_get_names().
- $menu_names = menu_get_names();
- $this->pass(implode(' | ', $menu_names));
- for ($i = 0; $i < 3; $i++) {
- $this->assertTrue(in_array('menu_test_' . $i, $menu_names), t('Expected menu name %expected is returned.', array('%expected' => 'menu_test_' . $i)));
- }
- }
-
- /**
- * Tests for menu_name parameter for hook_menu().
- */
- function testMenuName() {
- $admin_user = $this->drupalCreateUser(array('administer site configuration'));
- $this->drupalLogin($admin_user);
-
- $sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'";
- $name = db_query($sql)->fetchField();
- $this->assertEqual($name, 'original', 'Menu name is "original".');
-
- // Change the menu_name parameter in menu_test.module, then force a menu
- // rebuild.
- menu_test_menu_name('changed');
- menu_rebuild();
-
- $sql = "SELECT menu_name FROM {menu_links} WHERE router_path = 'menu_name_test'";
- $name = db_query($sql)->fetchField();
- $this->assertEqual($name, 'changed', 'Menu name was successfully changed after rebuild.');
- }
-
- /**
- * Tests for menu hierarchy.
- */
- function testMenuHierarchy() {
- $parent_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent'))->fetchAssoc();
- $child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child'))->fetchAssoc();
- $unattached_child_link = db_query('SELECT * FROM {menu_links} WHERE link_path = :link_path', array(':link_path' => 'menu-test/hierarchy/parent/child2/child'))->fetchAssoc();
-
- $this->assertEqual($child_link['plid'], $parent_link['mlid'], 'The parent of a directly attached child is correct.');
- $this->assertEqual($unattached_child_link['plid'], $parent_link['mlid'], 'The parent of a non-directly attached child is correct.');
- }
-
- /**
- * Tests menu link depth and parents of local tasks and menu callbacks.
- */
- function testMenuHidden() {
- // Verify links for one dynamic argument.
- $links = db_select('menu_links', 'ml')
- ->fields('ml')
- ->condition('ml.router_path', 'menu-test/hidden/menu%', 'LIKE')
- ->orderBy('ml.router_path')
- ->execute()
- ->fetchAllAssoc('router_path', PDO::FETCH_ASSOC);
-
- $parent = $links['menu-test/hidden/menu'];
- $depth = $parent['depth'] + 1;
- $plid = $parent['mlid'];
-
- $link = $links['menu-test/hidden/menu/list'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/add'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/settings'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/manage/%'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $parent = $links['menu-test/hidden/menu/manage/%'];
- $depth = $parent['depth'] + 1;
- $plid = $parent['mlid'];
-
- $link = $links['menu-test/hidden/menu/manage/%/list'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/manage/%/add'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/manage/%/edit'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/menu/manage/%/delete'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- // Verify links for two dynamic arguments.
- $links = db_select('menu_links', 'ml')
- ->fields('ml')
- ->condition('ml.router_path', 'menu-test/hidden/block%', 'LIKE')
- ->orderBy('ml.router_path')
- ->execute()
- ->fetchAllAssoc('router_path', PDO::FETCH_ASSOC);
-
- $parent = $links['menu-test/hidden/block'];
- $depth = $parent['depth'] + 1;
- $plid = $parent['mlid'];
-
- $link = $links['menu-test/hidden/block/list'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/block/add'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/block/manage/%/%'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $parent = $links['menu-test/hidden/block/manage/%/%'];
- $depth = $parent['depth'] + 1;
- $plid = $parent['mlid'];
-
- $link = $links['menu-test/hidden/block/manage/%/%/configure'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%path plid @link_plid is equal to @plid.', array('%path' => $link['router_path'], '@link_plid' => $link['plid'], '@plid' => $plid)));
-
- $link = $links['menu-test/hidden/block/manage/%/%/delete'];
- $this->assertEqual($link['depth'], $depth, format_string('%path depth @link_depth is equal to @depth.', array('%path' => $link['router_path'], '@link_depth' => $link['depth'], '@depth' => $depth)));
- $this->assertEqual($link['plid'], $plid, format_string('%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().
- */
- function testMenuSetItem() {
- $item = menu_get_item('node');
-
- $this->assertEqual($item['path'], 'node', "Path from menu_get_item('node') is equal to 'node'", 'menu');
-
- // Modify the path for the item then save it.
- $item['path'] = 'node_test';
- $item['href'] = 'node_test';
-
- menu_set_item('node', $item);
- $compare_item = menu_get_item('node');
- $this->assertEqual($compare_item, $item, 'Modified menu item is equal to newly retrieved menu item.', 'menu');
- }
-
- /**
- * Test menu maintenance hooks.
- */
- function testMenuItemHooks() {
- // Create an item.
- menu_link_maintain('menu_test', 'insert', 'menu_test_maintain/4', 'Menu link #4');
- $this->assertEqual(menu_test_static_variable(), 'insert', 'hook_menu_link_insert() fired correctly');
- // Update the item.
- menu_link_maintain('menu_test', 'update', 'menu_test_maintain/4', 'Menu link updated');
- $this->assertEqual(menu_test_static_variable(), 'update', 'hook_menu_link_update() fired correctly');
- // Delete the item.
- menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', '');
- $this->assertEqual(menu_test_static_variable(), 'delete', 'hook_menu_link_delete() fired correctly');
- }
-
- /**
- * Test menu link 'options' storage and rendering.
- */
- function testMenuLinkOptions() {
- // Create a menu link with options.
- $menu_link = array(
- 'link_title' => 'Menu link options test',
- 'link_path' => 'node',
- 'module' => 'menu_test',
- 'options' => array(
- 'attributes' => array(
- 'title' => 'Test title attribute',
- ),
- 'query' => array(
- 'testparam' => 'testvalue',
- ),
- ),
- );
- menu_link_save($menu_link);
-
- // Load front page.
- $this->drupalGet('node');
- $this->assertRaw('title="Test title attribute"', 'Title attribute of a menu link renders.');
- $this->assertRaw('testparam=testvalue', 'Query parameter added to menu link.');
- }
-
- /**
- * Tests the possible ways to set the title for menu items.
- * Also tests that menu item titles work with string overrides.
- */
- function testMenuItemTitlesCases() {
-
- // Build array with string overrides.
- $test_data = array(
- 1 => array('Example title - Case 1' => 'Alternative example title - Case 1'),
- 2 => array('Example @sub1 - Case @op2' => 'Alternative example @sub1 - Case @op2'),
- 3 => array('Example title' => 'Alternative example title'),
- 4 => array('Example title' => 'Alternative example title'),
- );
-
- foreach ($test_data as $case_no => $override) {
- $this->menuItemTitlesCasesHelper($case_no);
- variable_set('locale_custom_strings_en', array('' => $override));
- $this->menuItemTitlesCasesHelper($case_no, TRUE);
- variable_set('locale_custom_strings_en', array());
- }
- }
-
- /**
- * Get a URL and assert the title given a case number. If override is true,
- * the title is asserted to begin with "Alternative".
- */
- private function menuItemTitlesCasesHelper($case_no, $override = FALSE) {
- $this->drupalGet('menu-title-test/case' . $case_no);
- $this->assertResponse(200);
- $asserted_title = $override ? 'Alternative example title - Case ' . $case_no : 'Example title - Case ' . $case_no;
- $this->assertTitle($asserted_title . ' | Drupal', format_string('Menu title is: %title.', array('%title' => $asserted_title)), 'Menu');
- }
-
- /**
- * Load the router for a given path.
- */
- protected function menuLoadRouter($router_path) {
- return db_query('SELECT * FROM {menu_router} WHERE path = :path', array(':path' => $router_path))->fetchAssoc();
- }
-
- /**
- * Tests inheritance of 'load arguments'.
- */
- function testMenuLoadArgumentsInheritance() {
- $expected = array(
- 'menu-test/arguments/%/%' => array(
- 2 => array('menu_test_argument_load' => array(3)),
- 3 => NULL,
- ),
- // Arguments are inherited to normal children.
- 'menu-test/arguments/%/%/default' => array(
- 2 => array('menu_test_argument_load' => array(3)),
- 3 => NULL,
- ),
- // Arguments are inherited to tab children.
- 'menu-test/arguments/%/%/task' => array(
- 2 => array('menu_test_argument_load' => array(3)),
- 3 => NULL,
- ),
- // Arguments are only inherited to the same loader functions.
- 'menu-test/arguments/%/%/common-loader' => array(
- 2 => array('menu_test_argument_load' => array(3)),
- 3 => 'menu_test_other_argument_load',
- ),
- // Arguments are not inherited to children not using the same loader
- // function.
- 'menu-test/arguments/%/%/different-loaders-1' => array(
- 2 => NULL,
- 3 => 'menu_test_argument_load',
- ),
- 'menu-test/arguments/%/%/different-loaders-2' => array(
- 2 => 'menu_test_other_argument_load',
- 3 => NULL,
- ),
- 'menu-test/arguments/%/%/different-loaders-3' => array(
- 2 => NULL,
- 3 => NULL,
- ),
- // Explicit loader arguments should not be overriden by parent.
- 'menu-test/arguments/%/%/explicit-arguments' => array(
- 2 => array('menu_test_argument_load' => array()),
- 3 => NULL,
- ),
- );
-
- foreach ($expected as $router_path => $load_functions) {
- $router_item = $this->menuLoadRouter($router_path);
- $this->assertIdentical(unserialize($router_item['load_functions']), $load_functions, format_string('Expected load functions for router %router_path' , array('%router_path' => $router_path)));
- }
- }
-}
-
-/**
- * Tests for menu links.
- */
-class MenuLinksUnitTestCase extends DrupalWebTestCase {
- // Use the lightweight testing profile for this test.
- protected $profile = 'testing';
-
- public static function getInfo() {
- return array(
- 'name' => 'Menu links',
- 'description' => 'Test handling of menu links hierarchies.',
- 'group' => 'Menu',
- );
- }
-
- /**
- * Create a simple hierarchy of links.
- */
- function createLinkHierarchy($module = 'menu_test') {
- // First remove all the menu links.
- db_truncate('menu_links')->execute();
-
- // Then create a simple link hierarchy:
- // - $parent
- // - $child-1
- // - $child-1-1
- // - $child-1-2
- // - $child-2
- $base_options = array(
- 'link_title' => 'Menu link test',
- 'module' => $module,
- 'menu_name' => 'menu_test',
- );
-
- $links['parent'] = $base_options + array(
- 'link_path' => 'menu-test/parent',
- );
- menu_link_save($links['parent']);
-
- $links['child-1'] = $base_options + array(
- 'link_path' => 'menu-test/parent/child-1',
- 'plid' => $links['parent']['mlid'],
- );
- menu_link_save($links['child-1']);
-
- $links['child-1-1'] = $base_options + array(
- 'link_path' => 'menu-test/parent/child-1/child-1-1',
- 'plid' => $links['child-1']['mlid'],
- );
- menu_link_save($links['child-1-1']);
-
- $links['child-1-2'] = $base_options + array(
- 'link_path' => 'menu-test/parent/child-1/child-1-2',
- 'plid' => $links['child-1']['mlid'],
- );
- menu_link_save($links['child-1-2']);
-
- $links['child-2'] = $base_options + array(
- 'link_path' => 'menu-test/parent/child-2',
- 'plid' => $links['parent']['mlid'],
- );
- menu_link_save($links['child-2']);
-
- return $links;
- }
-
- /**
- * Assert that at set of links is properly parented.
- */
- function assertMenuLinkParents($links, $expected_hierarchy) {
- foreach ($expected_hierarchy as $child => $parent) {
- $mlid = $links[$child]['mlid'];
- $plid = $parent ? $links[$parent]['mlid'] : 0;
-
- $menu_link = menu_link_load($mlid);
- menu_link_save($menu_link);
- $this->assertEqual($menu_link['plid'], $plid, format_string('Menu link %mlid has parent of %plid, expected %expected_plid.', array('%mlid' => $mlid, '%plid' => $menu_link['plid'], '%expected_plid' => $plid)));
- }
- }
-
- /**
- * Test automatic reparenting of menu links.
- */
- function testMenuLinkReparenting($module = 'menu_test') {
- // Check the initial hierarchy.
- $links = $this->createLinkHierarchy($module);
-
- $expected_hierarchy = array(
- 'parent' => FALSE,
- 'child-1' => 'parent',
- 'child-1-1' => 'child-1',
- 'child-1-2' => 'child-1',
- 'child-2' => 'parent',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
-
- // Start over, and move child-1 under child-2, and check that all the
- // childs of child-1 have been moved too.
- $links = $this->createLinkHierarchy($module);
- $links['child-1']['plid'] = $links['child-2']['mlid'];
- menu_link_save($links['child-1']);
-
- $expected_hierarchy = array(
- 'parent' => FALSE,
- 'child-1' => 'child-2',
- 'child-1-1' => 'child-1',
- 'child-1-2' => 'child-1',
- 'child-2' => 'parent',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
-
- // Start over, and delete child-1, and check that the children of child-1
- // have been reassigned to the parent. menu_link_delete() will cowardly
- // refuse to delete a menu link defined by the system module, so skip the
- // test in that case.
- if ($module != 'system') {
- $links = $this->createLinkHierarchy($module);
- menu_link_delete($links['child-1']['mlid']);
-
- $expected_hierarchy = array(
- 'parent' => FALSE,
- 'child-1-1' => 'parent',
- 'child-1-2' => 'parent',
- 'child-2' => 'parent',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
- }
-
- // Start over, forcefully delete child-1 from the database, simulating a
- // database crash. Check that the children of child-1 have been reassigned
- // to the parent, going up on the old path hierarchy stored in each of the
- // links.
- $links = $this->createLinkHierarchy($module);
- // Don't do that at home.
- db_delete('menu_links')
- ->condition('mlid', $links['child-1']['mlid'])
- ->execute();
-
- $expected_hierarchy = array(
- 'parent' => FALSE,
- 'child-1-1' => 'parent',
- 'child-1-2' => 'parent',
- 'child-2' => 'parent',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
-
- // Start over, forcefully delete the parent from the database, simulating a
- // database crash. Check that the children of parent are now top-level.
- $links = $this->createLinkHierarchy($module);
- // Don't do that at home.
- db_delete('menu_links')
- ->condition('mlid', $links['parent']['mlid'])
- ->execute();
-
- $expected_hierarchy = array(
- 'child-1-1' => 'child-1',
- 'child-1-2' => 'child-1',
- 'child-2' => FALSE,
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
- }
-
- /**
- * Test automatic reparenting of menu links derived from menu routers.
- */
- function testMenuLinkRouterReparenting() {
- // Run all the standard parenting tests on menu links derived from
- // menu routers.
- $this->testMenuLinkReparenting('system');
-
- // Additionnaly, test reparenting based on path.
- $links = $this->createLinkHierarchy('system');
-
- // Move child-1-2 has a child of child-2, making the link hierarchy
- // inconsistent with the path hierarchy.
- $links['child-1-2']['plid'] = $links['child-2']['mlid'];
- menu_link_save($links['child-1-2']);
-
- // Check the new hierarchy.
- $expected_hierarchy = array(
- 'parent' => FALSE,
- 'child-1' => 'parent',
- 'child-1-1' => 'child-1',
- 'child-2' => 'parent',
- 'child-1-2' => 'child-2',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
-
- // Now delete 'parent' directly from the database, simulating a database
- // crash. 'child-1' and 'child-2' should get moved to the
- // top-level.
- // Don't do that at home.
- db_delete('menu_links')
- ->condition('mlid', $links['parent']['mlid'])
- ->execute();
- $expected_hierarchy = array(
- 'child-1' => FALSE,
- 'child-1-1' => 'child-1',
- 'child-2' => FALSE,
- 'child-1-2' => 'child-2',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
-
- // Now delete 'child-2' directly from the database, simulating a database
- // crash. 'child-1-2' will get reparented under 'child-1' based on its
- // path.
- // Don't do that at home.
- db_delete('menu_links')
- ->condition('mlid', $links['child-2']['mlid'])
- ->execute();
- $expected_hierarchy = array(
- 'child-1' => FALSE,
- 'child-1-1' => 'child-1',
- 'child-1-2' => 'child-1',
- );
- $this->assertMenuLinkParents($links, $expected_hierarchy);
- }
-}
-
-/**
- * Tests rebuilding the menu by setting 'menu_rebuild_needed.'
- */
-class MenuRebuildTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Menu rebuild test',
- 'description' => 'Test rebuilding of menu.',
- 'group' => 'Menu',
- );
- }
-
- /**
- * Test if the 'menu_rebuild_needed' variable triggers a menu_rebuild() call.
- */
- function testMenuRebuildByVariable() {
- // Check if 'admin' path exists.
- $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
- $this->assertEqual($admin_exists, 'admin', "The path 'admin/' exists prior to deleting.");
-
- // Delete the path item 'admin', and test that the path doesn't exist in the database.
- $delete = db_delete('menu_router')
- ->condition('path', 'admin')
- ->execute();
- $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
- $this->assertFalse($admin_exists, "The path 'admin/' has been deleted and doesn't exist in the database.");
-
- // Now we enable the rebuild variable and trigger menu_execute_active_handler()
- // to rebuild the menu item. Now 'admin' should exist.
- variable_set('menu_rebuild_needed', TRUE);
- // menu_execute_active_handler() should trigger the rebuild.
- $this->drupalGet('');
- $admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
- $this->assertEqual($admin_exists, 'admin', "The menu has been rebuilt, the path 'admin' now exists again.");
- }
-
-}
-
-/**
- * Menu tree data related tests.
- */
-class MenuTreeDataTestCase extends DrupalUnitTestCase {
- /**
- * Dummy link structure acceptable for menu_tree_data().
- */
- var $links = array(
- 1 => array('mlid' => 1, 'depth' => 1),
- 2 => array('mlid' => 2, 'depth' => 1),
- 3 => array('mlid' => 3, 'depth' => 2),
- 4 => array('mlid' => 4, 'depth' => 3),
- 5 => array('mlid' => 5, 'depth' => 1),
- );
-
- public static function getInfo() {
- return array(
- 'name' => 'Menu tree generation',
- 'description' => 'Tests recursive menu tree generation functions.',
- 'group' => 'Menu',
- );
- }
-
- /**
- * Validate the generation of a proper menu tree hierarchy.
- */
- function testMenuTreeData() {
- $tree = menu_tree_data($this->links);
-
- // Validate that parent items #1, #2, and #5 exist on the root level.
- $this->assertSameLink($this->links[1], $tree[1]['link'], 'Parent item #1 exists.');
- $this->assertSameLink($this->links[2], $tree[2]['link'], 'Parent item #2 exists.');
- $this->assertSameLink($this->links[5], $tree[5]['link'], 'Parent item #5 exists.');
-
- // Validate that child item #4 exists at the correct location in the hierarchy.
- $this->assertSameLink($this->links[4], $tree[2]['below'][3]['below'][4]['link'], 'Child item #4 exists in the hierarchy.');
- }
-
- /**
- * Check that two menu links are the same by comparing the mlid.
- *
- * @param $link1
- * A menu link item.
- * @param $link2
- * A menu link item.
- * @param $message
- * The message to display along with the assertion.
- * @return
- * TRUE if the assertion succeeded, FALSE otherwise.
- */
- protected function assertSameLink($link1, $link2, $message = '') {
- return $this->assert($link1['mlid'] == $link2['mlid'], $message ? $message : 'First link is identical to second link');
- }
-}
-
-/**
- * Menu tree output related tests.
- */
-class MenuTreeOutputTestCase extends DrupalWebTestCase {
- /**
- * Dummy link structure acceptable for menu_tree_output().
- */
- var $tree_data = array(
- '1'=> array(
- 'link' => array( 'menu_name' => 'main-menu', 'mlid' => 1, 'hidden'=>0, 'has_children' => 1, 'title' => 'Item 1', 'in_active_trail' => 1, 'access'=>1, 'href' => 'a', 'localized_options' => array('attributes' => array('title' =>'')) ),
- 'below' => array(
- '2' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 2, 'hidden'=>0, 'has_children' => 1, 'title' => 'Item 2', 'in_active_trail' => 1, 'access'=>1, 'href' => 'a/b', 'localized_options' => array('attributes' => array('title' =>'')) ),
- 'below' => array(
- '3' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 3, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 3', 'in_active_trail' => 0, 'access'=>1, 'href' => 'a/b/c', 'localized_options' => array('attributes' => array('title' =>'')) ),
- 'below' => array() ),
- '4' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 4, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 4', 'in_active_trail' => 0, 'access'=>1, 'href' => 'a/b/d', 'localized_options' => array('attributes' => array('title' =>'')) ),
- 'below' => array() )
- )
- )
- )
- ),
- '5' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 5, 'hidden'=>1, 'has_children' => 0, 'title' => 'Item 5', 'in_active_trail' => 0, 'access'=>1, 'href' => 'e', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) ),
- '6' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 6, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 6', 'in_active_trail' => 0, 'access'=>0, 'href' => 'f', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) ),
- '7' => array('link' => array( 'menu_name' => 'main-menu', 'mlid' => 7, 'hidden'=>0, 'has_children' => 0, 'title' => 'Item 7', 'in_active_trail' => 0, 'access'=>1, 'href' => 'g', 'localized_options' => array('attributes' => array('title' =>'')) ), 'below' => array( ) )
- );
-
- public static function getInfo() {
- return array(
- 'name' => 'Menu tree output',
- 'description' => 'Tests menu tree output functions.',
- 'group' => 'Menu',
- );
- }
-
- function setUp() {
- parent::setUp();
- }
-
- /**
- * Validate the generation of a proper menu tree output.
- */
- function testMenuTreeData() {
- $output = menu_tree_output($this->tree_data);
-
- // Validate that the - in main-menu is changed into an underscore
- $this->assertEqual($output['1']['#theme'], 'menu_link__main_menu', 'Hyphen is changed to an underscore on menu_link');
- $this->assertEqual($output['#theme_wrappers'][0], 'menu_tree__main_menu', 'Hyphen is changed to an underscore on menu_tree wrapper');
- // Looking for child items in the data
- $this->assertEqual( $output['1']['#below']['2']['#href'], 'a/b', 'Checking the href on a child item');
- $this->assertTrue( in_array('active-trail',$output['1']['#below']['2']['#attributes']['class']) , 'Checking the active trail class');
- // Validate that the hidden and no access items are missing
- $this->assertFalse( isset($output['5']), 'Hidden item should be missing');
- $this->assertFalse( isset($output['6']), 'False access should be missing');
- // Item 7 is after a couple hidden items. Just to make sure that 5 and 6 are skipped and 7 still included
- $this->assertTrue( isset($output['7']), 'Item after hidden items is present');
- }
-}
-
-/**
- * Menu breadcrumbs related tests.
- */
-class MenuBreadcrumbTestCase extends MenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Breadcrumbs',
- 'description' => 'Tests breadcrumbs functionality.',
- 'group' => 'Menu',
- );
- }
-
- function setUp() {
- $modules = func_get_args();
- if (isset($modules[0]) && is_array($modules[0])) {
- $modules = $modules[0];
- }
- $modules[] = 'menu_test';
- parent::setUp($modules);
- $perms = array_keys(module_invoke_all('permission'));
- $this->admin_user = $this->drupalCreateUser($perms);
- $this->drupalLogin($this->admin_user);
-
- // This test puts menu links in the Navigation menu and then tests for
- // their presence on the page, so we need to ensure that the Navigation
- // block will be displayed in all active themes.
- db_update('block')
- ->fields(array(
- // Use a region that is valid for all themes.
- 'region' => 'content',
- 'status' => 1,
- ))
- ->condition('module', 'system')
- ->condition('delta', 'navigation')
- ->execute();
- }
-
- /**
- * Tests breadcrumbs on node and administrative paths.
- */
- function testBreadCrumbs() {
- // Prepare common base breadcrumb elements.
- $home = array('' => 'Home');
- $admin = $home + array('admin' => t('Administration'));
- $config = $admin + array('admin/config' => t('Configuration'));
- $type = 'article';
- $langcode = LANGUAGE_NONE;
-
- // Verify breadcrumbs for default local tasks.
- $expected = array(
- 'menu-test' => t('Menu test root'),
- );
- $title = t('Breadcrumbs test: Local tasks');
- $trail = $home + $expected;
- $tree = $expected + array(
- 'menu-test/breadcrumb/tasks' => $title,
- );
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks', $trail, $title, $tree);
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first', $trail, $title, $tree);
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/first', $trail, $title, $tree);
- $trail += array(
- 'menu-test/breadcrumb/tasks' => t('Breadcrumbs test: Local tasks'),
- );
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/second', $trail, $title, $tree);
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second', $trail, $title, $tree);
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/first', $trail, $title, $tree);
- $trail += array(
- 'menu-test/breadcrumb/tasks/second' => t('Second'),
- );
- $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/second', $trail, $title, $tree);
-
- // Verify Taxonomy administration breadcrumbs.
- $trail = $admin + array(
- 'admin/structure' => t('Structure'),
- );
- $this->assertBreadcrumb('admin/structure/taxonomy', $trail);
-
- $trail += array(
- 'admin/structure/taxonomy' => t('Taxonomy'),
- );
- $this->assertBreadcrumb('admin/structure/taxonomy/tags', $trail);
- $trail += array(
- 'admin/structure/taxonomy/tags' => t('Tags'),
- );
- $this->assertBreadcrumb('admin/structure/taxonomy/tags/edit', $trail);
- $this->assertBreadcrumb('admin/structure/taxonomy/tags/fields', $trail);
- $this->assertBreadcrumb('admin/structure/taxonomy/tags/add', $trail);
-
- // Verify Menu administration breadcrumbs.
- $trail = $admin + array(
- 'admin/structure' => t('Structure'),
- );
- $this->assertBreadcrumb('admin/structure/menu', $trail);
-
- $trail += array(
- 'admin/structure/menu' => t('Menus'),
- );
- $this->assertBreadcrumb('admin/structure/menu/manage/navigation', $trail);
- $trail += array(
- 'admin/structure/menu/manage/navigation' => t('Navigation'),
- );
- $this->assertBreadcrumb("admin/structure/menu/item/6/edit", $trail);
- $this->assertBreadcrumb('admin/structure/menu/manage/navigation/edit', $trail);
- $this->assertBreadcrumb('admin/structure/menu/manage/navigation/add', $trail);
-
- // Verify Node administration breadcrumbs.
- $trail = $admin + array(
- 'admin/structure' => t('Structure'),
- 'admin/structure/types' => t('Content types'),
- );
- $this->assertBreadcrumb('admin/structure/types/add', $trail);
- $this->assertBreadcrumb("admin/structure/types/manage/$type", $trail);
- $trail += array(
- "admin/structure/types/manage/$type" => t('Article'),
- );
- $this->assertBreadcrumb("admin/structure/types/manage/$type/fields", $trail);
- $this->assertBreadcrumb("admin/structure/types/manage/$type/display", $trail);
- $trail_teaser = $trail + array(
- "admin/structure/types/manage/$type/display" => t('Manage display'),
- );
- $this->assertBreadcrumb("admin/structure/types/manage/$type/display/teaser", $trail_teaser);
- $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/fields", $trail);
- $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/display", $trail);
- $this->assertBreadcrumb("admin/structure/types/manage/$type/delete", $trail);
- $trail += array(
- "admin/structure/types/manage/$type/fields" => t('Manage fields'),
- );
- $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body", $trail);
- $trail += array(
- "admin/structure/types/manage/$type/fields/body" => t('Body'),
- );
- $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body/widget-type", $trail);
-
- // Verify Filter text format administration breadcrumbs.
- $format = db_query_range("SELECT format, name FROM {filter_format}", 1, 1)->fetch();
- $format_id = $format->format;
- $trail = $config + array(
- 'admin/config/content' => t('Content authoring'),
- );
- $this->assertBreadcrumb('admin/config/content/formats', $trail);
-
- $trail += array(
- 'admin/config/content/formats' => t('Text formats'),
- );
- $this->assertBreadcrumb('admin/config/content/formats/add', $trail);
- $this->assertBreadcrumb("admin/config/content/formats/$format_id", $trail);
- $trail += array(
- "admin/config/content/formats/$format_id" => $format->name,
- );
- $this->assertBreadcrumb("admin/config/content/formats/$format_id/disable", $trail);
-
- // Verify node breadcrumbs (without menu link).
- $node1 = $this->drupalCreateNode();
- $nid1 = $node1->nid;
- $trail = $home;
- $this->assertBreadcrumb("node/$nid1", $trail);
- // Also verify that the node does not appear elsewhere (e.g., menu trees).
- $this->assertNoLink($node1->title);
- // The node itself should not be contained in the breadcrumb on the default
- // local task, since there is no difference between both pages.
- $this->assertBreadcrumb("node/$nid1/view", $trail);
- // Also verify that the node does not appear elsewhere (e.g., menu trees).
- $this->assertNoLink($node1->title);
-
- $trail += array(
- "node/$nid1" => $node1->title,
- );
- $this->assertBreadcrumb("node/$nid1/edit", $trail);
-
- // Verify that breadcrumb on node listing page contains "Home" only.
- $trail = array();
- $this->assertBreadcrumb('node', $trail);
-
- // Verify node breadcrumbs (in menu).
- // Do this separately for Main menu and Navigation menu, since only the
- // latter is a preferred menu by default.
- // @todo Also test all themes? Manually testing led to the suspicion that
- // breadcrumbs may differ, possibly due to template.php overrides.
- $menus = array('main-menu', 'navigation');
- // Alter node type menu settings.
- variable_set("menu_options_$type", $menus);
- variable_set("menu_parent_$type", 'navigation:0');
-
- foreach ($menus as $menu) {
- // Create a parent node in the current menu.
- $title = $this->randomName();
- $node2 = $this->drupalCreateNode(array(
- 'type' => $type,
- 'title' => $title,
- 'menu' => array(
- 'enabled' => 1,
- 'link_title' => 'Parent ' . $title,
- 'description' => '',
- 'menu_name' => $menu,
- 'plid' => 0,
- ),
- ));
- $nid2 = $node2->nid;
-
- $trail = $home;
- $tree = array(
- "node/$nid2" => $node2->menu['link_title'],
- );
- $this->assertBreadcrumb("node/$nid2", $trail, $node2->title, $tree);
- // The node itself should not be contained in the breadcrumb on the
- // default local task, since there is no difference between both pages.
- $this->assertBreadcrumb("node/$nid2/view", $trail, $node2->title, $tree);
- $trail += array(
- "node/$nid2" => $node2->menu['link_title'],
- );
- $this->assertBreadcrumb("node/$nid2/edit", $trail);
-
- // Create a child node in the current menu.
- $title = $this->randomName();
- $node3 = $this->drupalCreateNode(array(
- 'type' => $type,
- 'title' => $title,
- 'menu' => array(
- 'enabled' => 1,
- 'link_title' => 'Child ' . $title,
- 'description' => '',
- 'menu_name' => $menu,
- 'plid' => $node2->menu['mlid'],
- ),
- ));
- $nid3 = $node3->nid;
-
- $this->assertBreadcrumb("node/$nid3", $trail, $node3->title, $tree, FALSE);
- // The node itself should not be contained in the breadcrumb on the
- // default local task, since there is no difference between both pages.
- $this->assertBreadcrumb("node/$nid3/view", $trail, $node3->title, $tree, FALSE);
- $trail += array(
- "node/$nid3" => $node3->menu['link_title'],
- );
- $tree += array(
- "node/$nid3" => $node3->menu['link_title'],
- );
- $this->assertBreadcrumb("node/$nid3/edit", $trail);
-
- // Verify that node listing page still contains "Home" only.
- $trail = array();
- $this->assertBreadcrumb('node', $trail);
-
- if ($menu == 'navigation') {
- $parent = $node2;
- $child = $node3;
- }
- }
-
- // Create a Navigation menu link for 'node', move the last parent node menu
- // link below it, and verify a full breadcrumb for the last child node.
- $menu = 'navigation';
- $edit = array(
- 'link_title' => 'Root',
- 'link_path' => 'node',
- );
- $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
- $link = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(':title' => 'Root'))->fetchAssoc();
-
- $edit = array(
- 'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'],
- );
- $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
- $expected = array(
- "node" => $link['link_title'],
- );
- $trail = $home + $expected;
- $tree = $expected + array(
- "node/{$parent->nid}" => $parent->menu['link_title'],
- );
- $this->assertBreadcrumb(NULL, $trail, $parent->title, $tree);
- $trail += array(
- "node/{$parent->nid}" => $parent->menu['link_title'],
- );
- $tree += array(
- "node/{$child->nid}" => $child->menu['link_title'],
- );
- $this->assertBreadcrumb("node/{$child->nid}", $trail, $child->title, $tree);
-
- // Add a taxonomy term/tag to last node, and add a link for that term to the
- // Navigation menu.
- $tags = array(
- 'Drupal' => array(),
- 'Breadcrumbs' => array(),
- );
- $edit = array(
- "field_tags[$langcode]" => implode(',', array_keys($tags)),
- );
- $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
-
- // Put both terms into a hierarchy Drupal » Breadcrumbs. Required for both
- // the menu links and the terms itself, since taxonomy_term_page() resets
- // the breadcrumb based on taxonomy term hierarchy.
- $parent_tid = 0;
- foreach ($tags as $name => $null) {
- $terms = taxonomy_term_load_multiple(NULL, array('name' => $name));
- $term = reset($terms);
- $tags[$name]['term'] = $term;
- if ($parent_tid) {
- $edit = array(
- 'parent[]' => array($parent_tid),
- );
- $this->drupalPost("taxonomy/term/{$term->tid}/edit", $edit, t('Save'));
- }
- $parent_tid = $term->tid;
- }
- $parent_mlid = 0;
- foreach ($tags as $name => $data) {
- $term = $data['term'];
- $edit = array(
- 'link_title' => "$name link",
- 'link_path' => "taxonomy/term/{$term->tid}",
- 'parent' => "$menu:{$parent_mlid}",
- );
- $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
- $tags[$name]['link'] = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
- ':title' => $edit['link_title'],
- ':href' => $edit['link_path'],
- ))->fetchAssoc();
- $tags[$name]['link']['link_path'] = $edit['link_path'];
- $parent_mlid = $tags[$name]['link']['mlid'];
- }
-
- // Verify expected breadcrumbs for menu links.
- $trail = $home;
- $tree = array();
- foreach ($tags as $name => $data) {
- $term = $data['term'];
- $link = $data['link'];
-
- $tree += array(
- $link['link_path'] => $link['link_title'],
- );
- $this->assertBreadcrumb($link['link_path'], $trail, $term->name, $tree);
- $this->assertRaw(check_plain($parent->title), 'Tagged node found.');
-
- // Additionally make sure that this link appears only once; i.e., the
- // untranslated menu links automatically generated from menu router items
- // ('taxonomy/term/%') should never be translated and appear in any menu
- // other than the breadcrumb trail.
- $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
- ':menu' => 'block-system-navigation',
- ':href' => url($link['link_path']),
- ));
- $this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once.");
-
- // Next iteration should expect this tag as parent link.
- // Note: Term name, not link name, due to taxonomy_term_page().
- $trail += array(
- $link['link_path'] => $term->name,
- );
- }
-
- // Verify breadcrumbs on user and user/%.
- // We need to log back in and out below, and cannot simply grant the
- // 'administer users' permission, since user_page() makes your head explode.
- user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
- 'access user profiles',
- ));
- $this->drupalLogout();
-
- // Verify breadcrumb on front page.
- $this->assertBreadcrumb('', array());
-
- // Verify breadcrumb on user pages (without menu link) for anonymous user.
- $trail = $home;
- $this->assertBreadcrumb('user', $trail, t('User account'));
- $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name);
-
- // Verify breadcrumb on user pages (without menu link) for registered users.
- $this->drupalLogin($this->admin_user);
- $trail = $home;
- $this->assertBreadcrumb('user', $trail, $this->admin_user->name);
- $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name);
- $trail += array(
- 'user/' . $this->admin_user->uid => $this->admin_user->name,
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name);
-
- // Create a second user to verify breadcrumb on user pages again.
- $this->web_user = $this->drupalCreateUser(array(
- 'administer users',
- 'access user profiles',
- ));
- $this->drupalLogin($this->web_user);
-
- // Verify correct breadcrumb and page title on another user's account pages
- // (without menu link).
- $trail = $home;
- $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name);
- $trail += array(
- 'user/' . $this->admin_user->uid => $this->admin_user->name,
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name);
-
- // Verify correct breadcrumb and page title when viewing own user account
- // pages (without menu link).
- $trail = $home;
- $this->assertBreadcrumb('user/' . $this->web_user->uid, $trail, $this->web_user->name);
- $trail += array(
- 'user/' . $this->web_user->uid => $this->web_user->name,
- );
- $this->assertBreadcrumb('user/' . $this->web_user->uid . '/edit', $trail, $this->web_user->name);
-
- // Add a Navigation menu links for 'user' and $this->admin_user.
- // Although it may be faster to manage these links via low-level API
- // functions, there's a lot that can go wrong in doing so.
- $this->drupalLogin($this->admin_user);
- $edit = array(
- 'link_title' => 'User',
- 'link_path' => 'user',
- );
- $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
- $link_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
- ':title' => $edit['link_title'],
- ':href' => $edit['link_path'],
- ))->fetchAssoc();
-
- $edit = array(
- 'link_title' => $this->admin_user->name . ' link',
- 'link_path' => 'user/' . $this->admin_user->uid,
- );
- $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
- $link_admin_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
- ':title' => $edit['link_title'],
- ':href' => $edit['link_path'],
- ))->fetchAssoc();
-
- // Verify expected breadcrumbs for the two separate links.
- $this->drupalLogout();
- $trail = $home;
- $tree = array(
- $link_user['link_path'] => $link_user['link_title'],
- );
- $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
- $tree = array(
- $link_admin_user['link_path'] => $link_admin_user['link_title'],
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
-
- $this->drupalLogin($this->admin_user);
- $trail += array(
- $link_admin_user['link_path'] => $link_admin_user['link_title'],
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
-
- // Move 'user/%' below 'user' and verify again.
- $edit = array(
- 'parent' => "$menu:{$link_user['mlid']}",
- );
- $this->drupalPost("admin/structure/menu/item/{$link_admin_user['mlid']}/edit", $edit, t('Save'));
-
- $this->drupalLogout();
- $trail = $home;
- $tree = array(
- $link_user['link_path'] => $link_user['link_title'],
- );
- $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
- $trail += array(
- $link_user['link_path'] => $link_user['link_title'],
- );
- $tree += array(
- $link_admin_user['link_path'] => $link_admin_user['link_title'],
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
-
- $this->drupalLogin($this->admin_user);
- $trail += array(
- $link_admin_user['link_path'] => $link_admin_user['link_title'],
- );
- $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
-
- // Create an only slightly privileged user being able to access site reports
- // but not administration pages.
- $this->web_user = $this->drupalCreateUser(array(
- 'access site reports',
- ));
- $this->drupalLogin($this->web_user);
-
- // Verify that we can access recent log entries, there is a corresponding
- // page title, and that the breadcrumb is empty (because the user is not
- // able to access "Administer", so the trail cannot recurse into it).
- $trail = array();
- $this->assertBreadcrumb('admin', $trail, t('Access denied'));
- $this->assertResponse(403);
-
- $trail = $home;
- $this->assertBreadcrumb('admin/reports', $trail, t('Reports'));
- $this->assertNoResponse(403);
-
- $this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
- $this->assertNoResponse(403);
- }
-}
-
-/**
- * Tests active menu trails.
- */
-class MenuTrailTestCase extends MenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Active trail',
- 'description' => 'Tests active menu trails and alteration functionality.',
- 'group' => 'Menu',
- );
- }
-
- function setUp() {
- $modules = func_get_args();
- if (isset($modules[0]) && is_array($modules[0])) {
- $modules = $modules[0];
- }
- $modules[] = 'menu_test';
- parent::setUp($modules);
- $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages'));
- $this->drupalLogin($this->admin_user);
-
- // This test puts menu links in the Navigation menu and then tests for
- // their presence on the page, so we need to ensure that the Navigation
- // block will be displayed in all active themes.
- db_update('block')
- ->fields(array(
- // Use a region that is valid for all themes.
- 'region' => 'content',
- 'status' => 1,
- ))
- ->condition('module', 'system')
- ->condition('delta', 'navigation')
- ->execute();
-
- // This test puts menu links in the Management menu and then tests for
- // their presence on the page, so we need to ensure that the Management
- // block will be displayed in all active themes.
- db_update('block')
- ->fields(array(
- // Use a region that is valid for all themes.
- 'region' => 'content',
- 'status' => 1,
- ))
- ->condition('module', 'system')
- ->condition('delta', 'management')
- ->execute();
- }
-
- /**
- * Tests active trails are properly affected by menu_tree_set_path().
- */
- function testMenuTreeSetPath() {
- $home = array('' => 'Home');
- $config_tree = array(
- 'admin' => t('Administration'),
- 'admin/config' => t('Configuration'),
- );
- $config = $home + $config_tree;
-
- // The menu_test_menu_tree_set_path system variable controls whether or not
- // the menu_test_menu_trail_callback() callback (used by all paths in these
- // tests) issues an overriding call to menu_trail_set_path().
- $test_menu_path = array(
- 'menu_name' => 'management',
- 'path' => 'admin/config/system/site-information',
- );
-
- $breadcrumb = $home + array(
- 'menu-test' => t('Menu test root'),
- );
- $tree = array(
- 'menu-test' => t('Menu test root'),
- 'menu-test/menu-trail' => t('Menu trail - Case 1'),
- );
-
- // Test the tree generation for the Navigation menu.
- variable_del('menu_test_menu_tree_set_path');
- $this->assertBreadcrumb('menu-test/menu-trail', $breadcrumb, t('Menu trail - Case 1'), $tree);
-
- // Override the active trail for the Management tree; it should not affect
- // the Navigation tree.
- variable_set('menu_test_menu_tree_set_path', $test_menu_path);
- $this->assertBreadcrumb('menu-test/menu-trail', $breadcrumb, t('Menu trail - Case 1'), $tree);
-
- $breadcrumb = $config + array(
- 'admin/config/development' => t('Development'),
- );
- $tree = $config_tree + array(
- 'admin/config/development' => t('Development'),
- 'admin/config/development/menu-trail' => t('Menu trail - Case 2'),
- );
-
- $override_breadcrumb = $config + array(
- 'admin/config/system' => t('System'),
- 'admin/config/system/site-information' => t('Site information'),
- );
- $override_tree = $config_tree + array(
- 'admin/config/system' => t('System'),
- 'admin/config/system/site-information' => t('Site information'),
- );
-
- // Test the tree generation for the Management menu.
- variable_del('menu_test_menu_tree_set_path');
- $this->assertBreadcrumb('admin/config/development/menu-trail', $breadcrumb, t('Menu trail - Case 2'), $tree);
-
- // Override the active trail for the Management tree; it should affect the
- // breadcrumbs and Management tree.
- variable_set('menu_test_menu_tree_set_path', $test_menu_path);
- $this->assertBreadcrumb('admin/config/development/menu-trail', $override_breadcrumb, t('Menu trail - Case 2'), $override_tree);
- }
-
- /**
- * Tests that the active trail works correctly on custom 403 and 404 pages.
- */
- function testCustom403And404Pages() {
- // Set the custom 403 and 404 pages we will use.
- variable_set('site_403', 'menu-test/custom-403-page');
- variable_set('site_404', 'menu-test/custom-404-page');
-
- // Define the paths we'll visit to trigger 403 and 404 responses during
- // this test, and the expected active trail for each case.
- $paths = array(
- 403 => 'admin/config',
- 404 => $this->randomName(),
- );
- // For the 403 page, the initial trail during the Drupal bootstrap should
- // include the page that the user is trying to visit, while the final trail
- // should reflect the custom 403 page that the user was redirected to.
- $expected_trail[403]['initial'] = array(
- '' => 'Home',
- 'admin/config' => 'Configuration',
- );
- $expected_trail[403]['final'] = array(
- '' => 'Home',
- 'menu-test' => 'Menu test root',
- 'menu-test/custom-403-page' => 'Custom 403 page',
- );
- // For the 404 page, the initial trail during the Drupal bootstrap should
- // only contain the link back to "Home" (since the page the user is trying
- // to visit doesn't have any menu items associated with it), while the
- // final trail should reflect the custom 404 page that the user was
- // redirected to.
- $expected_trail[404]['initial'] = array(
- '' => 'Home',
- );
- $expected_trail[404]['final'] = array(
- '' => 'Home',
- 'menu-test' => 'Menu test root',
- 'menu-test/custom-404-page' => 'Custom 404 page',
- );
-
- // Visit each path as an anonymous user so that we will actually get a 403
- // on admin/config.
- $this->drupalLogout();
- foreach (array(403, 404) as $status_code) {
- // Before visiting the page, trigger the code in the menu_test module
- // that will record the active trail (so we can check it in this test).
- variable_set('menu_test_record_active_trail', TRUE);
- $this->drupalGet($paths[$status_code]);
- $this->assertResponse($status_code);
-
- // Check that the initial trail (during the Drupal bootstrap) matches
- // what we expect.
- $initial_trail = variable_get('menu_test_active_trail_initial', array());
- $this->assertEqual(count($initial_trail), count($expected_trail[$status_code]['initial']), format_string('The initial active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array(
- '@status_code' => $status_code,
- '@expected' => count($expected_trail[$status_code]['initial']),
- '@found' => count($initial_trail),
- )));
- foreach (array_keys($expected_trail[$status_code]['initial']) as $index => $path) {
- $this->assertEqual($initial_trail[$index]['href'], $path, format_string('Element number @number of the initial active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array(
- '@number' => $index + 1,
- '@status_code' => $status_code,
- '@expected' => $path,
- '@found' => $initial_trail[$index]['href'],
- )));
- }
-
- // Check that the final trail (after the user has been redirected to the
- // custom 403/404 page) matches what we expect.
- $final_trail = variable_get('menu_test_active_trail_final', array());
- $this->assertEqual(count($final_trail), count($expected_trail[$status_code]['final']), format_string('The final active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array(
- '@status_code' => $status_code,
- '@expected' => count($expected_trail[$status_code]['final']),
- '@found' => count($final_trail),
- )));
- foreach (array_keys($expected_trail[$status_code]['final']) as $index => $path) {
- $this->assertEqual($final_trail[$index]['href'], $path, format_string('Element number @number of the final active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array(
- '@number' => $index + 1,
- '@status_code' => $status_code,
- '@expected' => $path,
- '@found' => $final_trail[$index]['href'],
- )));
- }
-
- // Check that the breadcrumb displayed on the final custom 403/404 page
- // matches what we expect. (The last item of the active trail represents
- // the current page, which is not supposed to appear in the breadcrumb,
- // so we need to remove it from the array before checking.)
- array_pop($expected_trail[$status_code]['final']);
- $this->assertBreadcrumb(NULL, $expected_trail[$status_code]['final']);
- }
- }
-}
diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info
deleted file mode 100644
index bdb1cf96..00000000
--- a/modules/simpletest/tests/menu_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Hook menu tests"
-description = "Support module for menu hook testing."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module
deleted file mode 100644
index 0b954ae1..00000000
--- a/modules/simpletest/tests/menu_test.module
+++ /dev/null
@@ -1,563 +0,0 @@
- 'Test menu_name router item',
- 'page callback' => 'node_save',
- 'menu_name' => menu_test_menu_name(),
- );
- // This item is of type MENU_CALLBACK with no parents to test title.
- $items['menu_callback_title'] = array(
- 'title' => 'Menu Callback Title',
- 'page callback' => 'menu_test_callback',
- 'type' => MENU_CALLBACK,
- 'access arguments' => array('access content'),
- );
- // Use FALSE as 'title callback' to bypass t().
- $items['menu_no_title_callback'] = array(
- 'title' => 'A title with @placeholder',
- 'title callback' => FALSE,
- 'title arguments' => array('@placeholder' => 'some other text'),
- 'page callback' => 'menu_test_callback',
- 'access arguments' => array('access content'),
- );
-
- // Hidden link for menu_link_maintain tests
- $items['menu_test_maintain/%'] = array(
- 'title' => 'Menu maintain test',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- // Hierarchical tests.
- $items['menu-test/hierarchy/parent'] = array(
- 'title' => 'Parent menu router',
- 'page callback' => 'node_page_default',
- );
- $items['menu-test/hierarchy/parent/child'] = array(
- 'title' => 'Child menu router',
- 'page callback' => 'node_page_default',
- );
- $items['menu-test/hierarchy/parent/child2/child'] = array(
- 'title' => 'Unattached subchild router',
- 'page callback' => 'node_page_default',
- );
- // Theme callback tests.
- $items['menu-test/theme-callback/%'] = array(
- 'title' => 'Page that displays different themes',
- 'page callback' => 'menu_test_theme_page_callback',
- 'access arguments' => array('access content'),
- 'theme callback' => 'menu_test_theme_callback',
- 'theme arguments' => array(2),
- );
- $items['menu-test/theme-callback/%/inheritance'] = array(
- 'title' => 'Page that tests theme callback inheritance.',
- 'page callback' => 'menu_test_theme_page_callback',
- 'page arguments' => array(TRUE),
- 'access arguments' => array('access content'),
- );
- $items['menu-test/no-theme-callback'] = array(
- 'title' => 'Page that displays different themes without using a theme callback.',
- 'page callback' => 'menu_test_theme_page_callback',
- 'access arguments' => array('access content'),
- );
- // Path containing "exotic" characters.
- $path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
- "%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
- "éøïвβä¸åœ‹æ›¸Ûž"; // Characters from various non-ASCII alphabets.
- $items[$path] = array(
- 'title' => '"Exotic" path',
- 'page callback' => 'menu_test_callback',
- 'access arguments' => array('access content'),
- );
-
- // Hidden tests; base parents.
- // Same structure as in Menu and Block modules. Since those structures can
- // change, we need to simulate our own in here.
- $items['menu-test'] = array(
- 'title' => 'Menu test root',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/hidden'] = array(
- 'title' => 'Hidden test root',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
-
- // Hidden tests; one dynamic argument.
- $items['menu-test/hidden/menu'] = array(
- 'title' => 'Menus',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/hidden/menu/list'] = array(
- 'title' => 'List menus',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- $items['menu-test/hidden/menu/add'] = array(
- 'title' => 'Add menu',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_ACTION,
- );
- $items['menu-test/hidden/menu/settings'] = array(
- 'title' => 'Settings',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 5,
- );
- $items['menu-test/hidden/menu/manage/%menu'] = array(
- 'title' => 'Customize menu',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/hidden/menu/manage/%menu/list'] = array(
- 'title' => 'List links',
- 'weight' => -10,
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
- );
- $items['menu-test/hidden/menu/manage/%menu/add'] = array(
- 'title' => 'Add link',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_ACTION,
- );
- $items['menu-test/hidden/menu/manage/%menu/edit'] = array(
- 'title' => 'Edit menu',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
- );
- $items['menu-test/hidden/menu/manage/%menu/delete'] = array(
- 'title' => 'Delete menu',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
-
- // Hidden tests; two dynamic arguments.
- $items['menu-test/hidden/block'] = array(
- 'title' => 'Blocks',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/hidden/block/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- $items['menu-test/hidden/block/add'] = array(
- 'title' => 'Add block',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_ACTION,
- );
- $items['menu-test/hidden/block/manage/%/%'] = array(
- 'title' => 'Configure block',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/hidden/block/manage/%/%/configure'] = array(
- 'title' => 'Configure block',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'context' => MENU_CONTEXT_INLINE,
- );
- $items['menu-test/hidden/block/manage/%/%/delete'] = array(
- 'title' => 'Delete block',
- 'page callback' => 'node_page_default',
- 'access arguments' => array('access content'),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_NONE,
- );
-
- // Breadcrumbs tests.
- // @see MenuBreadcrumbTestCase
- $base = array(
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
- // Local tasks: Second level below default local task.
- $items['menu-test/breadcrumb/tasks'] = array(
- 'title' => 'Breadcrumbs test: Local tasks',
- ) + $base;
- $items['menu-test/breadcrumb/tasks/first'] = array(
- 'title' => 'First',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- ) + $base;
- $items['menu-test/breadcrumb/tasks/second'] = array(
- 'title' => 'Second',
- 'type' => MENU_LOCAL_TASK,
- ) + $base;
- $items['menu-test/breadcrumb/tasks/first/first'] = array(
- 'title' => 'First first',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- ) + $base;
- $items['menu-test/breadcrumb/tasks/first/second'] = array(
- 'title' => 'First second',
- 'type' => MENU_LOCAL_TASK,
- ) + $base;
- $items['menu-test/breadcrumb/tasks/second/first'] = array(
- 'title' => 'Second first',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- ) + $base;
- $items['menu-test/breadcrumb/tasks/second/second'] = array(
- 'title' => 'Second second',
- 'type' => MENU_LOCAL_TASK,
- ) + $base;
-
- // Menu trail tests.
- // @see MenuTrailTestCase
- $items['menu-test/menu-trail'] = array(
- 'title' => 'Menu trail - Case 1',
- 'page callback' => 'menu_test_menu_trail_callback',
- 'access arguments' => array('access content'),
- );
- $items['admin/config/development/menu-trail'] = array(
- 'title' => 'Menu trail - Case 2',
- 'description' => 'Tests menu_tree_set_path()',
- 'page callback' => 'menu_test_menu_trail_callback',
- 'access arguments' => array('access administration pages'),
- );
- $items['menu-test/custom-403-page'] = array(
- 'title' => 'Custom 403 page',
- 'page callback' => 'menu_test_custom_403_404_callback',
- 'access arguments' => array('access content'),
- );
- $items['menu-test/custom-404-page'] = array(
- 'title' => 'Custom 404 page',
- 'page callback' => 'menu_test_custom_403_404_callback',
- 'access arguments' => array('access content'),
- );
-
- // File inheritance tests. This menu item should inherit the page callback
- // system_admin_menu_block_page() and therefore render its children as links
- // on the page.
- $items['admin/config/development/file-inheritance'] = array(
- 'title' => 'File inheritance',
- 'description' => 'Test file inheritance',
- 'access arguments' => array('access content'),
- );
- $items['admin/config/development/file-inheritance/inherit'] = array(
- 'title' => 'Inherit',
- 'description' => 'File inheritance test description',
- 'page callback' => 'menu_test_callback',
- 'access arguments' => array('access content'),
- );
-
- $items['menu_login_callback'] = array(
- 'title' => 'Used as a login path',
- 'page callback' => 'menu_login_callback',
- 'access callback' => TRUE,
- );
-
- $items['menu-title-test/case1'] = array(
- 'title' => 'Example title - Case 1',
- 'access callback' => TRUE,
- 'page callback' => 'menu_test_callback',
- );
- $items['menu-title-test/case2'] = array(
- 'title' => 'Example @sub1 - Case @op2',
- // If '2' is not in quotes, the argument becomes arg(2).
- 'title arguments' => array('@sub1' => 'title', '@op2' => '2'),
- 'access callback' => TRUE,
- 'page callback' => 'menu_test_callback',
- );
- $items['menu-title-test/case3'] = array(
- 'title' => 'Example title',
- 'title callback' => 'menu_test_title_callback',
- 'access callback' => TRUE,
- 'page callback' => 'menu_test_callback',
- );
- $items['menu-title-test/case4'] = array(
- // Title gets completely ignored. Good thing, too.
- 'title' => 'Bike sheds full of blue smurfs',
- 'title callback' => 'menu_test_title_callback',
- // If '4' is not in quotes, the argument becomes arg(4).
- 'title arguments' => array('Example title', '4'),
- 'access callback' => TRUE,
- 'page callback' => 'menu_test_callback',
- );
-
- // Load arguments inheritance test.
- $items['menu-test/arguments/%menu_test_argument/%'] = array(
- 'title' => 'Load arguments inheritance test',
- 'load arguments' => array(3),
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
- $items['menu-test/arguments/%menu_test_argument/%/default'] = array(
- 'title' => 'Default local task',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['menu-test/arguments/%menu_test_argument/%/task'] = array(
- 'title' => 'Local task',
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- 'type' => MENU_LOCAL_TASK,
- );
- // For this path, load arguments should be inherited for the first loader only.
- $items['menu-test/arguments/%menu_test_argument/%menu_test_other_argument/common-loader'] = array(
- 'title' => 'Local task',
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- 'type' => MENU_LOCAL_TASK,
- );
- // For these paths, no load arguments should be inherited.
- // Not on the same position.
- $items['menu-test/arguments/%/%menu_test_argument/different-loaders-1'] = array(
- 'title' => 'An item not sharing the same loader',
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
- // Not the same loader.
- $items['menu-test/arguments/%menu_test_other_argument/%/different-loaders-2'] = array(
- 'title' => 'An item not sharing the same loader',
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
- // Not the same loader.
- $items['menu-test/arguments/%/%/different-loaders-3'] = array(
- 'title' => 'An item not sharing the same loader',
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
- // Explict load arguments should not be overriden (even if empty).
- $items['menu-test/arguments/%menu_test_argument/%/explicit-arguments'] = array(
- 'title' => 'An item defining explicit load arguments',
- 'load arguments' => array(),
- 'page callback' => 'menu_test_callback',
- 'access callback' => TRUE,
- );
-
- return $items;
-}
-
-/**
- * Dummy argument loader for hook_menu() to point to.
- */
-function menu_test_argument_load($arg1) {
- return FALSE;
-}
-
-/**
- * Dummy argument loader for hook_menu() to point to.
- */
-function menu_test_other_argument_load($arg1) {
- return FALSE;
-}
-
-/**
- * Dummy callback for hook_menu() to point to.
- *
- * @return
- * A random string.
- */
-function menu_test_callback() {
- return 'This is menu_test_callback().';
-}
-
-/**
- * Callback that test menu_test_menu_tree_set_path().
- */
-function menu_test_menu_trail_callback() {
- $menu_path = variable_get('menu_test_menu_tree_set_path', array());
- if (!empty($menu_path)) {
- menu_tree_set_path($menu_path['menu_name'], $menu_path['path']);
- }
- return 'This is menu_test_menu_trail_callback().';
-}
-
-/**
- * Implements hook_init().
- */
-function menu_test_init() {
- // When requested by one of the MenuTrailTestCase tests, record the initial
- // active trail during Drupal's bootstrap (before the user is redirected to a
- // custom 403 or 404 page). See menu_test_custom_403_404_callback().
- if (variable_get('menu_test_record_active_trail', FALSE)) {
- variable_set('menu_test_active_trail_initial', menu_get_active_trail());
- }
-}
-
-/**
- * Callback for our custom 403 and 404 pages.
- */
-function menu_test_custom_403_404_callback() {
- // When requested by one of the MenuTrailTestCase tests, record the final
- // active trail now that the user has been redirected to the custom 403 or
- // 404 page. See menu_test_init().
- if (variable_get('menu_test_record_active_trail', FALSE)) {
- variable_set('menu_test_active_trail_final', menu_get_active_trail());
- }
-
- return 'This is menu_test_custom_403_404_callback().';
-}
-
-/**
- * Page callback to use when testing the theme callback functionality.
- *
- * @param $inherited
- * An optional boolean to set to TRUE when the requested page is intended to
- * inherit the theme of its parent.
- * @return
- * A string describing the requested custom theme and actual theme being used
- * for the current page request.
- */
-function menu_test_theme_page_callback($inherited = FALSE) {
- global $theme_key;
- // Initialize the theme system so that $theme_key will be populated.
- drupal_theme_initialize();
- // Now check both the requested custom theme and the actual theme being used.
- $custom_theme = menu_get_custom_theme();
- $requested_theme = empty($custom_theme) ? 'NONE' : $custom_theme;
- $output = "Custom theme: $requested_theme. Actual theme: $theme_key.";
- if ($inherited) {
- $output .= ' Theme callback inheritance is being tested.';
- }
- return $output;
-}
-
-/**
- * Theme callback to use when testing the theme callback functionality.
- *
- * @param $argument
- * The argument passed in from the URL.
- * @return
- * The name of the custom theme to request for the current page.
- */
-function menu_test_theme_callback($argument) {
- // Test using the variable administrative theme.
- if ($argument == 'use-admin-theme') {
- return variable_get('admin_theme');
- }
- // Test using a theme that exists, but may or may not be enabled.
- elseif ($argument == 'use-stark-theme') {
- return 'stark';
- }
- // Test using a theme that does not exist.
- elseif ($argument == 'use-fake-theme') {
- return 'fake_theme';
- }
- // For any other value of the URL argument, do not return anything. This
- // allows us to test that returning nothing from a theme callback function
- // causes the page to correctly fall back on using the main site theme.
-}
-
-/**
- * Implement hook_custom_theme().
- *
- * @return
- * The name of the custom theme to use for the current page.
- */
-function menu_test_custom_theme() {
- // If an appropriate variable has been set in the database, request the theme
- // that is stored there. Otherwise, do not attempt to dynamically set the
- // theme.
- if ($theme = variable_get('menu_test_hook_custom_theme_name', FALSE)) {
- return $theme;
- }
-}
-
-/**
- * Helper function for the testMenuName() test. Used to change the menu_name
- * parameter of a menu.
- *
- * @param $new_name
- * If set, will change the menu_name value.
- * @return
- * The menu_name value to use.
- */
-function menu_test_menu_name($new_name = '') {
- static $name = 'original';
- if ($new_name) {
- $name = $new_name;
- }
- return $name;
-}
-
-/**
- * Implements hook_menu_link_insert().
- *
- * @return
- * A random string.
- */
-function menu_test_menu_link_insert($item) {
- menu_test_static_variable('insert');
-}
-
-/**
- * Implements hook_menu_link_update().
- *
- * @return
- * A random string.
- */
-function menu_test_menu_link_update($item) {
- menu_test_static_variable('update');
-}
-
-/**
- * Implements hook_menu_link_delete().
- *
- * @return
- * A random string.
- */
-function menu_test_menu_link_delete($item) {
- menu_test_static_variable('delete');
-}
-
-/**
- * Static function for testing hook results.
- *
- * @param $value
- * The value to set or NULL to return the current value.
- * @return
- * A text string for comparison to test assertions.
- */
-function menu_test_static_variable($value = NULL) {
- static $variable;
- if (!empty($value)) {
- $variable = $value;
- }
- return $variable;
-}
-
-/**
- * Implements hook_menu_site_status_alter().
- */
-function menu_test_menu_site_status_alter(&$menu_site_status, $path) {
- // Allow access to ?q=menu_login_callback even if in maintenance mode.
- if ($menu_site_status == MENU_SITE_OFFLINE && $path == 'menu_login_callback') {
- $menu_site_status = MENU_SITE_ONLINE;
- }
-}
-
-/**
- * Menu callback to be used as a login path.
- */
-function menu_login_callback() {
- return 'This is menu_login_callback().';
-}
-
-/**
- * Concatenates a string, by using the t() function and a case number.
- *
- * @param $title
- * Title string.
- * @param $case_number
- * The current case number which is tests (defaults to 3).
- */
-function menu_test_title_callback($title, $case_no = 3) {
- return t($title) . ' - Case ' . $case_no;
-}
diff --git a/modules/simpletest/tests/module.test b/modules/simpletest/tests/module.test
deleted file mode 100644
index 371339f3..00000000
--- a/modules/simpletest/tests/module.test
+++ /dev/null
@@ -1,304 +0,0 @@
- 'Module API',
- 'description' => 'Test low-level module functions.',
- 'group' => 'Module',
- );
- }
-
- /**
- * The basic functionality of module_list().
- */
- function testModuleList() {
- // Build a list of modules, sorted alphabetically.
- $profile_info = install_profile_info('standard', 'en');
- $module_list = $profile_info['dependencies'];
-
- // Installation profile is a module that is expected to be loaded.
- $module_list[] = 'standard';
-
- sort($module_list);
- // Compare this list to the one returned by module_list(). We expect them
- // to match, since all default profile modules have a weight equal to 0
- // (except for block.module, which has a lower weight but comes first in
- // the alphabet anyway).
- $this->assertModuleList($module_list, t('Standard profile'));
-
- // Try to install a new module.
- module_enable(array('contact'));
- $module_list[] = 'contact';
- sort($module_list);
- $this->assertModuleList($module_list, t('After adding a module'));
-
- // Try to mess with the module weights.
- db_update('system')
- ->fields(array('weight' => 20))
- ->condition('name', 'contact')
- ->condition('type', 'module')
- ->execute();
- // Reset the module list.
- module_list(TRUE);
- // Move contact to the end of the array.
- unset($module_list[array_search('contact', $module_list)]);
- $module_list[] = 'contact';
- $this->assertModuleList($module_list, t('After changing weights'));
-
- // Test the fixed list feature.
- $fixed_list = array(
- 'system' => array('filename' => drupal_get_path('module', 'system')),
- 'menu' => array('filename' => drupal_get_path('module', 'menu')),
- );
- module_list(FALSE, FALSE, FALSE, $fixed_list);
- $new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list));
- $this->assertModuleList($new_module_list, t('When using a fixed list'));
-
- // Reset the module list.
- module_list(TRUE);
- $this->assertModuleList($module_list, t('After reset'));
- }
-
- /**
- * Assert that module_list() return the expected values.
- *
- * @param $expected_values
- * The expected values, sorted by weight and module name.
- */
- protected function assertModuleList(Array $expected_values, $condition) {
- $expected_values = array_combine($expected_values, $expected_values);
- $this->assertEqual($expected_values, module_list(), format_string('@condition: module_list() returns correct results', array('@condition' => $condition)));
- ksort($expected_values);
- $this->assertIdentical($expected_values, module_list(FALSE, FALSE, TRUE), format_string('@condition: module_list() returns correctly sorted results', array('@condition' => $condition)));
- }
-
- /**
- * Test module_implements() caching.
- */
- function testModuleImplements() {
- // Clear the cache.
- cache_clear_all('module_implements', 'cache_bootstrap');
- $this->assertFalse(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is empty.');
- $this->drupalGet('');
- $this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
-
- // Test again with an authenticated user.
- $this->user = $this->drupalCreateUser();
- $this->drupalLogin($this->user);
- cache_clear_all('module_implements', 'cache_bootstrap');
- $this->drupalGet('');
- $this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
-
- // Make sure group include files are detected properly even when the file is
- // already loaded when the cache is rebuilt.
- // For that activate the module_test which provides the file to load.
- module_enable(array('module_test'));
-
- module_load_include('inc', 'module_test', 'module_test.file');
- $modules = module_implements('test_hook');
- $static = drupal_static('module_implements');
- $this->assertTrue(in_array('module_test', $modules), 'Hook found.');
- $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.');
- }
-
- /**
- * Test that module_invoke() can load a hook defined in hook_hook_info().
- */
- function testModuleInvoke() {
- module_enable(array('module_test'), FALSE);
- $this->resetAll();
- $this->drupalGet('module-test/hook-dynamic-loading-invoke');
- $this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().');
- }
-
- /**
- * Test that module_invoke_all() can load a hook defined in hook_hook_info().
- */
- function testModuleInvokeAll() {
- module_enable(array('module_test'), FALSE);
- $this->resetAll();
- $this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
- $this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().');
- }
-
- /**
- * Test dependency resolution.
- */
- function testDependencyResolution() {
- // Enable the test module, and make sure that other modules we are testing
- // are not already enabled. (If they were, the tests below would not work
- // correctly.)
- module_enable(array('module_test'), FALSE);
- $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
- $this->assertFalse(module_exists('forum'), 'Forum module is disabled.');
- $this->assertFalse(module_exists('poll'), 'Poll module is disabled.');
- $this->assertFalse(module_exists('php'), 'PHP module is disabled.');
-
- // First, create a fake missing dependency. Forum depends on poll, which
- // depends on a made-up module, foo. Nothing should be installed.
- variable_set('dependency_test', 'missing dependency');
- drupal_static_reset('system_rebuild_module_data');
- $result = module_enable(array('forum'));
- $this->assertFalse($result, 'module_enable() returns FALSE if dependencies are missing.');
- $this->assertFalse(module_exists('forum'), 'module_enable() aborts if dependencies are missing.');
-
- // Now, fix the missing dependency. Forum module depends on poll, but poll
- // depends on the PHP module. module_enable() should work.
- variable_set('dependency_test', 'dependency');
- drupal_static_reset('system_rebuild_module_data');
- $result = module_enable(array('forum'));
- $this->assertTrue($result, 'module_enable() returns the correct value.');
- // Verify that the fake dependency chain was installed.
- $this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
- // Verify that the original module was installed.
- $this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.');
- // Finally, verify that the modules were enabled in the correct order.
- $this->assertEqual(variable_get('test_module_enable_order', array()), array('php', 'poll', 'forum'), 'Modules were enabled in the correct order by module_enable().');
-
- // Now, disable the PHP module. Both forum and poll should be disabled as
- // well, in the correct order.
- module_disable(array('php'));
- $this->assertTrue(!module_exists('forum') && !module_exists('poll'), 'Depedency chain was disabled by module_disable().');
- $this->assertFalse(module_exists('php'), 'Disabling a module with unlisted dependents succeeded.');
- $this->assertEqual(variable_get('test_module_disable_order', array()), array('forum', 'poll', 'php'), 'Modules were disabled in the correct order by module_disable().');
-
- // Disable a module that is listed as a dependency by the installation
- // profile. Make sure that the profile itself is not on the list of
- // dependent modules to be disabled.
- $profile = drupal_get_profile();
- $info = install_profile_info($profile);
- $this->assertTrue(in_array('comment', $info['dependencies']), 'Comment module is listed as a dependency of the installation profile.');
- $this->assertTrue(module_exists('comment'), 'Comment module is enabled.');
- module_disable(array('comment'));
- $this->assertFalse(module_exists('comment'), 'Comment module was disabled.');
- $disabled_modules = variable_get('test_module_disable_order', array());
- $this->assertTrue(in_array('comment', $disabled_modules), 'Comment module is in the list of disabled modules.');
- $this->assertFalse(in_array($profile, $disabled_modules), 'The installation profile is not in the list of disabled modules.');
-
- // Try to uninstall the PHP module by itself. This should be rejected,
- // since the modules which it depends on need to be uninstalled first, and
- // that is too destructive to perform automatically.
- $result = drupal_uninstall_modules(array('php'));
- $this->assertFalse($result, 'Calling drupal_uninstall_modules() on a module whose dependents are not uninstalled fails.');
- foreach (array('forum', 'poll', 'php') as $module) {
- $this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was not uninstalled.', array('@module' => $module)));
- }
-
- // Now uninstall all three modules explicitly, but in the incorrect order,
- // and make sure that drupal_uninstal_modules() uninstalled them in the
- // correct sequence.
- $result = drupal_uninstall_modules(array('poll', 'php', 'forum'));
- $this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
- foreach (array('forum', 'poll', 'php') as $module) {
- $this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was uninstalled.', array('@module' => $module)));
- }
- $this->assertEqual(variable_get('test_module_uninstall_order', array()), array('forum', 'poll', 'php'), 'Modules were uninstalled in the correct order by drupal_uninstall_modules().');
-
- // Uninstall the profile module from above, and make sure that the profile
- // itself is not on the list of dependent modules to be uninstalled.
- $result = drupal_uninstall_modules(array('comment'));
- $this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
- $this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.');
- $uninstalled_modules = variable_get('test_module_uninstall_order', array());
- $this->assertTrue(in_array('comment', $uninstalled_modules), 'Comment module is in the list of uninstalled modules.');
- $this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.');
-
- // Enable forum module again, which should enable both the poll module and
- // php module. But, this time do it with poll module declaring a dependency
- // on a specific version of php module in its info file. Make sure that
- // module_enable() still works.
- variable_set('dependency_test', 'version dependency');
- drupal_static_reset('system_rebuild_module_data');
- $result = module_enable(array('forum'));
- $this->assertTrue($result, 'module_enable() returns the correct value.');
- // Verify that the fake dependency chain was installed.
- $this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
- // Verify that the original module was installed.
- $this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.');
- // Finally, verify that the modules were enabled in the correct order.
- $enable_order = variable_get('test_module_enable_order', array());
- $php_position = array_search('php', $enable_order);
- $poll_position = array_search('poll', $enable_order);
- $forum_position = array_search('forum', $enable_order);
- $php_before_poll = $php_position !== FALSE && $poll_position !== FALSE && $php_position < $poll_position;
- $poll_before_forum = $poll_position !== FALSE && $forum_position !== FALSE && $poll_position < $forum_position;
- $this->assertTrue($php_before_poll && $poll_before_forum, 'Modules were enabled in the correct order by module_enable().');
- }
-}
-
-/**
- * Unit tests for module installation.
- */
-class ModuleInstallTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Module installation',
- 'description' => 'Tests the installation of modules.',
- 'group' => 'Module',
- );
- }
-
- function setUp() {
- parent::setUp('module_test');
- }
-
- /**
- * Test that calls to drupal_write_record() work during module installation.
- *
- * This is a useful function to test because modules often use it to insert
- * initial data in their database tables when they are being installed or
- * enabled. Furthermore, drupal_write_record() relies on the module schema
- * information being available, so this also checks that the data from one of
- * the module's hook implementations, in particular hook_schema(), is
- * properly available during this time. Therefore, this test helps ensure
- * that modules are fully functional while Drupal is installing and enabling
- * them.
- */
- function testDrupalWriteRecord() {
- // Check for data that was inserted using drupal_write_record() while the
- // 'module_test' module was being installed and enabled.
- $data = db_query("SELECT data FROM {module_test}")->fetchCol();
- $this->assertTrue(in_array('Data inserted in hook_install()', $data), 'Data inserted using drupal_write_record() in hook_install() is correctly saved.');
- $this->assertTrue(in_array('Data inserted in hook_enable()', $data), 'Data inserted using drupal_write_record() in hook_enable() is correctly saved.');
- }
-}
-
-/**
- * Unit tests for module uninstallation and related hooks.
- */
-class ModuleUninstallTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Module uninstallation',
- 'description' => 'Tests the uninstallation of modules.',
- 'group' => 'Module',
- );
- }
-
- function setUp() {
- parent::setUp('module_test', 'user');
- }
-
- /**
- * Tests the hook_modules_uninstalled() of the user module.
- */
- function testUserPermsUninstalled() {
- // Uninstalls the module_test module, so hook_modules_uninstalled()
- // is executed.
- module_disable(array('module_test'));
- drupal_uninstall_modules(array('module_test'));
-
- // Are the perms defined by module_test removed from {role_permission}.
- $count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm", array(':perm' => 'module_test perm'))->fetchField();
- $this->assertEqual(0, $count, 'Permissions were all removed.');
- }
-}
diff --git a/modules/simpletest/tests/module_test.file.inc b/modules/simpletest/tests/module_test.file.inc
deleted file mode 100644
index c0d3ec41..00000000
--- a/modules/simpletest/tests/module_test.file.inc
+++ /dev/null
@@ -1,13 +0,0 @@
- 'success!');
-}
diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info
deleted file mode 100644
index 1d43e123..00000000
--- a/modules/simpletest/tests/module_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Module test"
-description = "Support module for module system testing."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/module_test.install b/modules/simpletest/tests/module_test.install
deleted file mode 100644
index 4cc09df5..00000000
--- a/modules/simpletest/tests/module_test.install
+++ /dev/null
@@ -1,42 +0,0 @@
- 'Dummy table to test the behavior of hook_schema() during module installation.',
- 'fields' => array(
- 'data' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'An example data column for the module.',
- ),
- ),
- );
- return $schema;
-}
-
-/**
- * Implements hook_install().
- */
-function module_test_install() {
- $record = array('data' => 'Data inserted in hook_install()');
- drupal_write_record('module_test', $record);
-}
-
-/**
- * Implements hook_enable().
- */
-function module_test_enable() {
- $record = array('data' => 'Data inserted in hook_enable()');
- drupal_write_record('module_test', $record);
-}
-
diff --git a/modules/simpletest/tests/module_test.module b/modules/simpletest/tests/module_test.module
deleted file mode 100644
index d781350b..00000000
--- a/modules/simpletest/tests/module_test.module
+++ /dev/null
@@ -1,131 +0,0 @@
- t('example perm for module_test module'),
- );
-}
-
-/**
- * Implements hook_system_info_alter().
- *
- * Manipulate module dependencies to test dependency chains.
- */
-function module_test_system_info_alter(&$info, $file, $type) {
- if (variable_get('dependency_test', FALSE) == 'missing dependency') {
- if ($file->name == 'forum') {
- // Make forum module depend on poll.
- $info['dependencies'][] = 'poll';
- }
- elseif ($file->name == 'poll') {
- // Make poll depend on a made-up module.
- $info['dependencies'][] = 'foo';
- }
- }
- elseif (variable_get('dependency_test', FALSE) == 'dependency') {
- if ($file->name == 'forum') {
- // Make the forum module depend on poll.
- $info['dependencies'][] = 'poll';
- }
- elseif ($file->name == 'poll') {
- // Make poll depend on php module.
- $info['dependencies'][] = 'php';
- }
- }
- elseif (variable_get('dependency_test', FALSE) == 'version dependency') {
- if ($file->name == 'forum') {
- // Make the forum module depend on poll.
- $info['dependencies'][] = 'poll';
- }
- elseif ($file->name == 'poll') {
- // Make poll depend on a specific version of php module.
- $info['dependencies'][] = 'php (1.x)';
- }
- elseif ($file->name == 'php') {
- // Set php module to a version compatible with the above.
- $info['version'] = '7.x-1.0';
- }
- }
- if ($file->name == 'seven' && $type == 'theme') {
- $info['regions']['test_region'] = t('Test region');
- }
-}
-
-/**
- * Implements hook_hook_info().
- */
-function module_test_hook_info() {
- $hooks['test_hook'] = array(
- 'group' => 'file',
- );
- return $hooks;
-}
-
-/**
- * Implements hook_menu().
- */
-function module_test_menu() {
- $items['module-test/hook-dynamic-loading-invoke'] = array(
- 'title' => 'Test hook dynamic loading (invoke)',
- 'page callback' => 'module_test_hook_dynamic_loading_invoke',
- 'access arguments' => array('access content'),
- );
- $items['module-test/hook-dynamic-loading-invoke-all'] = array(
- 'title' => 'Test hook dynamic loading (invoke_all)',
- 'page callback' => 'module_test_hook_dynamic_loading_invoke_all',
- 'access arguments' => array('access content'),
- );
- return $items;
-}
-
-/**
- * Page callback for 'hook dynamic loading' test.
- *
- * If the hook is dynamically loaded correctly, the menu callback should
- * return 'success!'.
- */
-function module_test_hook_dynamic_loading_invoke() {
- $result = module_invoke('module_test', 'test_hook');
- return $result['module_test'];
-}
-
-/**
- * Page callback for 'hook dynamic loading' test.
- *
- * If the hook is dynamically loaded correctly, the menu callback should
- * return 'success!'.
- */
-function module_test_hook_dynamic_loading_invoke_all() {
- $result = module_invoke_all('test_hook');
- return $result['module_test'];
-}
-
-/**
- * Implements hook_modules_enabled().
- */
-function module_test_modules_enabled($modules) {
- // Record the ordered list of modules that were passed in to this hook so we
- // can check that the modules were enabled in the correct sequence.
- variable_set('test_module_enable_order', $modules);
-}
-
-/**
- * Implements hook_modules_disabled().
- */
-function module_test_modules_disabled($modules) {
- // Record the ordered list of modules that were passed in to this hook so we
- // can check that the modules were disabled in the correct sequence.
- variable_set('test_module_disable_order', $modules);
-}
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function module_test_modules_uninstalled($modules) {
- // Record the ordered list of modules that were passed in to this hook so we
- // can check that the modules were uninstalled in the correct sequence.
- variable_set('test_module_uninstall_order', $modules);
-}
diff --git a/modules/simpletest/tests/pager.test b/modules/simpletest/tests/pager.test
deleted file mode 100644
index 6e8ce8e7..00000000
--- a/modules/simpletest/tests/pager.test
+++ /dev/null
@@ -1,159 +0,0 @@
- 'Pager functionality',
- 'description' => 'Tests pager functionality.',
- 'group' => 'Pager',
- );
- }
-
- function setUp() {
- parent::setUp(array('dblog'));
-
- // Insert 300 log messages.
- for ($i = 0; $i < 300; $i++) {
- watchdog('pager_test', $this->randomString(), NULL, WATCHDOG_DEBUG);
- }
-
- $this->admin_user = $this->drupalCreateUser(array(
- 'access site reports',
- ));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Tests markup and CSS classes of pager links.
- */
- function testActiveClass() {
- // Verify first page.
- $this->drupalGet('admin/reports/dblog');
- $current_page = 0;
- $this->assertPagerItems($current_page);
-
- // Verify any page but first/last.
- $current_page++;
- $this->drupalGet('admin/reports/dblog', array('query' => array('page' => $current_page)));
- $this->assertPagerItems($current_page);
-
- // Verify last page.
- $elements = $this->xpath('//li[contains(@class, :class)]/a', array(':class' => 'pager-last'));
- preg_match('@page=(\d+)@', $elements[0]['href'], $matches);
- $current_page = (int) $matches[1];
- $this->drupalGet($GLOBALS['base_root'] . $elements[0]['href'], array('external' => TRUE));
- $this->assertPagerItems($current_page);
- }
-
- /**
- * Asserts pager items and links.
- *
- * @param int $current_page
- * The current pager page the internal browser is on.
- */
- protected function assertPagerItems($current_page) {
- $elements = $this->xpath('//ul[@class=:class]/li', array(':class' => 'pager'));
- $this->assertTrue(!empty($elements), 'Pager found.');
-
- // Make current page 1-based.
- $current_page++;
-
- // Extract first/previous and next/last items.
- // first/previous only exist, if the current page is not the first.
- if ($current_page > 1) {
- $first = array_shift($elements);
- $previous = array_shift($elements);
- }
- // next/last always exist, unless the current page is the last.
- if ($current_page != count($elements)) {
- $last = array_pop($elements);
- $next = array_pop($elements);
- }
-
- // Verify items and links to pages.
- foreach ($elements as $page => $element) {
- // Make item/page index 1-based.
- $page++;
- if ($current_page == $page) {
- $this->assertClass($element, 'pager-current', 'Item for current page has .pager-current class.');
- $this->assertFalse(isset($element->a), 'Item for current page has no link.');
- }
- else {
- $this->assertNoClass($element, 'pager-current', "Item for page $page has no .pager-current class.");
- $this->assertClass($element, 'pager-item', "Item for page $page has .pager-item class.");
- $this->assertTrue($element->a, "Link to page $page found.");
- $this->assertNoClass($element->a, 'active', "Link to page $page is not active.");
- }
- unset($elements[--$page]);
- }
- // Verify that no other items remain untested.
- $this->assertTrue(empty($elements), 'All expected items found.');
-
- // Verify first/previous and next/last items and links.
- if (isset($first)) {
- $this->assertClass($first, 'pager-first', 'Item for first page has .pager-first class.');
- $this->assertTrue($first->a, 'Link to first page found.');
- $this->assertNoClass($first->a, 'active', 'Link to first page is not active.');
- }
- if (isset($previous)) {
- $this->assertClass($previous, 'pager-previous', 'Item for first page has .pager-previous class.');
- $this->assertTrue($previous->a, 'Link to previous page found.');
- $this->assertNoClass($previous->a, 'active', 'Link to previous page is not active.');
- }
- if (isset($next)) {
- $this->assertClass($next, 'pager-next', 'Item for next page has .pager-next class.');
- $this->assertTrue($next->a, 'Link to next page found.');
- $this->assertNoClass($next->a, 'active', 'Link to next page is not active.');
- }
- if (isset($last)) {
- $this->assertClass($last, 'pager-last', 'Item for last page has .pager-last class.');
- $this->assertTrue($last->a, 'Link to last page found.');
- $this->assertNoClass($last->a, 'active', 'Link to last page is not active.');
- }
- }
-
- /**
- * Asserts that an element has a given class.
- *
- * @param SimpleXMLElement $element
- * The element to test.
- * @param string $class
- * The class to assert.
- * @param string $message
- * (optional) A verbose message to output.
- */
- protected function assertClass(SimpleXMLElement $element, $class, $message = NULL) {
- if (!isset($message)) {
- $message = "Class .$class found.";
- }
- $this->assertTrue(strpos($element['class'], $class) !== FALSE, $message);
- }
-
- /**
- * Asserts that an element does not have a given class.
- *
- * @param SimpleXMLElement $element
- * The element to test.
- * @param string $class
- * The class to assert.
- * @param string $message
- * (optional) A verbose message to output.
- */
- protected function assertNoClass(SimpleXMLElement $element, $class, $message = NULL) {
- if (!isset($message)) {
- $message = "Class .$class not found.";
- }
- $this->assertTrue(strpos($element['class'], $class) === FALSE, $message);
- }
-}
-
diff --git a/modules/simpletest/tests/password.test b/modules/simpletest/tests/password.test
deleted file mode 100644
index 5259d19e..00000000
--- a/modules/simpletest/tests/password.test
+++ /dev/null
@@ -1,60 +0,0 @@
- 'Password hashing',
- 'description' => 'Password hashing unit tests.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- parent::setUp();
- }
-
- /**
- * Test password hashing.
- */
- function testPasswordHashing() {
- // Set a log2 iteration count that is deliberately out of bounds to test
- // that it is corrected to be within bounds.
- variable_set('password_count_log2', 1);
- // Set up a fake $account with a password 'baz', hashed with md5.
- $password = 'baz';
- $account = (object) array('name' => 'foo', 'pass' => md5($password));
- // The md5 password should be flagged as needing an update.
- $this->assertTrue(user_needs_new_hash($account), 'User with md5 password needs a new hash.');
- // Re-hash the password.
- $old_hash = $account->pass;
- $account->pass = user_hash_password($password);
- $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT, 'Re-hashed password has the minimum number of log2 iterations.');
- $this->assertTrue($account->pass != $old_hash, 'Password hash changed.');
- $this->assertTrue(user_check_password($password, $account), 'Password check succeeds.');
- // Since the log2 setting hasn't changed and the user has a valid password,
- // user_needs_new_hash() should return FALSE.
- $this->assertFalse(user_needs_new_hash($account), 'User does not need a new hash.');
- // Increment the log2 iteration to MIN + 1.
- variable_set('password_count_log2', DRUPAL_MIN_HASH_COUNT + 1);
- $this->assertTrue(user_needs_new_hash($account), 'User needs a new hash after incrementing the log2 count.');
- // Re-hash the password.
- $old_hash = $account->pass;
- $account->pass = user_hash_password($password);
- $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT + 1, 'Re-hashed password has the correct number of log2 iterations.');
- $this->assertTrue($account->pass != $old_hash, 'Password hash changed again.');
- // Now the hash should be OK.
- $this->assertFalse(user_needs_new_hash($account), 'Re-hashed password does not need a new hash.');
- $this->assertTrue(user_check_password($password, $account), 'Password check succeeds with re-hashed password.');
- }
-}
diff --git a/modules/simpletest/tests/path.test b/modules/simpletest/tests/path.test
deleted file mode 100644
index b8b3c93c..00000000
--- a/modules/simpletest/tests/path.test
+++ /dev/null
@@ -1,381 +0,0 @@
- 'Drupal match path',
- 'description' => 'Tests the drupal_match_path() function to make sure it works properly.',
- 'group' => 'Path API',
- );
- }
-
- function setUp() {
- // Set up the database and testing environment.
- parent::setUp();
-
- // Set up a random site front page to test the '' placeholder.
- $this->front = $this->randomName();
- variable_set('site_frontpage', $this->front);
- // Refresh our static variables from the database.
- $this->refreshVariables();
- }
-
- /**
- * Run through our test cases, making sure each one works as expected.
- */
- function testDrupalMatchPath() {
- // Set up our test cases.
- $tests = $this->drupalMatchPathTests();
- foreach ($tests as $patterns => $cases) {
- foreach ($cases as $path => $expected_result) {
- $actual_result = drupal_match_path($path, $patterns);
- $this->assertIdentical($actual_result, $expected_result, format_string('Tried matching the path @path to the pattern @patterns - expected @expected, got @actual.', array('@path' => $path, '@patterns' => $patterns, '@expected' => var_export($expected_result, TRUE), '@actual' => var_export($actual_result, TRUE))));
- }
- }
- }
-
- /**
- * Helper function for testDrupalMatchPath(): set up an array of test cases.
- *
- * @return
- * An array of test cases to cycle through.
- */
- private function drupalMatchPathTests() {
- return array(
- // Single absolute paths.
- 'blog/1' => array(
- 'blog/1' => TRUE,
- 'blog/2' => FALSE,
- 'test' => FALSE,
- ),
- // Single paths with wildcards.
- 'blog/*' => array(
- 'blog/1' => TRUE,
- 'blog/2' => TRUE,
- 'blog/3/edit' => TRUE,
- 'blog/' => TRUE,
- 'blog' => FALSE,
- 'test' => FALSE,
- ),
- // Single paths with multiple wildcards.
- 'node/*/revisions/*' => array(
- 'node/1/revisions/3' => TRUE,
- 'node/345/revisions/test' => TRUE,
- 'node/23/edit' => FALSE,
- 'test' => FALSE,
- ),
- // Single paths with ''.
- '' => array(
- $this->front => TRUE,
- "$this->front/" => FALSE,
- "$this->front/edit" => FALSE,
- 'node' => FALSE,
- '' => FALSE,
- ),
- // Paths with both '' and wildcards (should not work).
- '/*' => array(
- $this->front => FALSE,
- "$this->front/" => FALSE,
- "$this->front/edit" => FALSE,
- 'node/12' => FALSE,
- '' => FALSE,
- ),
- // Multiple paths with the \n delimiter.
- "node/*\nnode/*/edit" => array(
- 'node/1' => TRUE,
- 'node/view' => TRUE,
- 'node/32/edit' => TRUE,
- 'node/delete/edit' => TRUE,
- 'node/50/delete' => TRUE,
- 'test/example' => FALSE,
- ),
- // Multiple paths with the \r delimiter.
- "user/*\rblog/*" => array(
- 'user/1' => TRUE,
- 'blog/1' => TRUE,
- 'user/1/blog/1' => TRUE,
- 'user/blog' => TRUE,
- 'test/example' => FALSE,
- 'user' => FALSE,
- 'blog' => FALSE,
- ),
- // Multiple paths with the \r\n delimiter.
- "test\r\n" => array(
- 'test' => TRUE,
- $this->front => TRUE,
- 'example' => FALSE,
- ),
- // Test existing regular expressions (should be escaped).
- '[^/]+?/[0-9]' => array(
- 'test/1' => FALSE,
- '[^/]+?/[0-9]' => TRUE,
- ),
- );
- }
-}
-
-/**
- * Tests hook_url_alter functions.
- */
-class UrlAlterFunctionalTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => t('URL altering'),
- 'description' => t('Tests hook_url_inbound_alter() and hook_url_outbound_alter().'),
- 'group' => t('Path API'),
- );
- }
-
- function setUp() {
- parent::setUp('path', 'forum', 'url_alter_test');
- }
-
- /**
- * Test that URL altering works and that it occurs in the correct order.
- */
- function testUrlAlter() {
- $account = $this->drupalCreateUser(array('administer url aliases'));
- $this->drupalLogin($account);
-
- $uid = $account->uid;
- $name = $account->name;
-
- // Test a single altered path.
- $this->assertUrlInboundAlter("user/$name", "user/$uid");
- $this->assertUrlOutboundAlter("user/$uid", "user/$name");
-
- // Test that a path always uses its alias.
- $path = array('source' => "user/$uid/test1", 'alias' => 'alias/test1');
- path_save($path);
- $this->assertUrlInboundAlter('alias/test1', "user/$uid/test1");
- $this->assertUrlOutboundAlter("user/$uid/test1", 'alias/test1');
-
- // Test that alias source paths are normalized in the interface.
- $edit = array('source' => "user/$name/edit", 'alias' => 'alias/test2');
- $this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
- $this->assertText(t('The alias has been saved.'));
-
- // Test that a path always uses its alias.
- $this->assertUrlInboundAlter('alias/test2', "user/$uid/edit");
- $this->assertUrlOutboundAlter("user/$uid/edit", 'alias/test2');
-
- // Test a non-existent user is not altered.
- $uid++;
- $this->assertUrlInboundAlter("user/$uid", "user/$uid");
- $this->assertUrlOutboundAlter("user/$uid", "user/$uid");
-
- // Test that 'forum' is altered to 'community' correctly, both at the root
- // level and for a specific existing forum.
- $this->assertUrlInboundAlter('community', 'forum');
- $this->assertUrlOutboundAlter('forum', 'community');
- $forum_vid = db_query("SELECT vid FROM {taxonomy_vocabulary} WHERE module = 'forum'")->fetchField();
- $tid = db_insert('taxonomy_term_data')
- ->fields(array(
- 'name' => $this->randomName(),
- 'vid' => $forum_vid,
- ))
- ->execute();
- $this->assertUrlInboundAlter("community/$tid", "forum/$tid");
- $this->assertUrlOutboundAlter("forum/$tid", "community/$tid");
- }
-
- /**
- * Test current_path() and request_path().
- */
- function testCurrentUrlRequestedPath() {
- $this->drupalGet('url-alter-test/bar');
- $this->assertRaw('request_path=url-alter-test/bar', 'request_path() returns the requested path.');
- $this->assertRaw('current_path=url-alter-test/foo', 'current_path() returns the internal path.');
- }
-
- /**
- * Tests that $_GET['q'] is initialized when the request path is empty.
- */
- function testGetQInitialized() {
- $this->drupalGet('');
- $this->assertText("\$_GET['q'] is non-empty with an empty request path.", "\$_GET['q'] is initialized with an empty request path.");
- }
-
- /**
- * Assert that an outbound path is altered to an expected value.
- *
- * @param $original
- * A string with the original path that is run through url().
- * @param $final
- * A string with the expected result after url().
- * @return
- * TRUE if $original was correctly altered to $final, FALSE otherwise.
- */
- protected function assertUrlOutboundAlter($original, $final) {
- // Test outbound altering.
- $result = url($original);
- $base_path = base_path() . (variable_get('clean_url', '0') ? '' : '?q=');
- $result = substr($result, strlen($base_path));
- $this->assertIdentical($result, $final, format_string('Altered outbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
- }
-
- /**
- * Assert that a inbound path is altered to an expected value.
- *
- * @param $original
- * A string with the aliased or un-normal path that is run through
- * drupal_get_normal_path().
- * @param $final
- * A string with the expected result after url().
- * @return
- * TRUE if $original was correctly altered to $final, FALSE otherwise.
- */
- protected function assertUrlInboundAlter($original, $final) {
- // Test inbound altering.
- $result = drupal_get_normal_path($original);
- $this->assertIdentical($result, $final, format_string('Altered inbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
- }
-}
-
-/**
- * Unit test for drupal_lookup_path().
- */
-class PathLookupTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => t('Path lookup'),
- 'description' => t('Tests that drupal_lookup_path() returns correct paths.'),
- 'group' => t('Path API'),
- );
- }
-
- /**
- * Test that drupal_lookup_path() returns the correct path.
- */
- function testDrupalLookupPath() {
- $account = $this->drupalCreateUser();
- $uid = $account->uid;
- $name = $account->name;
-
- // Test the situation where the source is the same for multiple aliases.
- // Start with a language-neutral alias, which we will override.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'foo',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Basic alias lookup works.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Basic source lookup works.');
-
- // Create a language specific alias for the default language (English).
- $path = array(
- 'source' => "user/$uid",
- 'alias' => "users/$name",
- 'language' => 'en',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'English alias overrides language-neutral alias.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'English source overrides language-neutral source.');
-
- // Create a language-neutral alias for the same path, again.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'bar',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a language-neutral alias.');
-
- // Create a language-specific (xx-lolspeak) alias for the same path.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'LOL',
- 'language' => 'xx-lolspeak',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a LOLspeak alias.');
- // The LOLspeak alias should be returned if we really want LOLspeak.
- $this->assertEqual(drupal_lookup_path('alias', $path['source'], 'xx-lolspeak'), 'LOL', 'LOLspeak alias returned if we specify xx-lolspeak to drupal_lookup_path().');
-
- // Create a new alias for this path in English, which should override the
- // previous alias for "user/$uid".
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'users/my-new-path',
- 'language' => 'en',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Recently created English alias returned.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Recently created English source returned.');
-
- // Remove the English aliases, which should cause a fallback to the most
- // recently created language-neutral alias, 'bar'.
- db_delete('url_alias')
- ->condition('language', 'en')
- ->execute();
- drupal_clear_path_cache();
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar', 'Path lookup falls back to recently created language-neutral alias.');
-
- // Test the situation where the alias and language are the same, but
- // the source differs. The newer alias record should be returned.
- $account2 = $this->drupalCreateUser();
- $path = array(
- 'source' => 'user/' . $account2->uid,
- 'alias' => 'bar',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.');
- }
-}
-
-/**
- * Tests the path_save() function.
- */
-class PathSaveTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => t('Path save'),
- 'description' => t('Tests that path_save() exposes the previous alias value.'),
- 'group' => t('Path API'),
- );
- }
-
- function setUp() {
- // Enable a helper module that implements hook_path_update().
- parent::setUp('path_test');
- path_test_reset();
- }
-
- /**
- * Tests that path_save() makes the original path available to modules.
- */
- function testDrupalSaveOriginalPath() {
- $account = $this->drupalCreateUser();
- $uid = $account->uid;
- $name = $account->name;
-
- // Create a language-neutral alias.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'foo',
- );
- $path_original = $path;
- path_save($path);
-
- // Alter the path.
- $path['alias'] = 'bar';
- path_save($path);
-
- // Test to see if the original alias is available to modules during
- // hook_path_update().
- $results = variable_get('path_test_results', array());
- $this->assertIdentical($results['hook_path_update']['original']['alias'], $path_original['alias'], 'Old path alias available to modules during hook_path_update.');
- $this->assertIdentical($results['hook_path_update']['original']['source'], $path_original['source'], 'Old path alias available to modules during hook_path_update.');
- }
-}
diff --git a/modules/simpletest/tests/path_test.info b/modules/simpletest/tests/path_test.info
deleted file mode 100644
index 086ba326..00000000
--- a/modules/simpletest/tests/path_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Hook path tests"
-description = "Support module for path hook testing."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/path_test.module b/modules/simpletest/tests/path_test.module
deleted file mode 100644
index d3dc80e2..00000000
--- a/modules/simpletest/tests/path_test.module
+++ /dev/null
@@ -1,23 +0,0 @@
- 'PSR0 example test: PSR-0 in disabled modules.',
- 'description' => 'We want to assert that this test case is being discovered.',
- 'group' => 'SimpleTest',
- );
- }
-
- function testArithmetics() {
- $this->assert(1 + 1 == 2, '1 + 1 == 2');
- }
-}
diff --git a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php b/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php
deleted file mode 100644
index 324ed439..00000000
--- a/modules/simpletest/tests/psr_0_test/lib/Drupal/psr_0_test/Tests/Nested/NestedExampleTest.php
+++ /dev/null
@@ -1,18 +0,0 @@
- 'PSR0 example test: PSR-0 in nested subfolders.',
- 'description' => 'We want to assert that this PSR-0 test case is being discovered.',
- 'group' => 'SimpleTest',
- );
- }
-
- function testArithmetics() {
- $this->assert(1 + 1 == 2, '1 + 1 == 2');
- }
-}
diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.info b/modules/simpletest/tests/psr_0_test/psr_0_test.info
deleted file mode 100644
index e392562c..00000000
--- a/modules/simpletest/tests/psr_0_test/psr_0_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = PSR-0 Test cases
-description = Test classes to be discovered by simpletest.
-core = 7.x
-
-hidden = TRUE
-package = Testing
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.module b/modules/simpletest/tests/psr_0_test/psr_0_test.module
deleted file mode 100644
index b3d9bbc7..00000000
--- a/modules/simpletest/tests/psr_0_test/psr_0_test.module
+++ /dev/null
@@ -1 +0,0 @@
- 'Registry parse file test',
- 'description' => 'Parse a simple file and check that its resources are saved to the database.',
- 'group' => 'System'
- );
- }
-
- function setUp() {
- $chrs = hash('sha256', microtime() . mt_rand());
- $this->fileName = 'registry_test_' . substr($chrs, 0, 16);
- $this->className = 'registry_test_class' . substr($chrs, 16, 16);
- $this->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
- parent::setUp();
- }
-
- /**
- * testRegistryParseFile
- */
- function testRegistryParseFile() {
- _registry_parse_file($this->fileName, $this->getFileContents());
- foreach (array('className', 'interfaceName') as $resource) {
- $foundName = db_query('SELECT name FROM {registry} WHERE name = :name', array(':name' => $this->$resource))->fetchField();
- $this->assertTrue($this->$resource == $foundName, t('Resource "@resource" found.', array('@resource' => $this->$resource)));
- }
- }
-
- /**
- * getFileContents
- */
- function getFileContents() {
- $file_contents = <<className} {}
-
-interface {$this->interfaceName} {}
-
-CONTENTS;
- return $file_contents;
- }
-
-}
-
-class RegistryParseFilesTestCase extends DrupalWebTestCase {
- protected $fileTypes = array('new', 'existing_changed');
-
- public static function getInfo() {
- return array(
- 'name' => 'Registry parse files test',
- 'description' => 'Read two a simple files from disc, and check that their resources are saved to the database.',
- 'group' => 'System'
- );
- }
-
- function setUp() {
- parent::setUp();
- // Create files with some php to parse - one 'new', one 'existing' so
- // we test all the important code paths in _registry_parse_files.
- foreach ($this->fileTypes as $fileType) {
- $chrs = hash('sha256', microtime() . mt_rand());
- $this->$fileType = new stdClass();
- $this->$fileType->fileName = 'public://registry_test_' . substr($chrs, 0, 16);
- $this->$fileType->className = 'registry_test_class' . substr($chrs, 16, 16);
- $this->$fileType->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
- $this->$fileType->contents = $this->getFileContents($fileType);
- file_save_data($this->$fileType->contents, $this->$fileType->fileName);
-
- if ($fileType == 'existing_changed') {
- // Add a record with an incorrect hash.
- $this->$fileType->fakeHash = hash('sha256', mt_rand());
- db_insert('registry_file')
- ->fields(array(
- 'hash' => $this->$fileType->fakeHash,
- 'filename' => $this->$fileType->fileName,
- ))
- ->execute();
-
- // Insert some fake resource records.
- foreach (array('class', 'interface') as $type) {
- db_insert('registry')
- ->fields(array(
- 'name' => $type . hash('sha256', microtime() . mt_rand()),
- 'type' => $type,
- 'filename' => $this->$fileType->fileName,
- ))
- ->execute();
- }
- }
- }
- }
-
- /**
- * testRegistryParseFiles
- */
- function testRegistryParseFiles() {
- _registry_parse_files($this->getFiles());
- foreach ($this->fileTypes as $fileType) {
- // Test that we have all the right resources.
- foreach (array('className', 'interfaceName') as $resource) {
- $foundName = db_query('SELECT name FROM {registry} WHERE name = :name', array(':name' => $this->$fileType->$resource))->fetchField();
- $this->assertTrue($this->$fileType->$resource == $foundName, t('Resource "@resource" found.', array('@resource' => $this->$fileType->$resource)));
- }
- // Test that we have the right hash.
- $hash = db_query('SELECT hash FROM {registry_file} WHERE filename = :filename', array(':filename' => $this->$fileType->fileName))->fetchField();
- $this->assertTrue(hash('sha256', $this->$fileType->contents) == $hash, t('sha-256 for "@filename" matched.' . $fileType . $hash, array('@filename' => $this->$fileType->fileName)));
- }
- }
-
- /**
- * getFiles
- */
- function getFiles() {
- $files = array();
- foreach ($this->fileTypes as $fileType) {
- $files[$this->$fileType->fileName] = array('module' => '', 'weight' => 0);
- if ($fileType == 'existing_changed') {
- $files[$this->$fileType->fileName]['hash'] = $this->$fileType->fakeHash;
- }
- }
- return $files;
- }
-
- /**
- * getFileContents
- */
- function getFileContents($fileType) {
- $file_contents = <<$fileType->className} {}
-
-interface {$this->$fileType->interfaceName} {}
-
-CONTENTS;
- return $file_contents;
- }
-
-}
diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info
deleted file mode 100644
index 611979c4..00000000
--- a/modules/simpletest/tests/requirements1_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = Requirements 1 Test
-description = "Tests that a module is not installed when it fails hook_requirements('install')."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/requirements1_test.install b/modules/simpletest/tests/requirements1_test.install
deleted file mode 100644
index 91caca3f..00000000
--- a/modules/simpletest/tests/requirements1_test.install
+++ /dev/null
@@ -1,21 +0,0 @@
- $t('Requirements 1 Test'),
- 'severity' => REQUIREMENT_ERROR,
- 'description' => $t('Requirements 1 Test failed requirements.'),
- );
- }
-
- return $requirements;
-}
diff --git a/modules/simpletest/tests/requirements1_test.module b/modules/simpletest/tests/requirements1_test.module
deleted file mode 100644
index e52266b2..00000000
--- a/modules/simpletest/tests/requirements1_test.module
+++ /dev/null
@@ -1,7 +0,0 @@
- 'Schema API',
- 'description' => 'Tests table creation and modification via the schema API.',
- 'group' => 'Database',
- );
- }
-
- /**
- *
- */
- function testSchema() {
- // Try creating a table.
- $table_specification = array(
- 'description' => 'Schema table description.',
- 'fields' => array(
- 'id' => array(
- 'type' => 'int',
- 'default' => NULL,
- ),
- 'test_field' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'description' => 'Schema column description.',
- ),
- ),
- );
- db_create_table('test_table', $table_specification);
-
- // Assert that the table exists.
- $this->assertTrue(db_table_exists('test_table'), 'The table exists.');
-
- // Assert that the table comment has been set.
- $this->checkSchemaComment($table_specification['description'], 'test_table');
-
- // Assert that the column comment has been set.
- $this->checkSchemaComment($table_specification['fields']['test_field']['description'], 'test_table', 'test_field');
-
- // An insert without a value for the column 'test_table' should fail.
- $this->assertFalse($this->tryInsert(), 'Insert without a default failed.');
-
- // Add a default value to the column.
- db_field_set_default('test_table', 'test_field', 0);
- // The insert should now succeed.
- $this->assertTrue($this->tryInsert(), 'Insert with a default succeeded.');
-
- // Remove the default.
- db_field_set_no_default('test_table', 'test_field');
- // The insert should fail again.
- $this->assertFalse($this->tryInsert(), 'Insert without a default failed.');
-
- // Test for fake index and test for the boolean result of indexExists().
- $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field');
- $this->assertIdentical($index_exists, FALSE, 'Fake index does not exists');
- // Add index.
- db_add_index('test_table', 'test_field', array('test_field'));
- // Test for created index and test for the boolean result of indexExists().
- $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field');
- $this->assertIdentical($index_exists, TRUE, 'Index created.');
-
- // Rename the table.
- db_rename_table('test_table', 'test_table2');
-
- // Index should be renamed.
- $index_exists = Database::getConnection()->schema()->indexExists('test_table2', 'test_field');
- $this->assertTrue($index_exists, 'Index was renamed.');
-
- // We need the default so that we can insert after the rename.
- db_field_set_default('test_table2', 'test_field', 0);
- $this->assertFalse($this->tryInsert(), 'Insert into the old table failed.');
- $this->assertTrue($this->tryInsert('test_table2'), 'Insert into the new table succeeded.');
-
- // We should have successfully inserted exactly two rows.
- $count = db_query('SELECT COUNT(*) FROM {test_table2}')->fetchField();
- $this->assertEqual($count, 2, 'Two fields were successfully inserted.');
-
- // Try to drop the table.
- db_drop_table('test_table2');
- $this->assertFalse(db_table_exists('test_table2'), 'The dropped table does not exist.');
-
- // Recreate the table.
- db_create_table('test_table', $table_specification);
- db_field_set_default('test_table', 'test_field', 0);
- db_add_field('test_table', 'test_serial', array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Added column description.'));
-
- // Assert that the column comment has been set.
- $this->checkSchemaComment('Added column description.', 'test_table', 'test_serial');
-
- // Change the new field to a serial column.
- db_change_field('test_table', 'test_serial', 'test_serial', array('type' => 'serial', 'not null' => TRUE, 'description' => 'Changed column description.'), array('primary key' => array('test_serial')));
-
- // Assert that the column comment has been set.
- $this->checkSchemaComment('Changed column description.', 'test_table', 'test_serial');
-
- $this->assertTrue($this->tryInsert(), 'Insert with a serial succeeded.');
- $max1 = db_query('SELECT MAX(test_serial) FROM {test_table}')->fetchField();
- $this->assertTrue($this->tryInsert(), 'Insert with a serial succeeded.');
- $max2 = db_query('SELECT MAX(test_serial) FROM {test_table}')->fetchField();
- $this->assertTrue($max2 > $max1, 'The serial is monotone.');
-
- $count = db_query('SELECT COUNT(*) FROM {test_table}')->fetchField();
- $this->assertEqual($count, 2, 'There were two rows.');
-
- // Use database specific data type and ensure that table is created.
- $table_specification = array(
- 'description' => 'Schema table description.',
- 'fields' => array(
- 'timestamp' => array(
- 'mysql_type' => 'timestamp',
- 'pgsql_type' => 'timestamp',
- 'sqlite_type' => 'datetime',
- 'not null' => FALSE,
- 'default' => NULL,
- ),
- ),
- );
- try {
- db_create_table('test_timestamp', $table_specification);
- }
- catch (Exception $e) {}
- $this->assertTrue(db_table_exists('test_timestamp'), 'Table with database specific datatype was created.');
- }
-
- function tryInsert($table = 'test_table') {
- try {
- db_insert($table)
- ->fields(array('id' => mt_rand(10, 20)))
- ->execute();
- return TRUE;
- }
- catch (Exception $e) {
- return FALSE;
- }
- }
-
- /**
- * Checks that a table or column comment matches a given description.
- *
- * @param $description
- * The asserted description.
- * @param $table
- * The table to test.
- * @param $column
- * Optional column to test.
- */
- function checkSchemaComment($description, $table, $column = NULL) {
- if (method_exists(Database::getConnection()->schema(), 'getComment')) {
- $comment = Database::getConnection()->schema()->getComment($table, $column);
- $this->assertEqual($comment, $description, 'The comment matches the schema description.');
- }
- }
-
- /**
- * Tests creating unsigned columns and data integrity thereof.
- */
- function testUnsignedColumns() {
- // First create the table with just a serial column.
- $table_name = 'unsigned_table';
- $table_spec = array(
- 'fields' => array('serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE)),
- 'primary key' => array('serial_column'),
- );
- $ret = array();
- db_create_table($table_name, $table_spec);
-
- // Now set up columns for the other types.
- $types = array('int', 'float', 'numeric');
- foreach ($types as $type) {
- $column_spec = array('type' => $type, 'unsigned'=> TRUE);
- if ($type == 'numeric') {
- $column_spec += array('precision' => 10, 'scale' => 0);
- }
- $column_name = $type . '_column';
- $table_spec['fields'][$column_name] = $column_spec;
- db_add_field($table_name, $column_name, $column_spec);
- }
-
- // Finally, check each column and try to insert invalid values into them.
- foreach ($table_spec['fields'] as $column_name => $column_spec) {
- $this->assertTrue(db_field_exists($table_name, $column_name), format_string('Unsigned @type column was created.', array('@type' => $column_spec['type'])));
- $this->assertFalse($this->tryUnsignedInsert($table_name, $column_name), format_string('Unsigned @type column rejected a negative value.', array('@type' => $column_spec['type'])));
- }
- }
-
- /**
- * Tries to insert a negative value into columns defined as unsigned.
- *
- * @param $table_name
- * The table to insert
- * @param $column_name
- * The column to insert
- * @return
- * TRUE if the insert succeeded, FALSE otherwise
- */
- function tryUnsignedInsert($table_name, $column_name) {
- try {
- db_insert($table_name)
- ->fields(array($column_name => -1))
- ->execute();
- return TRUE;
- }
- catch (Exception $e) {
- return FALSE;
- }
- }
-
- /**
- * Test adding columns to an existing table.
- */
- function testSchemaAddField() {
- // Test varchar types.
- foreach (array(1, 32, 128, 256, 512) as $length) {
- $base_field_spec = array(
- 'type' => 'varchar',
- 'length' => $length,
- );
- $variations = array(
- array('not null' => FALSE),
- array('not null' => FALSE, 'default' => '7'),
- array('not null' => TRUE, 'initial' => 'd'),
- array('not null' => TRUE, 'initial' => 'd', 'default' => '7'),
- );
-
- foreach ($variations as $variation) {
- $field_spec = $variation + $base_field_spec;
- $this->assertFieldAdditionRemoval($field_spec);
- }
- }
-
- // Test int and float types.
- foreach (array('int', 'float') as $type) {
- foreach (array('tiny', 'small', 'medium', 'normal', 'big') as $size) {
- $base_field_spec = array(
- 'type' => $type,
- 'size' => $size,
- );
- $variations = array(
- array('not null' => FALSE),
- array('not null' => FALSE, 'default' => 7),
- array('not null' => TRUE, 'initial' => 1),
- array('not null' => TRUE, 'initial' => 1, 'default' => 7),
- );
-
- foreach ($variations as $variation) {
- $field_spec = $variation + $base_field_spec;
- $this->assertFieldAdditionRemoval($field_spec);
- }
- }
- }
-
- // Test numeric types.
- foreach (array(1, 5, 10, 40, 65) as $precision) {
- foreach (array(0, 2, 10, 30) as $scale) {
- if ($precision <= $scale) {
- // Precision must be smaller then scale.
- continue;
- }
-
- $base_field_spec = array(
- 'type' => 'numeric',
- 'scale' => $scale,
- 'precision' => $precision,
- );
- $variations = array(
- array('not null' => FALSE),
- array('not null' => FALSE, 'default' => 7),
- array('not null' => TRUE, 'initial' => 1),
- array('not null' => TRUE, 'initial' => 1, 'default' => 7),
- );
-
- foreach ($variations as $variation) {
- $field_spec = $variation + $base_field_spec;
- $this->assertFieldAdditionRemoval($field_spec);
- }
- }
- }
- }
-
- /**
- * Assert that a given field can be added and removed from a table.
- *
- * The addition test covers both defining a field of a given specification
- * when initially creating at table and extending an existing table.
- *
- * @param $field_spec
- * The schema specification of the field.
- */
- protected function assertFieldAdditionRemoval($field_spec) {
- // Try creating the field on a new table.
- $table_name = 'test_table_' . ($this->counter++);
- $table_spec = array(
- 'fields' => array(
- 'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
- 'test_field' => $field_spec,
- ),
- 'primary key' => array('serial_column'),
- );
- db_create_table($table_name, $table_spec);
- $this->pass(format_string('Table %table created.', array('%table' => $table_name)));
-
- // Check the characteristics of the field.
- $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec);
-
- // Clean-up.
- db_drop_table($table_name);
-
- // Try adding a field to an existing table.
- $table_name = 'test_table_' . ($this->counter++);
- $table_spec = array(
- 'fields' => array(
- 'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
- ),
- 'primary key' => array('serial_column'),
- );
- db_create_table($table_name, $table_spec);
- $this->pass(format_string('Table %table created.', array('%table' => $table_name)));
-
- // Insert some rows to the table to test the handling of initial values.
- for ($i = 0; $i < 3; $i++) {
- db_insert($table_name)
- ->useDefaults(array('serial_column'))
- ->execute();
- }
-
- db_add_field($table_name, 'test_field', $field_spec);
- $this->pass(format_string('Column %column created.', array('%column' => 'test_field')));
-
- // Check the characteristics of the field.
- $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec);
-
- // Clean-up.
- db_drop_field($table_name, 'test_field');
- db_drop_table($table_name);
- }
-
- /**
- * Assert that a newly added field has the correct characteristics.
- */
- protected function assertFieldCharacteristics($table_name, $field_name, $field_spec) {
- // Check that the initial value has been registered.
- if (isset($field_spec['initial'])) {
- // There should be no row with a value different then $field_spec['initial'].
- $count = db_select($table_name)
- ->fields($table_name, array('serial_column'))
- ->condition($field_name, $field_spec['initial'], '<>')
- ->countQuery()
- ->execute()
- ->fetchField();
- $this->assertEqual($count, 0, 'Initial values filled out.');
- }
-
- // Check that the default value has been registered.
- if (isset($field_spec['default'])) {
- // Try inserting a row, and check the resulting value of the new column.
- $id = db_insert($table_name)
- ->useDefaults(array('serial_column'))
- ->execute();
- $field_value = db_select($table_name)
- ->fields($table_name, array($field_name))
- ->condition('serial_column', $id)
- ->execute()
- ->fetchField();
- $this->assertEqual($field_value, $field_spec['default'], 'Default value registered.');
- }
-
- db_drop_field($table_name, $field_name);
- }
-}
diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test
deleted file mode 100644
index 097503b6..00000000
--- a/modules/simpletest/tests/session.test
+++ /dev/null
@@ -1,530 +0,0 @@
- 'Session tests',
- 'description' => 'Drupal session handling tests.',
- 'group' => 'Session'
- );
- }
-
- function setUp() {
- parent::setUp('session_test');
- }
-
- /**
- * Tests for drupal_save_session() and drupal_session_regenerate().
- */
- function testSessionSaveRegenerate() {
- $this->assertFalse(drupal_save_session(), 'drupal_save_session() correctly returns FALSE (inside of testing framework) when initially called with no arguments.', 'Session');
- $this->assertFalse(drupal_save_session(FALSE), 'drupal_save_session() correctly returns FALSE when called with FALSE.', 'Session');
- $this->assertFalse(drupal_save_session(), 'drupal_save_session() correctly returns FALSE when saving has been disabled.', 'Session');
- $this->assertTrue(drupal_save_session(TRUE), 'drupal_save_session() correctly returns TRUE when called with TRUE.', 'Session');
- $this->assertTrue(drupal_save_session(), 'drupal_save_session() correctly returns TRUE when saving has been enabled.', 'Session');
-
- // Test session hardening code from SA-2008-044.
- $user = $this->drupalCreateUser(array('access content'));
-
- // Enable sessions.
- $this->sessionReset($user->uid);
-
- // Make sure the session cookie is set as HttpOnly.
- $this->drupalLogin($user);
- $this->assertTrue(preg_match('/HttpOnly/i', $this->drupalGetHeader('Set-Cookie', TRUE)), 'Session cookie is set as HttpOnly.');
- $this->drupalLogout();
-
- // Verify that the session is regenerated if a module calls exit
- // in hook_user_login().
- user_save($user, array('name' => 'session_test_user'));
- $user->name = 'session_test_user';
- $this->drupalGet('session-test/id');
- $matches = array();
- preg_match('/\s*session_id:(.*)\n/', $this->drupalGetContent(), $matches);
- $this->assertTrue(!empty($matches[1]) , 'Found session ID before logging in.');
- $original_session = $matches[1];
-
- // We cannot use $this->drupalLogin($user); because we exit in
- // session_test_user_login() which breaks a normal assertion.
- $edit = array(
- 'name' => $user->name,
- 'pass' => $user->pass_raw
- );
- $this->drupalPost('user', $edit, t('Log in'));
- $this->drupalGet('user');
- $pass = $this->assertText($user->name, format_string('Found name: %name', array('%name' => $user->name)), 'User login');
- $this->_logged_in = $pass;
-
- $this->drupalGet('session-test/id');
- $matches = array();
- preg_match('/\s*session_id:(.*)\n/', $this->drupalGetContent(), $matches);
- $this->assertTrue(!empty($matches[1]) , 'Found session ID after logging in.');
- $this->assertTrue($matches[1] != $original_session, 'Session ID changed after login.');
- }
-
- /**
- * Test data persistence via the session_test module callbacks.
- */
- function testDataPersistence() {
- $user = $this->drupalCreateUser(array('access content'));
- // Enable sessions.
- $this->sessionReset($user->uid);
-
- $this->drupalLogin($user);
-
- $value_1 = $this->randomName();
- $this->drupalGet('session-test/set/' . $value_1);
- $this->assertText($value_1, 'The session value was stored.', 'Session');
- $this->drupalGet('session-test/get');
- $this->assertText($value_1, 'Session correctly returned the stored data for an authenticated user.', 'Session');
-
- // Attempt to write over val_1. If drupal_save_session(FALSE) is working.
- // properly, val_1 will still be set.
- $value_2 = $this->randomName();
- $this->drupalGet('session-test/no-set/' . $value_2);
- $this->assertText($value_2, 'The session value was correctly passed to session-test/no-set.', 'Session');
- $this->drupalGet('session-test/get');
- $this->assertText($value_1, 'Session data is not saved for drupal_save_session(FALSE).', 'Session');
-
- // Switch browser cookie to anonymous user, then back to user 1.
- $this->sessionReset();
- $this->sessionReset($user->uid);
- $this->assertText($value_1, 'Session data persists through browser close.', 'Session');
-
- // Logout the user and make sure the stored value no longer persists.
- $this->drupalLogout();
- $this->sessionReset();
- $this->drupalGet('session-test/get');
- $this->assertNoText($value_1, "After logout, previous user's session data is not available.", 'Session');
-
- // Now try to store some data as an anonymous user.
- $value_3 = $this->randomName();
- $this->drupalGet('session-test/set/' . $value_3);
- $this->assertText($value_3, 'Session data stored for anonymous user.', 'Session');
- $this->drupalGet('session-test/get');
- $this->assertText($value_3, 'Session correctly returned the stored data for an anonymous user.', 'Session');
-
- // Try to store data when drupal_save_session(FALSE).
- $value_4 = $this->randomName();
- $this->drupalGet('session-test/no-set/' . $value_4);
- $this->assertText($value_4, 'The session value was correctly passed to session-test/no-set.', 'Session');
- $this->drupalGet('session-test/get');
- $this->assertText($value_3, 'Session data is not saved for drupal_save_session(FALSE).', 'Session');
-
- // Login, the data should persist.
- $this->drupalLogin($user);
- $this->sessionReset($user->uid);
- $this->drupalGet('session-test/get');
- $this->assertNoText($value_1, 'Session has persisted for an authenticated user after logging out and then back in.', 'Session');
-
- // Change session and create another user.
- $user2 = $this->drupalCreateUser(array('access content'));
- $this->sessionReset($user2->uid);
- $this->drupalLogin($user2);
- }
-
- /**
- * Test that empty anonymous sessions are destroyed.
- */
- function testEmptyAnonymousSession() {
- // Verify that no session is automatically created for anonymous user.
- $this->drupalGet('');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(TRUE);
-
- // The same behavior is expected when caching is enabled.
- variable_set('cache', 1);
- $this->drupalGet('');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(TRUE);
- $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
-
- // Start a new session by setting a message.
- $this->drupalGet('session-test/set-message');
- $this->assertSessionCookie(TRUE);
- $this->assertTrue($this->drupalGetHeader('Set-Cookie'), 'New session was started.');
-
- // Display the message, during the same request the session is destroyed
- // and the session cookie is unset.
- $this->drupalGet('');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(FALSE);
- $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.');
- $this->assertText(t('This is a dummy message.'), 'Message was displayed.');
- $this->assertTrue(preg_match('/SESS\w+=deleted/', $this->drupalGetHeader('Set-Cookie')), 'Session cookie was deleted.');
-
- // Verify that session was destroyed.
- $this->drupalGet('');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(TRUE);
- $this->assertNoText(t('This is a dummy message.'), 'Message was not cached.');
- $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
- $this->assertFalse($this->drupalGetHeader('Set-Cookie'), 'New session was not started.');
-
- // Verify that no session is created if drupal_save_session(FALSE) is called.
- $this->drupalGet('session-test/set-message-but-dont-save');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(TRUE);
-
- // Verify that no message is displayed.
- $this->drupalGet('');
- $this->assertSessionCookie(FALSE);
- $this->assertSessionEmpty(TRUE);
- $this->assertNoText(t('This is a dummy message.'), 'The message was not saved.');
- }
-
- /**
- * Test that sessions are only saved when necessary.
- */
- function testSessionWrite() {
- $user = $this->drupalCreateUser(array('access content'));
- $this->drupalLogin($user);
-
- $sql = 'SELECT u.access, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE u.uid = :uid';
- $times1 = db_query($sql, array(':uid' => $user->uid))->fetchObject();
-
- // Before every request we sleep one second to make sure that if the session
- // is saved, its timestamp will change.
-
- // Modify the session.
- sleep(1);
- $this->drupalGet('session-test/set/foo');
- $times2 = db_query($sql, array(':uid' => $user->uid))->fetchObject();
- $this->assertEqual($times2->access, $times1->access, 'Users table was not updated.');
- $this->assertNotEqual($times2->timestamp, $times1->timestamp, 'Sessions table was updated.');
-
- // Write the same value again, i.e. do not modify the session.
- sleep(1);
- $this->drupalGet('session-test/set/foo');
- $times3 = db_query($sql, array(':uid' => $user->uid))->fetchObject();
- $this->assertEqual($times3->access, $times1->access, 'Users table was not updated.');
- $this->assertEqual($times3->timestamp, $times2->timestamp, 'Sessions table was not updated.');
-
- // Do not change the session.
- sleep(1);
- $this->drupalGet('');
- $times4 = db_query($sql, array(':uid' => $user->uid))->fetchObject();
- $this->assertEqual($times4->access, $times3->access, 'Users table was not updated.');
- $this->assertEqual($times4->timestamp, $times3->timestamp, 'Sessions table was not updated.');
-
- // Force updating of users and sessions table once per second.
- variable_set('session_write_interval', 0);
- $this->drupalGet('');
- $times5 = db_query($sql, array(':uid' => $user->uid))->fetchObject();
- $this->assertNotEqual($times5->access, $times4->access, 'Users table was updated.');
- $this->assertNotEqual($times5->timestamp, $times4->timestamp, 'Sessions table was updated.');
- }
-
- /**
- * Test that empty session IDs are not allowed.
- */
- function testEmptySessionID() {
- $user = $this->drupalCreateUser(array('access content'));
- $this->drupalLogin($user);
- $this->drupalGet('session-test/is-logged-in');
- $this->assertResponse(200, 'User is logged in.');
-
- // Reset the sid in {sessions} to a blank string. This may exist in the
- // wild in some cases, although we normally prevent it from happening.
- db_query("UPDATE {sessions} SET sid = '' WHERE uid = :uid", array(':uid' => $user->uid));
- // Send a blank sid in the session cookie, and the session should no longer
- // be valid. Closing the curl handler will stop the previous session ID
- // from persisting.
- $this->curlClose();
- $this->additionalCurlOptions[CURLOPT_COOKIE] = rawurlencode($this->session_name) . '=;';
- $this->drupalGet('session-test/id-from-cookie');
- $this->assertRaw("session_id:\n", 'Session ID is blank as sent from cookie header.');
- // Assert that we have an anonymous session now.
- $this->drupalGet('session-test/is-logged-in');
- $this->assertResponse(403, 'An empty session ID is not allowed.');
- }
-
- /**
- * Reset the cookie file so that it refers to the specified user.
- *
- * @param $uid User id to set as the active session.
- */
- function sessionReset($uid = 0) {
- // Close the internal browser.
- $this->curlClose();
- $this->loggedInUser = FALSE;
-
- // Change cookie file for user.
- $this->cookieFile = file_stream_wrapper_get_instance_by_scheme('temporary')->getDirectoryPath() . '/cookie.' . $uid . '.txt';
- $this->additionalCurlOptions[CURLOPT_COOKIEFILE] = $this->cookieFile;
- $this->additionalCurlOptions[CURLOPT_COOKIESESSION] = TRUE;
- $this->drupalGet('session-test/get');
- $this->assertResponse(200, 'Session test module is correctly enabled.', 'Session');
- }
-
- /**
- * Assert whether the SimpleTest browser sent a session cookie.
- */
- function assertSessionCookie($sent) {
- if ($sent) {
- $this->assertNotNull($this->session_id, 'Session cookie was sent.');
- }
- else {
- $this->assertNull($this->session_id, 'Session cookie was not sent.');
- }
- }
-
- /**
- * Assert whether $_SESSION is empty at the beginning of the request.
- */
- function assertSessionEmpty($empty) {
- if ($empty) {
- $this->assertIdentical($this->drupalGetHeader('X-Session-Empty'), '1', 'Session was empty.');
- }
- else {
- $this->assertIdentical($this->drupalGetHeader('X-Session-Empty'), '0', 'Session was not empty.');
- }
- }
-}
-
-/**
- * Ensure that when running under HTTPS two session cookies are generated.
- */
-class SessionHttpsTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Session HTTPS handling',
- 'description' => 'Ensure that when running under HTTPS two session cookies are generated.',
- 'group' => 'Session'
- );
- }
-
- public function setUp() {
- parent::setUp('session_test');
- }
-
- protected function testHttpsSession() {
- global $is_https;
-
- if ($is_https) {
- $secure_session_name = session_name();
- $insecure_session_name = substr(session_name(), 1);
- }
- else {
- $secure_session_name = 'S' . session_name();
- $insecure_session_name = session_name();
- }
-
- $user = $this->drupalCreateUser(array('access administration pages'));
-
- // Test HTTPS session handling by altering the form action to submit the
- // login form through https.php, which creates a mock HTTPS request.
- $this->drupalGet('user');
- $form = $this->xpath('//form[@id="user-login"]');
- $form[0]['action'] = $this->httpsUrl('user');
- $edit = array('name' => $user->name, 'pass' => $user->pass_raw);
- $this->drupalPost(NULL, $edit, t('Log in'));
-
- // Test a second concurrent session.
- $this->curlClose();
- $this->drupalGet('user');
- $form = $this->xpath('//form[@id="user-login"]');
- $form[0]['action'] = $this->httpsUrl('user');
- $this->drupalPost(NULL, $edit, t('Log in'));
-
- // Check secure cookie on secure page.
- $this->assertTrue($this->cookies[$secure_session_name]['secure'], 'The secure cookie has the secure attribute');
- // Check insecure cookie is not set.
- $this->assertFalse(isset($this->cookies[$insecure_session_name]));
- $ssid = $this->cookies[$secure_session_name]['value'];
- $this->assertSessionIds($ssid, $ssid, 'Session has a non-empty SID and a correct secure SID.');
- $cookie = $secure_session_name . '=' . $ssid;
-
- // Verify that user is logged in on secure URL.
- $this->curlClose();
- $this->drupalGet($this->httpsUrl('admin/config'), array(), array('Cookie: ' . $cookie));
- $this->assertText(t('Configuration'));
- $this->assertResponse(200);
-
- // Verify that user is not logged in on non-secure URL.
- $this->curlClose();
- $this->drupalGet($this->httpUrl('admin/config'), array(), array('Cookie: ' . $cookie));
- $this->assertNoText(t('Configuration'));
- $this->assertResponse(403);
-
- // Verify that empty SID cannot be used on the non-secure site.
- $this->curlClose();
- $cookie = $insecure_session_name . '=';
- $this->drupalGet($this->httpUrl('admin/config'), array(), array('Cookie: ' . $cookie));
- $this->assertResponse(403);
-
- // Test HTTP session handling by altering the form action to submit the
- // login form through http.php, which creates a mock HTTP request on HTTPS
- // test environments.
- $this->curlClose();
- $this->drupalGet('user');
- $form = $this->xpath('//form[@id="user-login"]');
- $form[0]['action'] = $this->httpUrl('user');
- $edit = array('name' => $user->name, 'pass' => $user->pass_raw);
- $this->drupalPost(NULL, $edit, t('Log in'));
- $this->drupalGet($this->httpUrl('admin/config'));
- $this->assertResponse(200);
- $sid = $this->cookies[$insecure_session_name]['value'];
- $this->assertSessionIds($sid, '', 'Session has the correct SID and an empty secure SID.');
-
- // Verify that empty secure SID cannot be used on the secure site.
- $this->curlClose();
- $cookie = $secure_session_name . '=';
- $this->drupalGet($this->httpsUrl('admin/config'), array(), array('Cookie: ' . $cookie));
- $this->assertResponse(403);
-
- // Clear browser cookie jar.
- $this->cookies = array();
-
- if ($is_https) {
- // The functionality does not make sense when running on HTTPS.
- return;
- }
-
- // Enable secure pages.
- variable_set('https', TRUE);
-
- $this->curlClose();
- // Start an anonymous session on the insecure site.
- $session_data = $this->randomName();
- $this->drupalGet('session-test/set/' . $session_data);
- // Check secure cookie on insecure page.
- $this->assertFalse(isset($this->cookies[$secure_session_name]), 'The secure cookie is not sent on insecure pages.');
- // Check insecure cookie on insecure page.
- $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute');
-
- // Store the anonymous cookie so we can validate that its session is killed
- // after login.
- $anonymous_cookie = $insecure_session_name . '=' . $this->cookies[$insecure_session_name]['value'];
-
- // Check that password request form action is not secure.
- $this->drupalGet('user/password');
- $form = $this->xpath('//form[@id="user-pass"]');
- $this->assertNotEqual(substr($form[0]['action'], 0, 6), 'https:', 'Password request form action is not secure');
- $form[0]['action'] = $this->httpsUrl('user');
-
- // Check that user login form action is secure.
- $this->drupalGet('user');
- $form = $this->xpath('//form[@id="user-login"]');
- $this->assertEqual(substr($form[0]['action'], 0, 6), 'https:', 'Login form action is secure');
- $form[0]['action'] = $this->httpsUrl('user');
-
- $edit = array(
- 'name' => $user->name,
- 'pass' => $user->pass_raw,
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check secure cookie on secure page.
- $this->assertTrue($this->cookies[$secure_session_name]['secure'], 'The secure cookie has the secure attribute');
- // Check insecure cookie on secure page.
- $this->assertFalse($this->cookies[$insecure_session_name]['secure'], 'The insecure cookie does not have the secure attribute');
-
- $sid = $this->cookies[$insecure_session_name]['value'];
- $ssid = $this->cookies[$secure_session_name]['value'];
- $this->assertSessionIds($sid, $ssid, 'Session has both secure and insecure SIDs');
- $cookies = array(
- $insecure_session_name . '=' . $sid,
- $secure_session_name . '=' . $ssid,
- );
-
- // Test that session data saved before login is still available on the
- // authenticated session.
- $this->drupalGet('session-test/get');
- $this->assertText($session_data, 'Session correctly returned the stored data set by the anonymous session.');
-
- foreach ($cookies as $cookie_key => $cookie) {
- foreach (array('admin/config', $this->httpsUrl('admin/config')) as $url_key => $url) {
- $this->curlClose();
-
- $this->drupalGet($url, array(), array('Cookie: ' . $cookie));
- if ($cookie_key == $url_key) {
- $this->assertText(t('Configuration'));
- $this->assertResponse(200);
- }
- else {
- $this->assertNoText(t('Configuration'));
- $this->assertResponse(403);
- }
- }
- }
-
- // Test that session data saved before login is not available using the
- // pre-login anonymous cookie.
- $this->cookies = array();
- $this->drupalGet('session-test/get', array('Cookie: ' . $anonymous_cookie));
- $this->assertNoText($session_data, 'Initial anonymous session is inactive after login.');
-
- // Clear browser cookie jar.
- $this->cookies = array();
-
- // Start an anonymous session on the secure site.
- $this->drupalGet($this->httpsUrl('session-test/set/1'));
-
- // Mock a login to the secure site using the secure session cookie.
- $this->drupalGet('user');
- $form = $this->xpath('//form[@id="user-login"]');
- $form[0]['action'] = $this->httpsUrl('user');
- $this->drupalPost(NULL, $edit, t('Log in'));
-
- // Test that the user is also authenticated on the insecure site.
- $this->drupalGet("user/{$user->uid}/edit");
- $this->assertResponse(200);
- }
-
- /**
- * Test that there exists a session with two specific session IDs.
- *
- * @param $sid
- * The insecure session ID to search for.
- * @param $ssid
- * The secure session ID to search for.
- * @param $assertion_text
- * The text to display when we perform the assertion.
- *
- * @return
- * The result of assertTrue() that there's a session in the system that
- * has the given insecure and secure session IDs.
- */
- protected function assertSessionIds($sid, $ssid, $assertion_text) {
- $args = array(
- ':sid' => $sid,
- ':ssid' => $ssid,
- );
- return $this->assertTrue(db_query('SELECT timestamp FROM {sessions} WHERE sid = :sid AND ssid = :ssid', $args)->fetchField(), $assertion_text);
- }
-
- /**
- * Builds a URL for submitting a mock HTTPS request to HTTP test environments.
- *
- * @param $url
- * A Drupal path such as 'user'.
- *
- * @return
- * An absolute URL.
- */
- protected function httpsUrl($url) {
- global $base_url;
- return $base_url . '/modules/simpletest/tests/https.php?q=' . $url;
- }
-
- /**
- * Builds a URL for submitting a mock HTTP request to HTTPS test environments.
- *
- * @param $url
- * A Drupal path such as 'user'.
- *
- * @return
- * An absolute URL.
- */
- protected function httpUrl($url) {
- global $base_url;
- return $base_url . '/modules/simpletest/tests/http.php?q=' . $url;
- }
-}
-
diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info
deleted file mode 100644
index 4e210303..00000000
--- a/modules/simpletest/tests/session_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Session test"
-description = "Support module for session data testing."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/session_test.module b/modules/simpletest/tests/session_test.module
deleted file mode 100644
index 689ff099..00000000
--- a/modules/simpletest/tests/session_test.module
+++ /dev/null
@@ -1,192 +0,0 @@
- 'Session value',
- 'page callback' => '_session_test_get',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/id'] = array(
- 'title' => 'Session ID',
- 'page callback' => '_session_test_id',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/id-from-cookie'] = array(
- 'title' => 'Session ID from cookie',
- 'page callback' => '_session_test_id_from_cookie',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/set/%'] = array(
- 'title' => 'Set session value',
- 'page callback' => '_session_test_set',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/no-set/%'] = array(
- 'title' => 'Set session value but do not save session',
- 'page callback' => '_session_test_no_set',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/set-message'] = array(
- 'title' => 'Set message',
- 'page callback' => '_session_test_set_message',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/set-message-but-dont-save'] = array(
- 'title' => 'Set message but do not save session',
- 'page callback' => '_session_test_set_message_but_dont_save',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/set-not-started'] = array(
- 'title' => 'Set message when session is not started',
- 'page callback' => '_session_test_set_not_started',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['session-test/is-logged-in'] = array(
- 'title' => 'Check if user is logged in',
- 'page callback' => '_session_test_is_logged_in',
- 'access callback' => 'user_is_logged_in',
- 'type' => MENU_CALLBACK,
- );
-
- return $items;
-}
-
-/**
- * Implements hook_boot().
- */
-function session_test_boot() {
- header('X-Session-Empty: ' . intval(empty($_SESSION)));
-}
-
-/**
- * Page callback, prints the stored session value to the screen.
- */
-function _session_test_get() {
- if (!empty($_SESSION['session_test_value'])) {
- return t('The current value of the stored session variable is: %val', array('%val' => $_SESSION['session_test_value']));
- }
- else {
- return "";
- }
-}
-
-/**
- * Page callback, stores a value in $_SESSION['session_test_value'].
- */
-function _session_test_set($value) {
- $_SESSION['session_test_value'] = $value;
- return t('The current value of the stored session variable has been set to %val', array('%val' => $value));
-}
-
-/**
- * Menu callback: turns off session saving and then tries to save a value
- * anyway.
- */
-function _session_test_no_set($value) {
- drupal_save_session(FALSE);
- _session_test_set($value);
- return t('session saving was disabled, and then %val was set', array('%val' => $value));
-}
-
-/**
- * Menu callback: print the current session ID.
- */
-function _session_test_id() {
- // Set a value in $_SESSION, so that drupal_session_commit() will start
- // a session.
- $_SESSION['test'] = 'test';
-
- drupal_session_commit();
-
- return 'session_id:' . session_id() . "\n";
-}
-
-/**
- * Menu callback: print the current session ID as read from the cookie.
- */
-function _session_test_id_from_cookie() {
- return 'session_id:' . $_COOKIE[session_name()] . "\n";
-}
-
-/**
- * Menu callback, sets a message to me displayed on the following page.
- */
-function _session_test_set_message() {
- drupal_set_message(t('This is a dummy message.'));
- print t('A message was set.');
- // Do not return anything, so the current request does not result in a themed
- // page with messages. The message will be displayed in the following request
- // instead.
-}
-
-/**
- * Menu callback, sets a message but call drupal_save_session(FALSE).
- */
-function _session_test_set_message_but_dont_save() {
- drupal_save_session(FALSE);
- _session_test_set_message();
-}
-
-/**
- * Menu callback, stores a value in $_SESSION['session_test_value'] without
- * having started the session in advance.
- */
-function _session_test_set_not_started() {
- if (!drupal_session_will_start()) {
- $_SESSION['session_test_value'] = t('Session was not started');
- }
-}
-
-/**
- * Implements hook_user().
- */
-function session_test_user_login($edit = array(), $user = NULL) {
- if ($user->name == 'session_test_user') {
- // Exit so we can verify that the session was regenerated
- // before hook_user() was called.
- exit;
- }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function session_test_form_user_login_alter(&$form) {
- $form['#https'] = TRUE;
-}
-
-/**
- * Implements hook_drupal_goto_alter().
- *
- * Force the redirection to go to a non-secure page after being on a secure
- * page through https.php.
- */
-function session_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
- global $base_insecure_url, $is_https_mock;
- // Alter the redirect to use HTTP when using a mock HTTPS request through
- // https.php because form submissions would otherwise redirect to a
- // non-existent HTTPS site.
- if (!empty($is_https_mock)) {
- $path = $base_insecure_url . '/' . $path;
- }
-}
-
-/**
- * Menu callback, only available if current user is logged in.
- */
-function _session_test_is_logged_in() {
- return t('User is logged in.');
-}
diff --git a/modules/simpletest/tests/system.base.css b/modules/simpletest/tests/system.base.css
deleted file mode 100644
index c14ae9b2..00000000
--- a/modules/simpletest/tests/system.base.css
+++ /dev/null
@@ -1,6 +0,0 @@
-
-/**
- * This file is for testing CSS file override in
- * CascadingStylesheetsTestCase::testRenderOverride().
- * No contents are necessary.
- */
diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info
deleted file mode 100644
index 58260868..00000000
--- a/modules/simpletest/tests/system_dependencies_test.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = "System dependency test"
-description = "Support module for testing system dependencies."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-dependencies[] = _missing_dependency
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/system_dependencies_test.module b/modules/simpletest/tests/system_dependencies_test.module
deleted file mode 100644
index b3d9bbc7..00000000
--- a/modules/simpletest/tests/system_dependencies_test.module
+++ /dev/null
@@ -1 +0,0 @@
-2.0)
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module
deleted file mode 100644
index b3d9bbc7..00000000
--- a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module
+++ /dev/null
@@ -1 +0,0 @@
- 'system_test_sleep',
- 'page arguments' => array(2),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/auth'] = array(
- 'page callback' => 'system_test_basic_auth_page',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/authorize-init/%'] = array(
- 'page callback' => 'system_test_authorize_init_page',
- 'page arguments' => array(2),
- 'access arguments' => array('administer software updates'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/redirect/%'] = array(
- 'title' => 'Redirect',
- 'page callback' => 'system_test_redirect',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/multiple-redirects/%'] = array(
- 'title' => 'Redirect',
- 'page callback' => 'system_test_multiple_redirects',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/set-header'] = array(
- 'page callback' => 'system_test_set_header',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/redirect-noscheme'] = array(
- 'page callback' => 'system_test_redirect_noscheme',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/redirect-noparse'] = array(
- 'page callback' => 'system_test_redirect_noparse',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
- $items['system-test/redirect-invalid-scheme'] = array(
- 'page callback' => 'system_test_redirect_invalid_scheme',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/variable-get'] = array(
- 'title' => 'Variable Get',
- 'page callback' => 'variable_get',
- 'page arguments' => array('simpletest_bootstrap_variable_test', NULL),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/lock-acquire'] = array(
- 'title' => 'Lock acquire',
- 'page callback' => 'system_test_lock_acquire',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/lock-exit'] = array(
- 'title' => 'Lock acquire then exit',
- 'page callback' => 'system_test_lock_exit',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/main-content-handling'] = array(
- 'title' => 'Test main content handling',
- 'page callback' => 'system_test_main_content_fallback',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/main-content-fallback'] = array(
- 'title' => 'Test main content fallback',
- 'page callback' => 'system_test_main_content_fallback',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/main-content-duplication'] = array(
- 'title' => 'Test main content duplication',
- 'page callback' => 'system_test_main_content_fallback',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- $items['system-test/shutdown-functions'] = array(
- 'title' => 'Test main content duplication',
- 'page callback' => 'system_test_page_shutdown_functions',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- return $items;
-}
-
-function system_test_sleep($seconds) {
- sleep($seconds);
-}
-
-function system_test_basic_auth_page() {
- $output = t('$_SERVER[\'PHP_AUTH_USER\'] is @username.', array('@username' => $_SERVER['PHP_AUTH_USER']));
- $output .= t('$_SERVER[\'PHP_AUTH_PW\'] is @password.', array('@password' => $_SERVER['PHP_AUTH_PW']));
- return $output;
-}
-
-function system_test_redirect($code) {
- $code = (int) $code;
- if ($code != 200) {
- // Header names are case-insensitive.
- header("locaTION: " . url('system-test/redirect/200', array('absolute' => TRUE)), TRUE, $code);
- exit;
- }
- return '';
-}
-
-/**
- * Menu callback; sends a redirect header to itself until $count argument is 0.
- *
- * Emulates the variable number of redirects (given by initial $count argument)
- * to the final destination URL by continuous sending of 301 HTTP redirect
- * headers to itself together with decrementing the $count parameter until the
- * $count parameter reaches 0. After that it returns an empty string to render
- * the final destination page.
- *
- * @param $count
- * The count of redirects left until the final destination page.
- *
- * @returns
- * The location redirect if the $count > 0, otherwise an empty string.
- */
-function system_test_multiple_redirects($count) {
- $count = (int) $count;
- if ($count > 0) {
- header("location: " . url('system-test/multiple-redirects/' . --$count, array('absolute' => TRUE)), TRUE, 301);
- exit;
- }
- return '';
-}
-
-function system_test_set_header() {
- drupal_add_http_header($_GET['name'], $_GET['value']);
- return t('The following header was set: %name: %value', array('%name' => $_GET['name'], '%value' => $_GET['value']));
-}
-
-function system_test_redirect_noscheme() {
- header("Location: localhost/path", TRUE, 301);
- exit;
-}
-
-function system_test_redirect_noparse() {
- header("Location: http:///path", TRUE, 301);
- exit;
-}
-
-function system_test_redirect_invalid_scheme() {
- header("Location: ftp://localhost/path", TRUE, 301);
- exit;
-}
-
-/**
- * Implements hook_modules_installed().
- */
-function system_test_modules_installed($modules) {
- if (variable_get('test_verbose_module_hooks')) {
- foreach ($modules as $module) {
- drupal_set_message(t('hook_modules_installed fired for @module', array('@module' => $module)));
- }
- }
-}
-
-/**
- * Implements hook_modules_enabled().
- */
-function system_test_modules_enabled($modules) {
- if (variable_get('test_verbose_module_hooks')) {
- foreach ($modules as $module) {
- drupal_set_message(t('hook_modules_enabled fired for @module', array('@module' => $module)));
- }
- }
-}
-
-/**
- * Implements hook_modules_disabled().
- */
-function system_test_modules_disabled($modules) {
- if (variable_get('test_verbose_module_hooks')) {
- foreach ($modules as $module) {
- drupal_set_message(t('hook_modules_disabled fired for @module', array('@module' => $module)));
- }
- }
-}
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function system_test_modules_uninstalled($modules) {
- if (variable_get('test_verbose_module_hooks')) {
- foreach ($modules as $module) {
- drupal_set_message(t('hook_modules_uninstalled fired for @module', array('@module' => $module)));
- }
- }
-}
-
-/**
- * Implements hook_boot().
- */
-function system_test_boot() {
- watchdog('system_test', 'hook_boot');
-}
-
-/**
- * Implements hook_init().
- */
-function system_test_init() {
- // Used by FrontPageTestCase to get the results of drupal_is_front_page().
- if (variable_get('front_page_output', 0) && drupal_is_front_page()) {
- drupal_set_message(t('On front page.'));
- }
-}
-
-/**
- * Implements hook_exit().
- */
-function system_test_exit() {
- watchdog('system_test', 'hook_exit');
-}
-
-/**
- * Implements hook_system_info_alter().
- */
-function system_test_system_info_alter(&$info, $file, $type) {
- // We need a static otherwise the last test will fail to alter common_test.
- static $test;
- if (($dependencies = variable_get('dependencies', array())) || $test) {
- if ($file->name == 'module_test') {
- $info['hidden'] = FALSE;
- $info['dependencies'][] = array_shift($dependencies);
- variable_set('dependencies', $dependencies);
- $test = TRUE;
- }
- if ($file->name == 'common_test') {
- $info['hidden'] = FALSE;
- $info['version'] = '7.x-2.4-beta3';
- }
- }
-
- // Make the system_dependencies_test visible by default.
- if ($file->name == 'system_dependencies_test') {
- $info['hidden'] = FALSE;
- }
- if (in_array($file->name, array(
- 'system_incompatible_module_version_dependencies_test',
- 'system_incompatible_core_version_dependencies_test',
- 'system_incompatible_module_version_test',
- 'system_incompatible_core_version_test',
- ))) {
- $info['hidden'] = FALSE;
- }
- if ($file->name == 'requirements1_test' || $file->name == 'requirements2_test') {
- $info['hidden'] = FALSE;
- }
-}
-
-/**
- * Try to acquire a named lock and report the outcome.
- */
-function system_test_lock_acquire() {
- if (lock_acquire('system_test_lock_acquire')) {
- lock_release('system_test_lock_acquire');
- return 'TRUE: Lock successfully acquired in system_test_lock_acquire()';
- }
- else {
- return 'FALSE: Lock not acquired in system_test_lock_acquire()';
- }
-}
-
-/**
- * Try to acquire a specific lock, and then exit.
- */
-function system_test_lock_exit() {
- if (lock_acquire('system_test_lock_exit', 900)) {
- echo 'TRUE: Lock successfully acquired in system_test_lock_exit()';
- // The shut-down function should release the lock.
- exit();
- }
- else {
- return 'FALSE: Lock not acquired in system_test_lock_exit()';
- }
-}
-
-/**
- * Implements hook_page_build().
- */
-function system_test_page_build(&$page) {
- $menu_item = menu_get_item();
- $main_content_display = &drupal_static('system_main_content_added', FALSE);
-
- if ($menu_item['path'] == 'system-test/main-content-handling') {
- $page['footer'] = drupal_set_page_content();
- $page['footer']['main']['#markup'] = '' . $page['footer']['main']['#markup'] . '
';
- }
- elseif ($menu_item['path'] == 'system-test/main-content-fallback') {
- drupal_set_page_content();
- $main_content_display = FALSE;
- }
- elseif ($menu_item['path'] == 'system-test/main-content-duplication') {
- drupal_set_page_content();
- }
-}
-
-/**
- * Menu callback to test main content fallback().
- */
-function system_test_main_content_fallback() {
- return t('Content to test main content fallback');
-}
-
-/**
- * A simple page callback which adds a register shutdown function.
- */
-function system_test_page_shutdown_functions($arg1, $arg2) {
- drupal_register_shutdown_function('_system_test_first_shutdown_function', $arg1, $arg2);
-}
-
-/**
- * Dummy shutdown function which registers another shutdown function.
- */
-function _system_test_first_shutdown_function($arg1, $arg2) {
- // Output something, page has already been printed and the session stored
- // so we can't use drupal_set_message.
- print t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2));
- drupal_register_shutdown_function('_system_test_second_shutdown_function', $arg1, $arg2);
-}
-
-/**
- * Dummy shutdown function.
- */
-function _system_test_second_shutdown_function($arg1, $arg2) {
- // Output something, page has already been printed and the session stored
- // so we can't use drupal_set_message.
- print t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2));
-
- // Throw an exception with an HTML tag. Since this is called in a shutdown
- // function, it will not bubble up to the default exception handler but will
- // be caught in _drupal_shutdown_function() and be displayed through
- // _drupal_render_exception_safe().
- throw new Exception('Drupal is awesome .');
-}
-
-/**
- * Implements hook_filetransfer_info().
- */
-function system_test_filetransfer_info() {
- return array(
- 'system_test' => array(
- 'title' => t('System Test FileTransfer'),
- 'file' => 'system_test.module', // Should be a .inc, but for test, ok.
- 'class' => 'SystemTestFileTransfer',
- 'weight' => -10,
- ),
- );
-}
-
-/**
- * Mock FileTransfer object to test the settings form functionality.
- */
-class SystemTestFileTransfer {
- public static function factory() {
- return new SystemTestFileTransfer;
- }
-
- public function getSettingsForm() {
- $form = array();
- $form['system_test_username'] = array(
- '#type' => 'textfield',
- '#title' => t('System Test Username'),
- );
- return $form;
- }
-}
-
-/**
- * Page callback to initialize authorize.php during testing.
- *
- * @see system_authorized_init().
- */
-function system_test_authorize_init_page($page_title) {
- $authorize_url = $GLOBALS['base_url'] . '/authorize.php';
- system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
- drupal_goto($authorize_url);
-}
diff --git a/modules/simpletest/tests/tablesort.test b/modules/simpletest/tests/tablesort.test
deleted file mode 100644
index ffc9535d..00000000
--- a/modules/simpletest/tests/tablesort.test
+++ /dev/null
@@ -1,166 +0,0 @@
- 'Tablesort',
- 'description' => 'Tests table sorting.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- // Save the original $_GET to be restored later.
- $this->GET = $_GET;
-
- parent::setUp();
- }
-
- function tearDown() {
- // Revert $_GET.
- $_GET = $this->GET;
-
- parent::tearDown();
- }
-
- /**
- * Test tablesort_init().
- */
- function testTableSortInit() {
-
- // Test simple table headers.
-
- $headers = array('foo', 'bar', 'baz');
- // Reset $_GET to prevent parameters from Simpletest and Batch API ending
- // up in $ts['query'].
- $_GET = array('q' => 'jahwohl');
- $expected_ts = array(
- 'name' => 'foo',
- 'sql' => '',
- 'sort' => 'asc',
- 'query' => array(),
- );
- $ts = tablesort_init($headers);
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Simple table headers sorted correctly.');
-
- // Test with simple table headers plus $_GET parameters that should _not_
- // override the default.
-
- $_GET = array(
- 'q' => 'jahwohl',
- // This should not override the table order because only complex
- // headers are overridable.
- 'order' => 'bar',
- );
- $ts = tablesort_init($headers);
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Simple table headers plus non-overriding $_GET parameters sorted correctly.');
-
- // Test with simple table headers plus $_GET parameters that _should_
- // override the default.
-
- $_GET = array(
- 'q' => 'jahwohl',
- 'sort' => 'DESC',
- // Add an unrelated parameter to ensure that tablesort will include
- // it in the links that it creates.
- 'alpha' => 'beta',
- );
- $expected_ts['sort'] = 'desc';
- $expected_ts['query'] = array('alpha' => 'beta');
- $ts = tablesort_init($headers);
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Simple table headers plus $_GET parameters sorted correctly.');
-
- // Test complex table headers.
-
- $headers = array(
- 'foo',
- array(
- 'data' => '1',
- 'field' => 'one',
- 'sort' => 'asc',
- 'colspan' => 1,
- ),
- array(
- 'data' => '2',
- 'field' => 'two',
- 'sort' => 'desc',
- ),
- );
- // Reset $_GET from previous assertion.
- $_GET = array(
- 'q' => 'jahwohl',
- 'order' => '2',
- );
- $ts = tablesort_init($headers);
- $expected_ts = array(
- 'name' => '2',
- 'sql' => 'two',
- 'sort' => 'desc',
- 'query' => array(),
- );
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Complex table headers sorted correctly.');
-
- // Test complex table headers plus $_GET parameters that should _not_
- // override the default.
-
- $_GET = array(
- 'q' => 'jahwohl',
- // This should not override the table order because this header does not
- // exist.
- 'order' => 'bar',
- );
- $ts = tablesort_init($headers);
- $expected_ts = array(
- 'name' => '1',
- 'sql' => 'one',
- 'sort' => 'asc',
- 'query' => array(),
- );
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Complex table headers plus non-overriding $_GET parameters sorted correctly.');
- unset($_GET['sort'], $_GET['order'], $_GET['alpha']);
-
- // Test complex table headers plus $_GET parameters that _should_
- // override the default.
-
- $_GET = array(
- 'q' => 'jahwohl',
- 'order' => '1',
- 'sort' => 'ASC',
- // Add an unrelated parameter to ensure that tablesort will include
- // it in the links that it creates.
- 'alpha' => 'beta',
- );
- $expected_ts = array(
- 'name' => '1',
- 'sql' => 'one',
- 'sort' => 'asc',
- 'query' => array('alpha' => 'beta'),
- );
- $ts = tablesort_init($headers);
- $this->verbose(strtr('$ts: !ts ', array('!ts' => check_plain(var_export($ts, TRUE)))));
- $this->assertEqual($ts, $expected_ts, 'Complex table headers plus $_GET parameters sorted correctly.');
- unset($_GET['sort'], $_GET['order'], $_GET['alpha']);
-
- }
-}
diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info
deleted file mode 100644
index 296a2b85..00000000
--- a/modules/simpletest/tests/taxonomy_test.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = "Taxonomy test module"
-description = "Tests functions and hooks not used in core".
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-dependencies[] = taxonomy
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/taxonomy_test.install b/modules/simpletest/tests/taxonomy_test.install
deleted file mode 100644
index d5c94da5..00000000
--- a/modules/simpletest/tests/taxonomy_test.install
+++ /dev/null
@@ -1,34 +0,0 @@
- 'Stores term antonym.',
- 'fields' => array(
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The {taxonomy_term_data}.tid of the term.',
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The name of the antonym.',
- ),
- ),
- 'primary key' => array('tid'),
- );
-
- return $schema;
-}
diff --git a/modules/simpletest/tests/taxonomy_test.module b/modules/simpletest/tests/taxonomy_test.module
deleted file mode 100644
index f82950c3..00000000
--- a/modules/simpletest/tests/taxonomy_test.module
+++ /dev/null
@@ -1,111 +0,0 @@
-tid);
- if ($antonym) {
- $term->antonym = $antonym;
- }
- }
-}
-
-/**
- * Implements hook_taxonomy_term_insert().
- */
-function taxonomy_test_taxonomy_term_insert($term) {
- if (!empty($term->antonym)) {
- db_insert('taxonomy_term_antonym')
- ->fields(array(
- 'tid' => $term->tid,
- 'name' => trim($term->antonym)
- ))
- ->execute();
- }
-}
-
-/**
- * Implements hook_taxonomy_term_update().
- */
-function taxonomy_test_taxonomy_term_update($term) {
- if (!empty($term->antonym)) {
- db_merge('taxonomy_term_antonym')
- ->key(array('tid' => $term->tid))
- ->fields(array(
- 'name' => trim($term->antonym)
- ))
- ->execute();
- }
-}
-
-/**
- * Implements hook_taxonomy_term_delete().
- */
-function taxonomy_test_taxonomy_term_delete($term) {
- db_delete('taxonomy_term_antonym')
- ->condition('tid', $term->tid)
- ->execute();
-}
-
-/**
- * Implements hook_taxonomy_term_view().
- */
-function taxonomy_test_taxonomy_term_view($term, $view_mode, $langcode) {
- if ($view_mode == 'full') {
- $term->content['taxonomy_test_term_view_check'] = array(
- '#prefix' => '',
- '#markup' => t('The antonym is %antonym', array('%antonym' => $term->antonym)),
- '#suffix' => '
',
- '#weight' => 10,
- );
- }
-}
-
-/**
- * Implements hook_entity_view().
- */
-function taxonomy_test_entity_view($entity, $type, $view_mode, $langcode) {
- if ($type == 'taxonomy_term' && $view_mode == 'full') {
- $entity->content['taxonomy_test_entity_view_check'] = array(
- '#prefix' => '',
- '#markup' => t('The antonym is %antonym', array('%antonym' => $entity->antonym)),
- '#suffix' => '
',
- '#weight' => 20,
- );
- }
-}
-
-/**
- * Implements hook_form_alter().
- */
-function taxonomy_test_form_alter(&$form, $form_state, $form_id) {
- if ($form_id == 'taxonomy_form_term') {
- $antonym = taxonomy_test_get_antonym($form['#term']['tid']);
- $form['advanced']['antonym'] = array(
- '#type' => 'textfield',
- '#title' => t('Antonym'),
- '#default_value' => !empty($antonym) ? $antonym : '',
- '#description' => t('Antonym of this term.')
- );
- }
-}
-
-/**
- * Return the antonym of the given term ID.
- */
-function taxonomy_test_get_antonym($tid) {
- return db_select('taxonomy_term_antonym', 'ta')
- ->fields('ta', array('name'))
- ->condition('tid', $tid)
- ->execute()
- ->fetchField();
-}
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
deleted file mode 100644
index 519a7a90..00000000
--- a/modules/simpletest/tests/theme.test
+++ /dev/null
@@ -1,502 +0,0 @@
- 'Theme API',
- 'description' => 'Test low-level theme functions.',
- 'group' => 'Theme',
- );
- }
-
- function setUp() {
- parent::setUp('theme_test');
- theme_enable(array('test_theme'));
- }
-
- /**
- * Test function theme_get_suggestions() for SA-CORE-2009-003.
- */
- function testThemeSuggestions() {
- // Set the front page as something random otherwise the CLI
- // test runner fails.
- variable_set('site_frontpage', 'nobody-home');
- $args = array('node', '1', 'edit');
- $suggestions = theme_get_suggestions($args, 'page');
- $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1', 'page__node__edit'), 'Found expected node edit page suggestions');
- // Check attack vectors.
- $args = array('node', '\\1');
- $suggestions = theme_get_suggestions($args, 'page');
- $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid \\ from suggestions');
- $args = array('node', '1/');
- $suggestions = theme_get_suggestions($args, 'page');
- $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid / from suggestions');
- $args = array('node', "1\0");
- $suggestions = theme_get_suggestions($args, 'page');
- $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1'), 'Removed invalid \\0 from suggestions');
- // Define path with hyphens to be used to generate suggestions.
- $args = array('node', '1', 'hyphen-path');
- $result = array('page__node', 'page__node__%', 'page__node__1', 'page__node__hyphen_path');
- $suggestions = theme_get_suggestions($args, 'page');
- $this->assertEqual($suggestions, $result, 'Found expected page suggestions for paths containing hyphens.');
- }
-
- /**
- * Ensures preprocess functions run even for suggestion implementations.
- *
- * The theme hook used by this test has its base preprocess function in a
- * separate file, so this test also ensures that that file is correctly loaded
- * when needed.
- */
- function testPreprocessForSuggestions() {
- // Test with both an unprimed and primed theme registry.
- drupal_theme_rebuild();
- for ($i = 0; $i < 2; $i++) {
- $this->drupalGet('theme-test/suggestion');
- $this->assertText('Theme hook implementor=test_theme_theme_test__suggestion(). Foo=template_preprocess_theme_test', 'Theme hook suggestion ran with data available from a preprocess function for the base hook.');
- }
- }
-
- /**
- * Ensure page-front template suggestion is added when on front page.
- */
- function testFrontPageThemeSuggestion() {
- $q = $_GET['q'];
- // Set $_GET['q'] to node because theme_get_suggestions() will query it to
- // see if we are on the front page.
- $_GET['q'] = variable_get('site_frontpage', 'node');
- $suggestions = theme_get_suggestions(explode('/', $_GET['q']), 'page');
- // Set it back to not annoy the batch runner.
- $_GET['q'] = $q;
- $this->assertTrue(in_array('page__front', $suggestions), 'Front page template was suggested.');
- }
-
- /**
- * Ensures theme hook_*_alter() implementations can run before anything is rendered.
- */
- function testAlter() {
- $this->drupalGet('theme-test/alter');
- $this->assertText('The altered data is test_theme_theme_test_alter_alter was invoked.', 'The theme was able to implement an alter hook during page building before anything was rendered.');
- }
-
- /**
- * Ensures a theme's .info file is able to override a module CSS file from being added to the page.
- *
- * @see test_theme.info
- */
- function testCSSOverride() {
- // Reuse the same page as in testPreprocessForSuggestions(). We're testing
- // what is output to the HTML HEAD based on what is in a theme's .info file,
- // so it doesn't matter what page we get, as long as it is themed with the
- // test theme. First we test with CSS aggregation disabled.
- variable_set('preprocess_css', 0);
- $this->drupalGet('theme-test/suggestion');
- $this->assertNoText('system.base.css', 'The theme\'s .info file is able to override a module CSS file from being added to the page.');
-
- // Also test with aggregation enabled, simply ensuring no PHP errors are
- // triggered during drupal_build_css_cache() when a source file doesn't
- // exist. Then allow remaining tests to continue with aggregation disabled
- // by default.
- variable_set('preprocess_css', 1);
- $this->drupalGet('theme-test/suggestion');
- variable_set('preprocess_css', 0);
- }
-
- /**
- * Ensures the theme registry is rebuilt when modules are disabled/enabled.
- */
- function testRegistryRebuild() {
- $this->assertIdentical(theme('theme_test_foo', array('foo' => 'a')), 'a', 'The theme registry contains theme_test_foo.');
-
- module_disable(array('theme_test'), FALSE);
- $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '', 'The theme registry does not contain theme_test_foo, because the module is disabled.');
-
- module_enable(array('theme_test'), FALSE);
- $this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.');
- }
-
- /**
- * Test the list_themes() function.
- */
- function testListThemes() {
- $themes = list_themes();
- // Check if drupal_theme_access() retrieves enabled themes properly from list_themes().
- $this->assertTrue(drupal_theme_access('test_theme'), 'Enabled theme detected');
- // Check if list_themes() returns disabled themes.
- $this->assertTrue(array_key_exists('test_basetheme', $themes), 'Disabled theme detected');
- // Check for base theme and subtheme lists.
- $base_theme_list = array('test_basetheme' => 'Theme test base theme');
- $sub_theme_list = array('test_subtheme' => 'Theme test subtheme');
- $this->assertIdentical($themes['test_basetheme']->sub_themes, $sub_theme_list, 'Base theme\'s object includes list of subthemes.');
- $this->assertIdentical($themes['test_subtheme']->base_themes, $base_theme_list, 'Subtheme\'s object includes list of base themes.');
- // Check for theme engine in subtheme.
- $this->assertIdentical($themes['test_subtheme']->engine, 'phptemplate', 'Subtheme\'s object includes the theme engine.');
- // Check for theme engine prefix.
- $this->assertIdentical($themes['test_basetheme']->prefix, 'phptemplate', 'Base theme\'s object includes the theme engine prefix.');
- $this->assertIdentical($themes['test_subtheme']->prefix, 'phptemplate', 'Subtheme\'s object includes the theme engine prefix.');
- }
-
- /**
- * Test the theme_get_setting() function.
- */
- function testThemeGetSetting() {
- $GLOBALS['theme_key'] = 'test_theme';
- $this->assertIdentical(theme_get_setting('theme_test_setting'), 'default value', 'theme_get_setting() uses the default theme automatically.');
- $this->assertNotEqual(theme_get_setting('subtheme_override', 'test_basetheme'), theme_get_setting('subtheme_override', 'test_subtheme'), 'Base theme\'s default settings values can be overridden by subtheme.');
- $this->assertIdentical(theme_get_setting('basetheme_only', 'test_subtheme'), 'base theme value', 'Base theme\'s default settings values are inherited by subtheme.');
- }
-}
-
-/**
- * Unit tests for theme_table().
- */
-class ThemeTableTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme Table',
- 'description' => 'Tests built-in theme functions.',
- 'group' => 'Theme',
- );
- }
-
- /**
- * Tableheader.js provides 'sticky' table headers, and is included by default.
- */
- function testThemeTableStickyHeaders() {
- $header = array('one', 'two', 'three');
- $rows = array(array(1,2,3), array(4,5,6), array(7,8,9));
- $this->content = theme('table', array('header' => $header, 'rows' => $rows));
- $js = drupal_add_js();
- $this->assertTrue(isset($js['misc/tableheader.js']), 'tableheader.js was included when $sticky = TRUE.');
- $this->assertRaw('sticky-enabled', 'Table has a class of sticky-enabled when $sticky = TRUE.');
- drupal_static_reset('drupal_add_js');
- }
-
- /**
- * If $sticky is FALSE, no tableheader.js should be included.
- */
- function testThemeTableNoStickyHeaders() {
- $header = array('one', 'two', 'three');
- $rows = array(array(1,2,3), array(4,5,6), array(7,8,9));
- $attributes = array();
- $caption = NULL;
- $colgroups = array();
- $this->content = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => $attributes, 'caption' => $caption, 'colgroups' => $colgroups, 'sticky' => FALSE));
- $js = drupal_add_js();
- $this->assertFalse(isset($js['misc/tableheader.js']), 'tableheader.js was not included because $sticky = FALSE.');
- $this->assertNoRaw('sticky-enabled', 'Table does not have a class of sticky-enabled because $sticky = FALSE.');
- drupal_static_reset('drupal_add_js');
- }
-
- /**
- * Tests that the table header is printed correctly even if there are no rows,
- * and that the empty text is displayed correctly.
- */
- function testThemeTableWithEmptyMessage() {
- $header = array(
- t('Header 1'),
- array(
- 'data' => t('Header 2'),
- 'colspan' => 2,
- ),
- );
- $this->content = theme('table', array('header' => $header, 'rows' => array(), 'empty' => t('No strings available.')));
- $this->assertRaw('No strings available. ', 'Correct colspan was set on empty message.');
- $this->assertRaw('Header 1 ', 'Table header was printed.');
- }
-
- /**
- * Tests that the 'no_striping' option works correctly.
- */
- function testThemeTableWithNoStriping() {
- $rows = array(
- array(
- 'data' => array(1),
- 'no_striping' => TRUE,
- ),
- );
- $this->content = theme('table', array('rows' => $rows));
- $this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.');
- $this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.');
- }
-}
-
-/**
- * Unit tests for theme_item_list().
- */
-class ThemeItemListUnitTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme item list',
- 'description' => 'Test the theme_item_list() function.',
- 'group' => 'Theme',
- );
- }
-
- /**
- * Test item list rendering.
- */
- function testItemList() {
- $items = array('a', array('data' => 'b', 'children' => array('c' => 'c', 'd' => 'd', 'e' => 'e')), 'f');
- $expected = '';
- $output = theme('item_list', array('items' => $items));
- $this->assertIdentical($expected, $output, 'Item list is rendered correctly.');
- }
-}
-
-/**
- * Unit tests for theme_links().
- */
-class ThemeLinksTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Links',
- 'description' => 'Test the theme_links() function and rendering groups of links.',
- 'group' => 'Theme',
- );
- }
-
- /**
- * Test the use of drupal_pre_render_links() on a nested array of links.
- */
- function testDrupalPreRenderLinks() {
- // Define the base array to be rendered, containing a variety of different
- // kinds of links.
- $base_array = array(
- '#theme' => 'links',
- '#pre_render' => array('drupal_pre_render_links'),
- '#links' => array(
- 'parent_link' => array(
- 'title' => 'Parent link original',
- 'href' => 'parent-link-original',
- ),
- ),
- 'first_child' => array(
- '#theme' => 'links',
- '#links' => array(
- // This should be rendered if 'first_child' is rendered separately,
- // but ignored if the parent is being rendered (since it duplicates
- // one of the parent's links).
- 'parent_link' => array(
- 'title' => 'Parent link copy',
- 'href' => 'parent-link-copy',
- ),
- // This should always be rendered.
- 'first_child_link' => array(
- 'title' => 'First child link',
- 'href' => 'first-child-link',
- ),
- ),
- ),
- // This should always be rendered as part of the parent.
- 'second_child' => array(
- '#theme' => 'links',
- '#links' => array(
- 'second_child_link' => array(
- 'title' => 'Second child link',
- 'href' => 'second-child-link',
- ),
- ),
- ),
- // This should never be rendered, since the user does not have access to
- // it.
- 'third_child' => array(
- '#theme' => 'links',
- '#links' => array(
- 'third_child_link' => array(
- 'title' => 'Third child link',
- 'href' => 'third-child-link',
- ),
- ),
- '#access' => FALSE,
- ),
- );
-
- // Start with a fresh copy of the base array, and try rendering the entire
- // thing. We expect a single with appropriate links contained within
- // it.
- $render_array = $base_array;
- $html = drupal_render($render_array);
- $dom = new DOMDocument();
- $dom->loadHTML($html);
- $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, 'One "ul" tag found in the rendered HTML.');
- $list_elements = $dom->getElementsByTagName('li');
- $this->assertEqual($list_elements->length, 3, 'Three "li" tags found in the rendered HTML.');
- $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link original', 'First expected link found.');
- $this->assertEqual($list_elements->item(1)->nodeValue, 'First child link', 'Second expected link found.');
- $this->assertEqual($list_elements->item(2)->nodeValue, 'Second child link', 'Third expected link found.');
- $this->assertIdentical(strpos($html, 'Parent link copy'), FALSE, '"Parent link copy" link not found.');
- $this->assertIdentical(strpos($html, 'Third child link'), FALSE, '"Third child link" link not found.');
-
- // Now render 'first_child', followed by the rest of the links, and make
- // sure we get two separate 's with the appropriate links contained
- // within each.
- $render_array = $base_array;
- $child_html = drupal_render($render_array['first_child']);
- $parent_html = drupal_render($render_array);
- // First check the child HTML.
- $dom = new DOMDocument();
- $dom->loadHTML($child_html);
- $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, 'One "ul" tag found in the rendered child HTML.');
- $list_elements = $dom->getElementsByTagName('li');
- $this->assertEqual($list_elements->length, 2, 'Two "li" tags found in the rendered child HTML.');
- $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link copy', 'First expected link found.');
- $this->assertEqual($list_elements->item(1)->nodeValue, 'First child link', 'Second expected link found.');
- // Then check the parent HTML.
- $dom = new DOMDocument();
- $dom->loadHTML($parent_html);
- $this->assertEqual($dom->getElementsByTagName('ul')->length, 1, 'One "ul" tag found in the rendered parent HTML.');
- $list_elements = $dom->getElementsByTagName('li');
- $this->assertEqual($list_elements->length, 2, 'Two "li" tags found in the rendered parent HTML.');
- $this->assertEqual($list_elements->item(0)->nodeValue, 'Parent link original', 'First expected link found.');
- $this->assertEqual($list_elements->item(1)->nodeValue, 'Second child link', 'Second expected link found.');
- $this->assertIdentical(strpos($parent_html, 'First child link'), FALSE, '"First child link" link not found.');
- $this->assertIdentical(strpos($parent_html, 'Third child link'), FALSE, '"Third child link" link not found.');
- }
-}
-
-/**
- * Functional test for initialization of the theme system in hook_init().
- */
-class ThemeHookInitTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme initialization in hook_init()',
- 'description' => 'Tests that the theme system can be correctly initialized in hook_init().',
- 'group' => 'Theme',
- );
- }
-
- function setUp() {
- parent::setUp('theme_test');
- }
-
- /**
- * Test that the theme system can generate output when called by hook_init().
- */
- function testThemeInitializationHookInit() {
- $this->drupalGet('theme-test/hook-init');
- $this->assertRaw('Themed output generated in hook_init()', 'Themed output generated in hook_init() correctly appears on the page.');
- $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page when the theme system is initialized in hook_init().");
- }
-}
-
-/**
- * Tests autocompletion not loading registry.
- */
-class ThemeFastTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme fast initialization',
- 'description' => 'Test that autocompletion does not load the registry.',
- 'group' => 'Theme'
- );
- }
-
- function setUp() {
- parent::setUp('theme_test');
- $this->account = $this->drupalCreateUser(array('access user profiles'));
- }
-
- /**
- * Tests access to user autocompletion and verify the correct results.
- */
- function testUserAutocomplete() {
- $this->drupalLogin($this->account);
- $this->drupalGet('user/autocomplete/' . $this->account->name);
- $this->assertText('registry not initialized', 'The registry was not initialized');
- }
-}
-
-/**
- * Unit tests for theme_html_tag().
- */
-class ThemeHtmlTag extends DrupalUnitTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme HTML Tag',
- 'description' => 'Tests theme_html_tag() built-in theme functions.',
- 'group' => 'Theme',
- );
- }
-
- /**
- * Test function theme_html_tag()
- */
- function testThemeHtmlTag() {
- // Test auto-closure meta tag generation
- $tag['element'] = array('#tag' => 'meta', '#attributes' => array('name' => 'description', 'content' => 'Drupal test'));
- $this->assertEqual(' '."\n", theme_html_tag($tag), 'Test auto-closure meta tag generation.');
-
- // Test title tag generation
- $tag['element'] = array('#tag' => 'title', '#value' => 'title test');
- $this->assertEqual('title test '."\n", theme_html_tag($tag), 'Test title tag generation.');
- }
-}
-
-/**
- * Tests for the ThemeRegistry class.
- */
-class ThemeRegistryTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'ThemeRegistry',
- 'description' => 'Tests the behavior of the ThemeRegistry class',
- 'group' => 'Theme',
- );
- }
- function setUp() {
- parent::setUp('theme_test');
- }
-
- /**
- * Tests the behavior of the theme registry class.
- */
- function testRaceCondition() {
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $cid = 'test_theme_registry';
-
- // Directly instantiate the theme registry, this will cause a base cache
- // entry to be written in __construct().
- $registry = new ThemeRegistry($cid, 'cache');
-
- $this->assertTrue(cache_get($cid), 'Cache entry was created.');
-
- // Trigger a cache miss for an offset.
- $this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry.');
- // This will cause the ThemeRegistry class to write an updated version of
- // the cache entry when it is destroyed, usually at the end of the request.
- // Before that happens, manually delete the cache entry we created earlier
- // so that the new entry is written from scratch.
- cache_clear_all($cid, 'cache');
-
- // Destroy the class so that it triggers a cache write for the offset.
- unset($registry);
-
- $this->assertTrue(cache_get($cid), 'Cache entry was created.');
-
- // Create a new instance of the class. Confirm that both the offset
- // requested previously, and one that has not yet been requested are both
- // available.
- $registry = new ThemeRegistry($cid, 'cache');
-
- $this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry');
- $this->assertTrue($registry['theme_test_template_test_2'], 'Offset was returned correctly from the theme registry');
- }
-}
diff --git a/modules/simpletest/tests/theme_test.inc b/modules/simpletest/tests/theme_test.inc
deleted file mode 100644
index 6cde6838..00000000
--- a/modules/simpletest/tests/theme_test.inc
+++ /dev/null
@@ -1,15 +0,0 @@
- 'theme_test.inc',
- 'variables' => array('foo' => ''),
- );
- $items['theme_test_template_test'] = array(
- 'template' => 'theme_test.template_test',
- );
- $items['theme_test_template_test_2'] = array(
- 'template' => 'theme_test.template_test',
- );
- $items['theme_test_foo'] = array(
- 'variables' => array('foo' => NULL),
- );
- return $items;
-}
-
-/**
- * Implements hook_system_theme_info().
- */
-function theme_test_system_theme_info() {
- $themes['test_theme'] = drupal_get_path('module', 'theme_test') . '/themes/test_theme/test_theme.info';
- $themes['test_basetheme'] = drupal_get_path('module', 'theme_test') . '/themes/test_basetheme/test_basetheme.info';
- $themes['test_subtheme'] = drupal_get_path('module', 'theme_test') . '/themes/test_subtheme/test_subtheme.info';
- return $themes;
-}
-
-/**
- * Implements hook_menu().
- */
-function theme_test_menu() {
- $items['theme-test/suggestion'] = array(
- 'title' => 'Suggestion',
- 'page callback' => '_theme_test_suggestion',
- 'access arguments' => array('access content'),
- 'theme callback' => '_theme_custom_theme',
- 'type' => MENU_CALLBACK,
- );
- $items['theme-test/alter'] = array(
- 'title' => 'Suggestion',
- 'page callback' => '_theme_test_alter',
- 'access arguments' => array('access content'),
- 'theme callback' => '_theme_custom_theme',
- 'type' => MENU_CALLBACK,
- );
- $items['theme-test/hook-init'] = array(
- 'page callback' => 'theme_test_hook_init_page_callback',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
- return $items;
-}
-
-/**
- * Implements hook_init().
- */
-function theme_test_init() {
- if (arg(0) == 'theme-test' && arg(1) == 'hook-init') {
- // First, force the theme registry to be rebuilt on this page request. This
- // allows us to test a full initialization of the theme system in the code
- // below.
- drupal_theme_rebuild();
- // Next, initialize the theme system by storing themed text in a global
- // variable. We will use this later in theme_test_hook_init_page_callback()
- // to test that even when the theme system is initialized this early, it is
- // still capable of returning output and theming the page as a whole.
- $GLOBALS['theme_test_output'] = theme('more_link', array('url' => 'user', 'title' => 'Themed output generated in hook_init()'));
- }
-}
-
-/**
- * Implements hook_exit().
- */
-function theme_test_exit() {
- if (arg(0) == 'user') {
- // Register a fake registry loading callback. If it gets called by
- // theme_get_registry(), the registry has not been initialized yet.
- _theme_registry_callback('_theme_test_load_registry', array());
- print theme_get_registry() ? 'registry initialized' : 'registry not initialized';
- }
-}
-
-/**
- * Fake registry loading callback.
- */
-function _theme_test_load_registry() {
- return array();
-}
-
-/**
- * Menu callback for testing themed output generated in hook_init().
- */
-function theme_test_hook_init_page_callback() {
- return $GLOBALS['theme_test_output'];
-}
-
-/**
- * Custom theme callback.
- */
-function _theme_custom_theme() {
- return 'test_theme';
-}
-
-/**
- * Page callback, calls drupal_alter().
- *
- * This is for testing that the theme can have hook_*_alter() implementations
- * that run during page callback execution, even before theme() is called for
- * the first time.
- */
-function _theme_test_alter() {
- $data = 'foo';
- drupal_alter('theme_test_alter', $data);
- return "The altered data is $data.";
-}
-
-/**
- * Page callback, calls a theme hook suggestion.
- */
-function _theme_test_suggestion() {
- return theme(array('theme_test__suggestion', 'theme_test'), array());
-}
-
-/**
- * Theme function for testing theme('theme_test_foo').
- */
-function theme_theme_test_foo($variables) {
- return $variables['foo'];
-}
diff --git a/modules/simpletest/tests/theme_test.template_test.tpl.php b/modules/simpletest/tests/theme_test.template_test.tpl.php
deleted file mode 100644
index cde8faad..00000000
--- a/modules/simpletest/tests/theme_test.template_test.tpl.php
+++ /dev/null
@@ -1,2 +0,0 @@
-
-Fail: Template not overridden.
diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
deleted file mode 100644
index 2af492c1..00000000
--- a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = Theme test base theme
-description = Test theme which acts as a base theme for other test subthemes.
-core = 7.x
-hidden = TRUE
-
-settings[basetheme_only] = base theme value
-settings[subtheme_override] = base theme value
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
deleted file mode 100644
index 641c4c74..00000000
--- a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = Theme test subtheme
-description = Test theme which uses test_basetheme as the base theme.
-core = 7.x
-base theme = test_basetheme
-hidden = TRUE
-
-settings[subtheme_override] = subtheme value
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/simpletest/tests/themes/test_theme/template.php b/modules/simpletest/tests/themes/test_theme/template.php
deleted file mode 100644
index 8275818e..00000000
--- a/modules/simpletest/tests/themes/test_theme/template.php
+++ /dev/null
@@ -1,19 +0,0 @@
- 'Unicode handling',
- 'description' => 'Tests Drupal Unicode handling.',
- 'group' => 'System',
- );
- }
-
- /**
- * Test full unicode features implemented using the mbstring extension.
- */
- function testMbStringUnicode() {
- global $multibyte;
-
- // mbstring was not detected on this installation, there is no way to test
- // multibyte features. Treat that as an exception.
- if ($multibyte == UNICODE_SINGLEBYTE) {
- $this->error(t('Unable to test Multibyte features: mbstring extension was not detected.'));
- }
-
- $multibyte = UNICODE_MULTIBYTE;
-
- $this->extendedMode = TRUE;
- $this->pass(t('Testing in mbstring mode'));
-
- $this->helperTestStrToLower();
- $this->helperTestStrToUpper();
- $this->helperTestUcFirst();
- $this->helperTestStrLen();
- $this->helperTestSubStr();
- $this->helperTestTruncate();
- }
-
- /**
- * Test emulated unicode features.
- */
- function testEmulatedUnicode() {
- global $multibyte;
-
- $multibyte = UNICODE_SINGLEBYTE;
-
- $this->extendedMode = FALSE;
-
- $this->pass(t('Testing in emulated (best-effort) mode'));
-
- $this->helperTestStrToLower();
- $this->helperTestStrToUpper();
- $this->helperTestUcFirst();
- $this->helperTestStrLen();
- $this->helperTestSubStr();
- $this->helperTestTruncate();
- }
-
- function helperTestStrToLower() {
- $testcase = array(
- 'tHe QUIcK bRoWn' => 'the quick brown',
- 'FrançAIS is ÜBER-åwesome' => 'français is über-åwesome',
- );
- if ($this->extendedMode) {
- $testcase['ΑΒΓΔΕΖΗΘΙΚΛΜÎΞΟΣὨ'] = 'αβγδεζηθικλμνξοσὠ';
- }
-
- foreach ($testcase as $input => $output) {
- $this->assertEqual(drupal_strtolower($input), $output, format_string('%input is lowercased as %output', array('%input' => $input, '%output' => $output)));
- }
- }
-
- function helperTestStrToUpper() {
- $testcase = array(
- 'tHe QUIcK bRoWn' => 'THE QUICK BROWN',
- 'FrançAIS is ÜBER-åwesome' => 'FRANÇAIS IS ÜBER-ÅWESOME',
- );
- if ($this->extendedMode) {
- $testcase['αβγδεζηθικλμνξοσὠ'] = 'ΑΒΓΔΕΖΗΘΙΚΛΜÎΞΟΣὨ';
- }
-
- foreach ($testcase as $input => $output) {
- $this->assertEqual(drupal_strtoupper($input), $output, format_string('%input is uppercased as %output', array('%input' => $input, '%output' => $output)));
- }
- }
-
- function helperTestUcFirst() {
- $testcase = array(
- 'tHe QUIcK bRoWn' => 'THe QUIcK bRoWn',
- 'françAIS' => 'FrançAIS',
- 'über' => 'Über',
- 'Ã¥wesome' => 'Ã…wesome'
- );
- if ($this->extendedMode) {
- $testcase['σion'] = 'Σion';
- }
-
- foreach ($testcase as $input => $output) {
- $this->assertEqual(drupal_ucfirst($input), $output, format_string('%input is ucfirst-ed as %output', array('%input' => $input, '%output' => $output)));
- }
- }
-
- function helperTestStrLen() {
- $testcase = array(
- 'tHe QUIcK bRoWn' => 15,
- 'ÜBER-åwesome' => 12,
- );
-
- foreach ($testcase as $input => $output) {
- $this->assertEqual(drupal_strlen($input), $output, format_string('%input length is %output', array('%input' => $input, '%output' => $output)));
- }
- }
-
- function helperTestSubStr() {
- $testcase = array(
- // 012345678901234567890123
- array('frà nçAIS is über-åwesome', 0, 0,
- ''),
- array('frà nçAIS is über-åwesome', 0, 1,
- 'f'),
- array('frà nçAIS is über-åwesome', 0, 8,
- 'frà nçAIS'),
- array('frà nçAIS is über-åwesome', 0, 23,
- 'frà nçAIS is über-åwesom'),
- array('frà nçAIS is über-åwesome', 0, 24,
- 'frà nçAIS is über-åwesome'),
- array('frà nçAIS is über-åwesome', 0, 25,
- 'frà nçAIS is über-åwesome'),
- array('frà nçAIS is über-åwesome', 0, 100,
- 'frà nçAIS is über-åwesome'),
- array('frà nçAIS is über-åwesome', 4, 4,
- 'çAIS'),
- array('frà nçAIS is über-åwesome', 1, 0,
- ''),
- array('frà nçAIS is über-åwesome', 100, 0,
- ''),
- array('frà nçAIS is über-åwesome', -4, 2,
- 'so'),
- array('frà nçAIS is über-åwesome', -4, 3,
- 'som'),
- array('frà nçAIS is über-åwesome', -4, 4,
- 'some'),
- array('frà nçAIS is über-åwesome', -4, 5,
- 'some'),
- array('frà nçAIS is über-åwesome', -7, 10,
- 'Ã¥wesome'),
- array('frà nçAIS is über-åwesome', 5, -10,
- 'AIS is üb'),
- array('frà nçAIS is über-åwesome', 0, -10,
- 'frà nçAIS is üb'),
- array('frà nçAIS is über-åwesome', 0, -1,
- 'frà nçAIS is über-åwesom'),
- array('frà nçAIS is über-åwesome', -7, -2,
- 'Ã¥weso'),
- array('frà nçAIS is über-åwesome', -7, -6,
- 'Ã¥'),
- array('frà nçAIS is über-åwesome', -7, -7,
- ''),
- array('frà nçAIS is über-åwesome', -7, -8,
- ''),
- array('...', 0, 2, '..'),
- array('以呂波耳・ã»ã¸ã¨ã¡ã€‚リヌルヲ。', 1, 3,
- '呂波耳'),
-
- );
-
- foreach ($testcase as $test) {
- list($input, $start, $length, $output) = $test;
- $result = drupal_substr($input, $start, $length);
- $this->assertEqual($result, $output, format_string('%input substring at offset %offset for %length characters is %output (got %result)', array('%input' => $input, '%offset' => $start, '%length' => $length, '%output' => $output, '%result' => $result)));
- }
- }
-
- /**
- * Test decode_entities().
- */
- function testDecodeEntities() {
- $testcase = array(
- 'Drupal' => 'Drupal',
- ' & < > " \' ';
- $title_filtered = check_plain($title);
-
- $slogan = '';
- $slogan_filtered = filter_xss_admin($slogan);
-
- // Activate needed appearance settings.
- $edit = array(
- 'toggle_name' => TRUE,
- 'toggle_slogan' => TRUE,
- 'toggle_main_menu' => TRUE,
- 'toggle_secondary_menu' => TRUE,
- );
- $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));
-
- // Set title and slogan.
- $edit = array(
- 'site_name' => $title,
- 'site_slogan' => $slogan,
- );
- $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
-
- // Load frontpage.
- $this->drupalGet('');
-
- // Test the title.
- $this->assertNoRaw($title, 'Check for the unfiltered version of the title.');
- // Adding so we do not test the escaped version from drupal_set_title().
- $this->assertRaw($title_filtered . '', 'Check for the filtered version of the title.');
-
- // Test the slogan.
- $this->assertNoRaw($slogan, 'Check for the unfiltered version of the slogan.');
- $this->assertRaw($slogan_filtered, 'Check for the filtered version of the slogan.');
- }
-}
-
-/**
- * Test front page functionality and administration.
- */
-class FrontPageTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Front page',
- 'description' => 'Tests front page functionality and administration.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp('system_test');
-
- // Create admin user, log in admin user, and create one node.
- $this->admin_user = $this->drupalCreateUser(array('access content', 'administer site configuration'));
- $this->drupalLogin($this->admin_user);
- $this->node_path = "node/" . $this->drupalCreateNode(array('promote' => 1))->nid;
-
- // Enable front page logging in system_test.module.
- variable_set('front_page_output', 1);
- }
-
- /**
- * Test front page functionality.
- */
- function testDrupalIsFrontPage() {
- $this->drupalGet('');
- $this->assertText(t('On front page.'), 'Path is the front page.');
- $this->drupalGet('node');
- $this->assertText(t('On front page.'), 'Path is the front page.');
- $this->drupalGet($this->node_path);
- $this->assertNoText(t('On front page.'), 'Path is not the front page.');
-
- // Change the front page to an invalid path.
- $edit = array('site_frontpage' => 'kittens');
- $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
- $this->assertText(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $edit['site_frontpage'])));
-
- // Change the front page to a valid path.
- $edit['site_frontpage'] = $this->node_path;
- $this->drupalPost('admin/config/system/site-information', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), 'The front page path has been saved.');
-
- $this->drupalGet('');
- $this->assertText(t('On front page.'), 'Path is the front page.');
- $this->drupalGet('node');
- $this->assertNoText(t('On front page.'), 'Path is not the front page.');
- $this->drupalGet($this->node_path);
- $this->assertText(t('On front page.'), 'Path is the front page.');
- }
-}
-
-class SystemBlockTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
- public static function getInfo() {
- return array(
- 'name' => 'Block functionality',
- 'description' => 'Configure and move powered-by block.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp('block');
-
- // Create and login user
- $admin_user = $this->drupalCreateUser(array('administer blocks', 'access administration pages'));
- $this->drupalLogin($admin_user);
- }
-
- /**
- * Test displaying and hiding the powered-by and help blocks.
- */
- function testSystemBlocks() {
- // Set block title and some settings to confirm that the interface is available.
- $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => $this->randomName(8)), t('Save block'));
- $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
-
- // Set the powered-by block to the footer region.
- $edit = array();
- $edit['blocks[system_powered-by][region]'] = 'footer';
- $edit['blocks[system_main][region]'] = 'content';
- $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
- $this->assertText(t('The block settings have been updated.'), t('Block successfully moved to footer region.'));
-
- // Confirm that the block is being displayed.
- $this->drupalGet('node');
- $this->assertRaw('id="block-system-powered-by"', t('Block successfully being displayed on the page.'));
-
- // Set the block to the disabled region.
- $edit = array();
- $edit['blocks[system_powered-by][region]'] = '-1';
- $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-
- // Confirm that the block is hidden.
- $this->assertNoRaw('id="block-system-powered-by"', t('Block no longer appears on page.'));
-
- // For convenience of developers, set the block to its default settings.
- $edit = array();
- $edit['blocks[system_powered-by][region]'] = 'footer';
- $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
- $this->drupalPost('admin/structure/block/manage/system/powered-by/configure', array('title' => ''), t('Save block'));
-
- // Set the help block to the help region.
- $edit = array();
- $edit['blocks[system_help][region]'] = 'help';
- $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-
- // Test displaying the help block with block caching enabled.
- variable_set('block_cache', TRUE);
- $this->drupalGet('admin/structure/block/add');
- $this->assertRaw(t('Use this page to create a new custom block.'));
- $this->drupalGet('admin/index');
- $this->assertRaw(t('This page shows you all available administration tasks for each module.'));
- }
-}
-
-/**
- * Test main content rendering fallback provided by system module.
- */
-class SystemMainContentFallback extends DrupalWebTestCase {
- protected $admin_user;
- protected $web_user;
-
- public static function getInfo() {
- return array(
- 'name' => 'Main content rendering fallback',
- 'description' => ' Test system module main content rendering fallback.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp('system_test');
-
- // Create and login admin user.
- $this->admin_user = $this->drupalCreateUser(array(
- 'access administration pages',
- 'administer site configuration',
- 'administer modules',
- 'administer blocks',
- 'administer nodes',
- ));
- $this->drupalLogin($this->admin_user);
-
- // Create a web user.
- $this->web_user = $this->drupalCreateUser(array('access user profiles', 'access content'));
- }
-
- /**
- * Test availability of main content.
- */
- function testMainContentFallback() {
- $edit = array();
- // Disable the dashboard module, which depends on the block module.
- $edit['modules[Core][dashboard][enable]'] = FALSE;
- $this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
- // Disable the block module.
- $edit['modules[Core][block][enable]'] = FALSE;
- $this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
- module_list(TRUE);
- $this->assertFalse(module_exists('block'), 'Block module disabled.');
-
- // At this point, no region is filled and fallback should be triggered.
- $this->drupalGet('admin/config/system/site-information');
- $this->assertField('site_name', 'Admin interface still available.');
-
- // Fallback should not trigger when another module is handling content.
- $this->drupalGet('system-test/main-content-handling');
- $this->assertRaw('id="system-test-content"', 'Content handled by another module');
- $this->assertText(t('Content to test main content fallback'), 'Main content still displayed.');
-
- // Fallback should trigger when another module
- // indicates that it is not handling the content.
- $this->drupalGet('system-test/main-content-fallback');
- $this->assertText(t('Content to test main content fallback'), 'Main content fallback properly triggers.');
-
- // Fallback should not trigger when another module is handling content.
- // Note that this test ensures that no duplicate
- // content gets created by the fallback.
- $this->drupalGet('system-test/main-content-duplication');
- $this->assertNoText(t('Content to test main content fallback'), 'Main content not duplicated.');
-
- // Request a user* page and see if it is displayed.
- $this->drupalLogin($this->web_user);
- $this->drupalGet('user/' . $this->web_user->uid . '/edit');
- $this->assertField('mail', 'User interface still available.');
-
- // Enable the block module again.
- $this->drupalLogin($this->admin_user);
- $edit = array();
- $edit['modules[Core][block][enable]'] = 'block';
- $this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
- module_list(TRUE);
- $this->assertTrue(module_exists('block'), 'Block module re-enabled.');
- }
-}
-
-/**
- * Tests for the theme interface functionality.
- */
-class SystemThemeFunctionalTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Theme interface functionality',
- 'description' => 'Tests the theme interface functionality by enabling and switching themes, and using an administration theme.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp();
-
- $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer themes', 'bypass node access', 'administer blocks'));
- $this->drupalLogin($this->admin_user);
- $this->node = $this->drupalCreateNode();
- }
-
- /**
- * Test the theme settings form.
- */
- function testThemeSettings() {
- // Specify a filesystem path to be used for the logo.
- $file = current($this->drupalGetTestFiles('image'));
- $file_relative = strtr($file->uri, array('public:/' => variable_get('file_public_path', conf_path() . '/files')));
- $default_theme_path = 'themes/stark';
-
- $supported_paths = array(
- // Raw stream wrapper URI.
- $file->uri => array(
- 'form' => file_uri_target($file->uri),
- 'src' => file_create_url($file->uri),
- ),
- // Relative path within the public filesystem.
- file_uri_target($file->uri) => array(
- 'form' => file_uri_target($file->uri),
- 'src' => file_create_url($file->uri),
- ),
- // Relative path to a public file.
- $file_relative => array(
- 'form' => $file_relative,
- 'src' => file_create_url($file->uri),
- ),
- // Relative path to an arbitrary file.
- 'misc/druplicon.png' => array(
- 'form' => 'misc/druplicon.png',
- 'src' => $GLOBALS['base_url'] . '/' . 'misc/druplicon.png',
- ),
- // Relative path to a file in a theme.
- $default_theme_path . '/logo.png' => array(
- 'form' => $default_theme_path . '/logo.png',
- 'src' => $GLOBALS['base_url'] . '/' . $default_theme_path . '/logo.png',
- ),
- );
- foreach ($supported_paths as $input => $expected) {
- $edit = array(
- 'default_logo' => FALSE,
- 'logo_path' => $input,
- );
- $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));
- $this->assertNoText('The custom logo path is invalid.');
- $this->assertFieldByName('logo_path', $expected['form']);
-
- // Verify the actual 'src' attribute of the logo being output.
- $this->drupalGet('');
- $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo'));
- $this->assertEqual((string) $elements[0]['src'], $expected['src']);
- }
-
- $unsupported_paths = array(
- // Stream wrapper URI to non-existing file.
- 'public://whatever.png',
- 'private://whatever.png',
- 'temporary://whatever.png',
- // Bogus stream wrapper URIs.
- 'public:/whatever.png',
- '://whatever.png',
- ':whatever.png',
- 'public://',
- // Relative path within the public filesystem to non-existing file.
- 'whatever.png',
- // Relative path to non-existing file in public filesystem.
- variable_get('file_public_path', conf_path() . '/files') . '/whatever.png',
- // Semi-absolute path to non-existing file in public filesystem.
- '/' . variable_get('file_public_path', conf_path() . '/files') . '/whatever.png',
- // Relative path to arbitrary non-existing file.
- 'misc/whatever.png',
- // Semi-absolute path to arbitrary non-existing file.
- '/misc/whatever.png',
- // Absolute paths to any local file (even if it exists).
- drupal_realpath($file->uri),
- );
- $this->drupalGet('admin/appearance/settings');
- foreach ($unsupported_paths as $path) {
- $edit = array(
- 'default_logo' => FALSE,
- 'logo_path' => $path,
- );
- $this->drupalPost(NULL, $edit, t('Save configuration'));
- $this->assertText('The custom logo path is invalid.');
- }
-
- // Upload a file to use for the logo.
- $edit = array(
- 'default_logo' => FALSE,
- 'logo_path' => '',
- 'files[logo_upload]' => drupal_realpath($file->uri),
- );
- $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'));
-
- $fields = $this->xpath($this->constructFieldXpath('name', 'logo_path'));
- $uploaded_filename = 'public://' . $fields[0]['value'];
-
- $this->drupalGet('');
- $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo'));
- $this->assertEqual($elements[0]['src'], file_create_url($uploaded_filename));
- }
-
- /**
- * Test the administration theme functionality.
- */
- function testAdministrationTheme() {
- theme_enable(array('stark'));
- variable_set('theme_default', 'stark');
- // Enable an administration theme and show it on the node admin pages.
- $edit = array(
- 'admin_theme' => 'seven',
- 'node_admin_theme' => TRUE,
- );
- $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
-
- $this->drupalGet('admin/config');
- $this->assertRaw('themes/seven', 'Administration theme used on an administration page.');
-
- $this->drupalGet('node/' . $this->node->nid);
- $this->assertRaw('themes/stark', 'Site default theme used on node page.');
-
- $this->drupalGet('node/add');
- $this->assertRaw('themes/seven', 'Administration theme used on the add content page.');
-
- $this->drupalGet('node/' . $this->node->nid . '/edit');
- $this->assertRaw('themes/seven', 'Administration theme used on the edit content page.');
-
- // Disable the admin theme on the node admin pages.
- $edit = array(
- 'node_admin_theme' => FALSE,
- );
- $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
-
- $this->drupalGet('admin/config');
- $this->assertRaw('themes/seven', 'Administration theme used on an administration page.');
-
- $this->drupalGet('node/add');
- $this->assertRaw('themes/stark', 'Site default theme used on the add content page.');
-
- // Reset to the default theme settings.
- variable_set('theme_default', 'bartik');
- $edit = array(
- 'admin_theme' => '0',
- 'node_admin_theme' => FALSE,
- );
- $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
-
- $this->drupalGet('admin');
- $this->assertRaw('themes/bartik', 'Site default theme used on administration page.');
-
- $this->drupalGet('node/add');
- $this->assertRaw('themes/bartik', 'Site default theme used on the add content page.');
- }
-
- /**
- * Test switching the default theme.
- */
- function testSwitchDefaultTheme() {
- // Enable "stark" and set it as the default theme.
- theme_enable(array('stark'));
- $this->drupalGet('admin/appearance');
- $this->clickLink(t('Set default'), 1);
- $this->assertTrue(variable_get('theme_default', '') == 'stark', 'Site default theme switched successfully.');
-
- // Test the default theme on the secondary links (blocks admin page).
- $this->drupalGet('admin/structure/block');
- $this->assertText('Stark(' . t('active tab') . ')', 'Default local task on blocks admin page is the default theme.');
- // Switch back to Bartik and test again to test that the menu cache is cleared.
- $this->drupalGet('admin/appearance');
- $this->clickLink(t('Set default'), 0);
- $this->drupalGet('admin/structure/block');
- $this->assertText('Bartik(' . t('active tab') . ')', 'Default local task on blocks admin page has changed.');
- }
-}
-
-
-/**
- * Test the basic queue functionality.
- */
-class QueueTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Queue functionality',
- 'description' => 'Queues and dequeues a set of items to check the basic queue functionality.',
- 'group' => 'System',
- );
- }
-
- /**
- * Queues and dequeues a set of items to check the basic queue functionality.
- */
- function testQueue() {
- // Create two queues.
- $queue1 = DrupalQueue::get($this->randomName());
- $queue1->createQueue();
- $queue2 = DrupalQueue::get($this->randomName());
- $queue2->createQueue();
-
- // Create four items.
- $data = array();
- for ($i = 0; $i < 4; $i++) {
- $data[] = array($this->randomName() => $this->randomName());
- }
-
- // Queue items 1 and 2 in the queue1.
- $queue1->createItem($data[0]);
- $queue1->createItem($data[1]);
-
- // Retrieve two items from queue1.
- $items = array();
- $new_items = array();
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- // First two dequeued items should match the first two items we queued.
- $this->assertEqual($this->queueScore($data, $new_items), 2, 'Two items matched');
-
- // Add two more items.
- $queue1->createItem($data[2]);
- $queue1->createItem($data[3]);
-
- $this->assertTrue($queue1->numberOfItems(), 'Queue 1 is not empty after adding items.');
- $this->assertFalse($queue2->numberOfItems(), 'Queue 2 is empty while Queue 1 has items');
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- $items[] = $item = $queue1->claimItem();
- $new_items[] = $item->data;
-
- // All dequeued items should match the items we queued exactly once,
- // therefore the score must be exactly 4.
- $this->assertEqual($this->queueScore($data, $new_items), 4, 'Four items matched');
-
- // There should be no duplicate items.
- $this->assertEqual($this->queueScore($new_items, $new_items), 4, 'Four items matched');
-
- // Delete all items from queue1.
- foreach ($items as $item) {
- $queue1->deleteItem($item);
- }
-
- // Check that both queues are empty.
- $this->assertFalse($queue1->numberOfItems(), 'Queue 1 is empty');
- $this->assertFalse($queue2->numberOfItems(), 'Queue 2 is empty');
- }
-
- /**
- * This function returns the number of equal items in two arrays.
- */
- function queueScore($items, $new_items) {
- $score = 0;
- foreach ($items as $item) {
- foreach ($new_items as $new_item) {
- if ($item === $new_item) {
- $score++;
- }
- }
- }
- return $score;
- }
-}
-
-/**
- * Test token replacement in strings.
- */
-class TokenReplaceTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Token replacement',
- 'description' => 'Generates text using placeholders for dummy content to check token replacement.',
- 'group' => 'System',
- );
- }
-
- /**
- * Creates a user and a node, then tests the tokens generated from them.
- */
- function testTokenReplacement() {
- // Create the initial objects.
- $account = $this->drupalCreateUser();
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
- $node->title = 'Blinking Text ';
- global $user, $language;
-
- $source = '[node:title]'; // Title of the node we passed in
- $source .= '[node:author:name]'; // Node author's name
- $source .= '[node:created:since]'; // Time since the node was created
- $source .= '[current-user:name]'; // Current user's name
- $source .= '[date:short]'; // Short date format of REQUEST_TIME
- $source .= '[user:name]'; // No user passed in, should be untouched
- $source .= '[bogus:token]'; // Non-existent token
-
- $target = check_plain($node->title);
- $target .= check_plain($account->name);
- $target .= format_interval(REQUEST_TIME - $node->created, 2, $language->language);
- $target .= check_plain($user->name);
- $target .= format_date(REQUEST_TIME, 'short', '', NULL, $language->language);
-
- // Test that the clear parameter cleans out non-existent tokens.
- $result = token_replace($source, array('node' => $node), array('language' => $language, 'clear' => TRUE));
- $result = $this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens cleared out.');
-
- // Test without using the clear parameter (non-existent token untouched).
- $target .= '[user:name]';
- $target .= '[bogus:token]';
- $result = token_replace($source, array('node' => $node), array('language' => $language));
- $this->assertEqual($target, $result, 'Valid tokens replaced while invalid tokens ignored.');
-
- // Check that the results of token_generate are sanitized properly. This does NOT
- // test the cleanliness of every token -- just that the $sanitize flag is being
- // passed properly through the call stack and being handled correctly by a 'known'
- // token, [node:title].
- $raw_tokens = array('title' => '[node:title]');
- $generated = token_generate('node', $raw_tokens, array('node' => $node));
- $this->assertEqual($generated['[node:title]'], check_plain($node->title), 'Token sanitized.');
-
- $generated = token_generate('node', $raw_tokens, array('node' => $node), array('sanitize' => FALSE));
- $this->assertEqual($generated['[node:title]'], $node->title, 'Unsanitized token generated properly.');
-
- // Test token replacement when the string contains no tokens.
- $this->assertEqual(token_replace('No tokens here.'), 'No tokens here.');
- }
-
- /**
- * Test whether token-replacement works in various contexts.
- */
- function testSystemTokenRecognition() {
- global $language;
-
- // Generate prefixes and suffixes for the token context.
- $tests = array(
- array('prefix' => 'this is the ', 'suffix' => ' site'),
- array('prefix' => 'this is the', 'suffix' => 'site'),
- array('prefix' => '[', 'suffix' => ']'),
- array('prefix' => '', 'suffix' => ']]]'),
- array('prefix' => '[[[', 'suffix' => ''),
- array('prefix' => ':[:', 'suffix' => '--]'),
- array('prefix' => '-[-', 'suffix' => ':]:'),
- array('prefix' => '[:', 'suffix' => ']'),
- array('prefix' => '[site:', 'suffix' => ':name]'),
- array('prefix' => '[site:', 'suffix' => ']'),
- );
-
- // Check if the token is recognized in each of the contexts.
- foreach ($tests as $test) {
- $input = $test['prefix'] . '[site:name]' . $test['suffix'];
- $expected = $test['prefix'] . 'Drupal' . $test['suffix'];
- $output = token_replace($input, array(), array('language' => $language));
- $this->assertTrue($output == $expected, format_string('Token recognized in string %string', array('%string' => $input)));
- }
- }
-
- /**
- * Tests the generation of all system site information tokens.
- */
- function testSystemSiteTokenReplacement() {
- global $language;
- $url_options = array(
- 'absolute' => TRUE,
- 'language' => $language,
- );
-
- // Set a few site variables.
- variable_set('site_name', 'Drupal');
- variable_set('site_slogan', 'Slogan ');
-
- // Generate and test sanitized tokens.
- $tests = array();
- $tests['[site:name]'] = check_plain(variable_get('site_name', 'Drupal'));
- $tests['[site:slogan]'] = check_plain(variable_get('site_slogan', ''));
- $tests['[site:mail]'] = 'simpletest@example.com';
- $tests['[site:url]'] = url('', $url_options);
- $tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', url('', $url_options));
- $tests['[site:login-url]'] = url('user', $url_options);
-
- // Test to make sure that we generated something for each token.
- $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array(), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Sanitized system site information token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test unsanitized tokens.
- $tests['[site:name]'] = variable_get('site_name', 'Drupal');
- $tests['[site:slogan]'] = variable_get('site_slogan', '');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array(), array('language' => $language, 'sanitize' => FALSE));
- $this->assertEqual($output, $expected, format_string('Unsanitized system site information token %token replaced.', array('%token' => $input)));
- }
- }
-
- /**
- * Tests the generation of all system date tokens.
- */
- function testSystemDateTokenReplacement() {
- global $language;
-
- // Set time to one hour before request.
- $date = REQUEST_TIME - 3600;
-
- // Generate and test tokens.
- $tests = array();
- $tests['[date:short]'] = format_date($date, 'short', '', NULL, $language->language);
- $tests['[date:medium]'] = format_date($date, 'medium', '', NULL, $language->language);
- $tests['[date:long]'] = format_date($date, 'long', '', NULL, $language->language);
- $tests['[date:custom:m/j/Y]'] = format_date($date, 'custom', 'm/j/Y', NULL, $language->language);
- $tests['[date:since]'] = format_interval((REQUEST_TIME - $date), 2, $language->language);
- $tests['[date:raw]'] = filter_xss($date);
-
- // Test to make sure that we generated something for each token.
- $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('date' => $date), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Date token %token replaced.', array('%token' => $input)));
- }
- }
-}
-
-class InfoFileParserTestCase extends DrupalUnitTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Info file format parser',
- 'description' => 'Tests proper parsing of a .info file formatted string.',
- 'group' => 'System',
- );
- }
-
- /**
- * Test drupal_parse_info_format().
- */
- function testDrupalParseInfoFormat() {
- $config = '
-simple = Value
-quoted = " Value"
-multiline = "Value
- Value"
-array[] = Value1
-array[] = Value2
-array_assoc[a] = Value1
-array_assoc[b] = Value2
-array_deep[][][] = Value
-array_deep_assoc[a][b][c] = Value
-array_space[a b] = Value';
-
- $expected = array(
- 'simple' => 'Value',
- 'quoted' => ' Value',
- 'multiline' => "Value\n Value",
- 'array' => array(
- 0 => 'Value1',
- 1 => 'Value2',
- ),
- 'array_assoc' => array(
- 'a' => 'Value1',
- 'b' => 'Value2',
- ),
- 'array_deep' => array(
- 0 => array(
- 0 => array(
- 0 => 'Value',
- ),
- ),
- ),
- 'array_deep_assoc' => array(
- 'a' => array(
- 'b' => array(
- 'c' => 'Value',
- ),
- ),
- ),
- 'array_space' => array(
- 'a b' => 'Value',
- ),
- );
-
- $parsed = drupal_parse_info_format($config);
-
- $this->assertEqual($parsed['simple'], $expected['simple'], 'Set a simple value.');
- $this->assertEqual($parsed['quoted'], $expected['quoted'], 'Set a simple value in quotes.');
- $this->assertEqual($parsed['multiline'], $expected['multiline'], 'Set a multiline value.');
- $this->assertEqual($parsed['array'], $expected['array'], 'Set a simple array.');
- $this->assertEqual($parsed['array_assoc'], $expected['array_assoc'], 'Set an associative array.');
- $this->assertEqual($parsed['array_deep'], $expected['array_deep'], 'Set a nested array.');
- $this->assertEqual($parsed['array_deep_assoc'], $expected['array_deep_assoc'], 'Set a nested associative array.');
- $this->assertEqual($parsed['array_space'], $expected['array_space'], 'Set an array with a whitespace in the key.');
- $this->assertEqual($parsed, $expected, 'Entire parsed .info string and expected array are identical.');
- }
-}
-
-/**
- * Tests the effectiveness of hook_system_info_alter().
- */
-class SystemInfoAlterTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'System info alter',
- 'description' => 'Tests the effectiveness of hook_system_info_alter().',
- 'group' => 'System',
- );
- }
-
- /**
- * Tests that {system}.info is rebuilt after a module that implements
- * hook_system_info_alter() is enabled. Also tests if core *_list() functions
- * return freshly altered info.
- */
- function testSystemInfoAlter() {
- // Enable our test module. Flush all caches, which we assert is the only
- // thing necessary to use the rebuilt {system}.info.
- module_enable(array('module_test'), FALSE);
- drupal_flush_all_caches();
- $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
-
- $info = $this->getSystemInfo('seven', 'theme');
- $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was added to {system}.info.');
- $seven_regions = system_region_list('seven');
- $this->assertTrue(isset($seven_regions['test_region']), 'Altered theme info was returned by system_region_list().');
- $system_list_themes = system_list('theme');
- $info = $system_list_themes['seven']->info;
- $this->assertTrue(isset($info['regions']['test_region']), 'Altered theme info was returned by system_list().');
- $list_themes = list_themes();
- $this->assertTrue(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was returned by list_themes().');
-
- // Disable the module and verify that {system}.info is rebuilt without it.
- module_disable(array('module_test'), FALSE);
- drupal_flush_all_caches();
- $this->assertFalse(module_exists('module_test'), 'Test module is disabled.');
-
- $info = $this->getSystemInfo('seven', 'theme');
- $this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was removed from {system}.info.');
- $seven_regions = system_region_list('seven');
- $this->assertFalse(isset($seven_regions['test_region']), 'Altered theme info was not returned by system_region_list().');
- $system_list_themes = system_list('theme');
- $info = $system_list_themes['seven']->info;
- $this->assertFalse(isset($info['regions']['test_region']), 'Altered theme info was not returned by system_list().');
- $list_themes = list_themes();
- $this->assertFalse(isset($list_themes['seven']->info['regions']['test_region']), 'Altered theme info was not returned by list_themes().');
- }
-
- /**
- * Returns the info array as it is stored in {system}.
- *
- * @param $name
- * The name of the record in {system}.
- * @param $type
- * The type of record in {system}.
- *
- * @return
- * Array of info, or FALSE if the record is not found.
- */
- function getSystemInfo($name, $type) {
- $raw_info = db_query("SELECT info FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
- return $raw_info ? unserialize($raw_info) : FALSE;
- }
-}
-
-/**
- * Tests for the update system functionality.
- */
-class UpdateScriptFunctionalTest extends DrupalWebTestCase {
- private $update_url;
- private $update_user;
-
- public static function getInfo() {
- return array(
- 'name' => 'Update functionality',
- 'description' => 'Tests the update script access and functionality.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp('update_script_test');
- $this->update_url = $GLOBALS['base_url'] . '/update.php';
- $this->update_user = $this->drupalCreateUser(array('administer software updates'));
- }
-
- /**
- * Tests access to the update script.
- */
- function testUpdateAccess() {
- // Try accessing update.php without the proper permission.
- $regular_user = $this->drupalCreateUser();
- $this->drupalLogin($regular_user);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertResponse(403);
-
- // Try accessing update.php as an anonymous user.
- $this->drupalLogout();
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertResponse(403);
-
- // Access the update page with the proper permission.
- $this->drupalLogin($this->update_user);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertResponse(200);
-
- // Access the update page as user 1.
- $user1 = user_load(1);
- $user1->pass_raw = user_password();
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- $user1->pass = user_hash_password(trim($user1->pass_raw));
- db_query("UPDATE {users} SET pass = :pass WHERE uid = :uid", array(':pass' => $user1->pass, ':uid' => $user1->uid));
- $this->drupalLogin($user1);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertResponse(200);
- }
-
- /**
- * Tests that requirements warnings and errors are correctly displayed.
- */
- function testRequirements() {
- $this->drupalLogin($this->update_user);
-
- // If there are no requirements warnings or errors, we expect to be able to
- // go through the update process uninterrupted.
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->drupalPost(NULL, array(), t('Continue'));
- $this->assertText(t('No pending updates.'), 'End of update process was reached.');
- // Confirm that all caches were cleared.
- $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared when there were no requirements warnings or errors.');
-
- // If there is a requirements warning, we expect it to be initially
- // displayed, but clicking the link to proceed should allow us to go
- // through the rest of the update process uninterrupted.
-
- // First, run this test with pending updates to make sure they can be run
- // successfully.
- variable_set('update_script_test_requirement_type', REQUIREMENT_WARNING);
- drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertText('This is a requirements warning provided by the update_script_test module.');
- $this->clickLink('try again');
- $this->assertNoText('This is a requirements warning provided by the update_script_test module.');
- $this->drupalPost(NULL, array(), t('Continue'));
- $this->drupalPost(NULL, array(), t('Apply pending updates'));
- $this->assertText(t('The update_script_test_update_7000() update was executed successfully.'), 'End of update process was reached.');
- // Confirm that all caches were cleared.
- $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared after resolving a requirements warning and applying updates.');
-
- // Now try again without pending updates to make sure that works too.
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertText('This is a requirements warning provided by the update_script_test module.');
- $this->clickLink('try again');
- $this->assertNoText('This is a requirements warning provided by the update_script_test module.');
- $this->drupalPost(NULL, array(), t('Continue'));
- $this->assertText(t('No pending updates.'), 'End of update process was reached.');
- // Confirm that all caches were cleared.
- $this->assertText(t('hook_flush_caches() invoked for update_script_test.module.'), 'Caches were cleared after applying updates and re-running the script.');
-
- // If there is a requirements error, it should be displayed even after
- // clicking the link to proceed (since the problem that triggered the error
- // has not been fixed).
- variable_set('update_script_test_requirement_type', REQUIREMENT_ERROR);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $this->assertText('This is a requirements error provided by the update_script_test module.');
- $this->clickLink('try again');
- $this->assertText('This is a requirements error provided by the update_script_test module.');
- }
-
- /**
- * Tests the effect of using the update script on the theme system.
- */
- function testThemeSystem() {
- // Since visiting update.php triggers a rebuild of the theme system from an
- // unusual maintenance mode environment, we check that this rebuild did not
- // put any incorrect information about the themes into the database.
- $original_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll();
- $this->drupalLogin($this->update_user);
- $this->drupalGet($this->update_url, array('external' => TRUE));
- $final_theme_data = db_query("SELECT * FROM {system} WHERE type = 'theme' ORDER BY name")->fetchAll();
- $this->assertEqual($original_theme_data, $final_theme_data, 'Visiting update.php does not alter the information about themes stored in the database.');
- }
-
- /**
- * Tests update.php when there are no updates to apply.
- */
- function testNoUpdateFunctionality() {
- // Click through update.php with 'administer software updates' permission.
- $this->drupalLogin($this->update_user);
- $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE));
- $this->assertText(t('No pending updates.'));
- $this->assertNoLink('Administration pages');
- $this->clickLink('Front page');
- $this->assertResponse(200);
-
- // Click through update.php with 'access administration pages' permission.
- $admin_user = $this->drupalCreateUser(array('administer software updates', 'access administration pages'));
- $this->drupalLogin($admin_user);
- $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE));
- $this->assertText(t('No pending updates.'));
- $this->clickLink('Administration pages');
- $this->assertResponse(200);
- }
-
- /**
- * Tests update.php after performing a successful update.
- */
- function testSuccessfulUpdateFunctionality() {
- drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1);
- // Click through update.php with 'administer software updates' permission.
- $this->drupalLogin($this->update_user);
- $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE));
- $this->drupalPost(NULL, array(), t('Apply pending updates'));
- $this->assertText('Updates were attempted.');
- $this->assertLink('site');
- $this->assertNoLink('Administration pages');
- $this->assertNoLink('logged');
- $this->clickLink('Front page');
- $this->assertResponse(200);
-
- drupal_set_installed_schema_version('update_script_test', drupal_get_installed_schema_version('update_script_test') - 1);
- // Click through update.php with 'access administration pages' and
- // 'access site reports' permissions.
- $admin_user = $this->drupalCreateUser(array('administer software updates', 'access administration pages', 'access site reports'));
- $this->drupalLogin($admin_user);
- $this->drupalPost($this->update_url, array(), t('Continue'), array('external' => TRUE));
- $this->drupalPost(NULL, array(), t('Apply pending updates'));
- $this->assertText('Updates were attempted.');
- $this->assertLink('logged');
- $this->clickLink('Administration pages');
- $this->assertResponse(200);
- }
-}
-
-/**
- * Functional tests for the flood control mechanism.
- */
-class FloodFunctionalTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Flood control mechanism',
- 'description' => 'Functional tests for the flood control mechanism.',
- 'group' => 'System',
- );
- }
-
- /**
- * Test flood control mechanism clean-up.
- */
- function testCleanUp() {
- $threshold = 1;
- $window_expired = -1;
- $name = 'flood_test_cleanup';
-
- // Register expired event.
- flood_register_event($name, $window_expired);
- // Verify event is not allowed.
- $this->assertFalse(flood_is_allowed($name, $threshold));
- // Run cron and verify event is now allowed.
- $this->cronRun();
- $this->assertTrue(flood_is_allowed($name, $threshold));
-
- // Register unexpired event.
- flood_register_event($name);
- // Verify event is not allowed.
- $this->assertFalse(flood_is_allowed($name, $threshold));
- // Run cron and verify event is still not allowed.
- $this->cronRun();
- $this->assertFalse(flood_is_allowed($name, $threshold));
- }
-}
-
-/**
- * Test HTTP file downloading capability.
- */
-class RetrieveFileTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'HTTP file retrieval',
- 'description' => 'Checks HTTP file fetching and error handling.',
- 'group' => 'System',
- );
- }
-
- /**
- * Invokes system_retrieve_file() in several scenarios.
- */
- function testFileRetrieving() {
- // Test 404 handling by trying to fetch a randomly named file.
- drupal_mkdir($sourcedir = 'public://' . $this->randomName());
- $filename = 'Файл Ð´Ð»Ñ Ñ‚ÐµÑÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ ' . $this->randomName();
- $url = file_create_url($sourcedir . '/' . $filename);
- $retrieved_file = system_retrieve_file($url);
- $this->assertFalse($retrieved_file, 'Non-existent file not fetched.');
-
- // Actually create that file, download it via HTTP and test the returned path.
- file_put_contents($sourcedir . '/' . $filename, 'testing');
- $retrieved_file = system_retrieve_file($url);
-
- // URLs could not contains characters outside the ASCII set so $filename
- // has to be encoded.
- $encoded_filename = rawurlencode($filename);
-
- $this->assertEqual($retrieved_file, 'public://' . $encoded_filename, 'Sane path for downloaded file returned (public:// scheme).');
- $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (public:// scheme).');
- $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (public:// scheme).');
- file_unmanaged_delete($retrieved_file);
-
- // Test downloading file to a different location.
- drupal_mkdir($targetdir = 'temporary://' . $this->randomName());
- $retrieved_file = system_retrieve_file($url, $targetdir);
- $this->assertEqual($retrieved_file, "$targetdir/$encoded_filename", 'Sane path for downloaded file returned (temporary:// scheme).');
- $this->assertTrue(is_file($retrieved_file), 'Downloaded file does exist (temporary:// scheme).');
- $this->assertEqual(filesize($retrieved_file), 7, 'File size of downloaded file is correct (temporary:// scheme).');
- file_unmanaged_delete($retrieved_file);
-
- file_unmanaged_delete_recursive($sourcedir);
- file_unmanaged_delete_recursive($targetdir);
- }
-}
-
-/**
- * Functional tests shutdown functions.
- */
-class ShutdownFunctionsTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Shutdown functions',
- 'description' => 'Functional tests for shutdown functions',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp('system_test');
- }
-
- /**
- * Test shutdown functions.
- */
- function testShutdownFunctions() {
- $arg1 = $this->randomName();
- $arg2 = $this->randomName();
- $this->drupalGet('system-test/shutdown-functions/' . $arg1 . '/' . $arg2);
- $this->assertText(t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)));
- $this->assertText(t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)));
-
- // Make sure exceptions displayed through _drupal_render_exception_safe()
- // are correctly escaped.
- $this->assertRaw('Drupal is <blink>awesome</blink>.');
- }
-}
-
-/**
- * Tests administrative overview pages.
- */
-class SystemAdminTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Administrative pages',
- 'description' => 'Tests output on administrative pages and compact mode functionality.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- // testAdminPages() requires Locale module.
- parent::setUp(array('locale'));
-
- // Create an administrator with all permissions, as well as a regular user
- // who can only access administration pages and perform some Locale module
- // administrative tasks, but not all of them.
- $this->admin_user = $this->drupalCreateUser(array_keys(module_invoke_all('permission')));
- $this->web_user = $this->drupalCreateUser(array(
- 'access administration pages',
- 'translate interface',
- ));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Tests output on administrative listing pages.
- */
- function testAdminPages() {
- // Go to Administration.
- $this->drupalGet('admin');
-
- // Verify that all visible, top-level administration links are listed on
- // the main administration page.
- foreach (menu_get_router() as $path => $item) {
- if (strpos($path, 'admin/') === 0 && ($item['type'] & MENU_VISIBLE_IN_TREE) && $item['_number_parts'] == 2) {
- $this->assertLink($item['title']);
- $this->assertLinkByHref($path);
- $this->assertText($item['description']);
- }
- }
-
- // For each administrative listing page on which the Locale module appears,
- // verify that there are links to the module's primary configuration pages,
- // but no links to its individual sub-configuration pages. Also verify that
- // a user with access to only some Locale module administration pages only
- // sees links to the pages they have access to.
- $admin_list_pages = array(
- 'admin/index',
- 'admin/config',
- 'admin/config/regional',
- );
-
- foreach ($admin_list_pages as $page) {
- // For the administrator, verify that there are links to Locale's primary
- // configuration pages, but no links to individual sub-configuration
- // pages.
- $this->drupalLogin($this->admin_user);
- $this->drupalGet($page);
- $this->assertLinkByHref('admin/config');
- $this->assertLinkByHref('admin/config/regional/settings');
- $this->assertLinkByHref('admin/config/regional/date-time');
- $this->assertLinkByHref('admin/config/regional/language');
- $this->assertNoLinkByHref('admin/config/regional/language/configure/session');
- $this->assertNoLinkByHref('admin/config/regional/language/configure/url');
- $this->assertLinkByHref('admin/config/regional/translate');
- // On admin/index only, the administrator should also see a "Configure
- // permissions" link for the Locale module.
- if ($page == 'admin/index') {
- $this->assertLinkByHref("admin/people/permissions#module-locale");
- }
-
- // For a less privileged user, verify that there are no links to Locale's
- // primary configuration pages, but a link to the translate page exists.
- $this->drupalLogin($this->web_user);
- $this->drupalGet($page);
- $this->assertLinkByHref('admin/config');
- $this->assertNoLinkByHref('admin/config/regional/settings');
- $this->assertNoLinkByHref('admin/config/regional/date-time');
- $this->assertNoLinkByHref('admin/config/regional/language');
- $this->assertNoLinkByHref('admin/config/regional/language/configure/session');
- $this->assertNoLinkByHref('admin/config/regional/language/configure/url');
- $this->assertLinkByHref('admin/config/regional/translate');
- // This user cannot configure permissions, so even on admin/index should
- // not see a "Configure permissions" link for the Locale module.
- if ($page == 'admin/index') {
- $this->assertNoLinkByHref("admin/people/permissions#module-locale");
- }
- }
- }
-
- /**
- * Test compact mode.
- */
- function testCompactMode() {
- $this->drupalGet('admin/compact/on');
- $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode turns on.');
- $this->drupalGet('admin/compact/on');
- $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode remains on after a repeat call.');
- $this->drupalGet('');
- $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.');
-
- $this->drupalGet('admin/compact/off');
- $this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode turns off.');
- $this->drupalGet('admin/compact/off');
- $this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode remains off after a repeat call.');
- $this->drupalGet('');
- $this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.');
- }
-}
-
-/**
- * Tests authorize.php and related hooks.
- */
-class SystemAuthorizeCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Authorize API',
- 'description' => 'Tests the authorize.php script and related API.',
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp(array('system_test'));
-
- variable_set('allow_authorize_operations', TRUE);
-
- // Create an administrator user.
- $this->admin_user = $this->drupalCreateUser(array('administer software updates'));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Helper function to initialize authorize.php and load it via drupalGet().
- *
- * Initializing authorize.php needs to happen in the child Drupal
- * installation, not the parent. So, we visit a menu callback provided by
- * system_test.module which calls system_authorized_init() to initialize the
- * $_SESSION inside the test site, not the framework site. This callback
- * redirects to authorize.php when it's done initializing.
- *
- * @see system_authorized_init().
- */
- function drupalGetAuthorizePHP($page_title = 'system-test-auth') {
- $this->drupalGet('system-test/authorize-init/' . $page_title);
- }
-
- /**
- * Tests the FileTransfer hooks
- */
- function testFileTransferHooks() {
- $page_title = $this->randomName(16);
- $this->drupalGetAuthorizePHP($page_title);
- $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)), 'authorize.php page title is correct.');
- $this->assertNoText('It appears you have reached this page in error.');
- $this->assertText('To continue, provide your server connection details');
- // Make sure we see the new connection method added by system_test.
- $this->assertRaw('System Test FileTransfer');
- // Make sure the settings form callback works.
- $this->assertText('System Test Username');
- }
-}
-
-/**
- * Test the handling of requests containing 'index.php'.
- */
-class SystemIndexPhpTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Index.php handling',
- 'description' => "Test the handling of requests containing 'index.php'.",
- 'group' => 'System',
- );
- }
-
- function setUp() {
- parent::setUp();
- }
-
- /**
- * Test index.php handling.
- */
- function testIndexPhpHandling() {
- $index_php = $GLOBALS['base_url'] . '/index.php';
-
- $this->drupalGet($index_php, array('external' => TRUE));
- $this->assertResponse(200, 'Make sure index.php returns a valid page.');
-
- $this->drupalGet($index_php, array('external' => TRUE, 'query' => array('q' => 'user')));
- $this->assertResponse(200, 'Make sure index.php?q=user returns a valid page.');
-
- $this->drupalGet($index_php .'/user', array('external' => TRUE));
- $this->assertResponse(404, "Make sure index.php/user returns a 'page not found'.");
- }
-}
-
-/**
- * Test token replacement in strings.
- */
-class TokenScanTest extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Token scanning',
- 'description' => 'Scan token-like patterns in a dummy text to check token scanning.',
- 'group' => 'System',
- );
- }
-
- /**
- * Scans dummy text, then tests the output.
- */
- function testTokenScan() {
- // Define text with valid and not valid, fake and existing token-like
- // strings.
- $text = 'First a [valid:simple], but dummy token, and a dummy [valid:token with: spaces].';
- $text .= 'Then a [not valid:token].';
- $text .= 'Last an existing token: [node:author:name].';
- $token_wannabes = token_scan($text);
-
- $this->assertTrue(isset($token_wannabes['valid']['simple']), 'A simple valid token has been matched.');
- $this->assertTrue(isset($token_wannabes['valid']['token with: spaces']), 'A valid token with space characters in the token name has been matched.');
- $this->assertFalse(isset($token_wannabes['not valid']), 'An invalid token with spaces in the token type has not been matched.');
- $this->assertTrue(isset($token_wannabes['node']), 'An existing valid token has been matched.');
- }
-}
-
-/**
- * Test case for drupal_valid_token().
- */
-class SystemValidTokenTest extends DrupalUnitTestCase {
-
- /**
- * Flag to indicate whether PHP error reportings should be asserted.
- *
- * @var bool
- */
- protected $assertErrors = TRUE;
-
- public static function getInfo() {
- return array(
- 'name' => 'Token validation',
- 'description' => 'Test the security token validation.',
- 'group' => 'System',
- );
- }
-
- /**
- * Tests invalid invocations of drupal_valid_token() that must return FALSE.
- */
- public function testTokenValidation() {
- // The following checks will throw PHP notices, so we disable error
- // assertions.
- $this->assertErrors = FALSE;
- $this->assertFalse(drupal_valid_token(NULL, new stdClass()), 'Token NULL, value object returns FALSE.');
- $this->assertFalse(drupal_valid_token(0, array()), 'Token 0, value array returns FALSE.');
- $this->assertFalse(drupal_valid_token('', array()), "Token '', value array returns FALSE.");
- $this->assertFalse('' === drupal_get_token(array()), 'Token generation does not return an empty string on invalid parameters.');
- $this->assertErrors = TRUE;
-
- $this->assertFalse(drupal_valid_token(TRUE, 'foo'), 'Token TRUE, value foo returns FALSE.');
- $this->assertFalse(drupal_valid_token(0, 'foo'), 'Token 0, value foo returns FALSE.');
- }
-
- /**
- * Overrides DrupalTestCase::errorHandler().
- */
- public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
- if ($this->assertErrors) {
- return parent::errorHandler($severity, $message, $file, $line);
- }
- return TRUE;
- }
-}
diff --git a/modules/system/system.theme-rtl.css b/modules/system/system.theme-rtl.css
deleted file mode 100644
index 0cd7fa64..00000000
--- a/modules/system/system.theme-rtl.css
+++ /dev/null
@@ -1,53 +0,0 @@
-
-/**
- * @file
- * RTL styles for common markup.
- */
-
-/**
- * HTML elements.
- */
-th {
- text-align: right;
- padding-left: 1em;
- padding-right: 0;
-}
-
-/**
- * Markup generated by theme_item_list().
- */
-.item-list ul li {
- margin: 0 1.5em 0.25em 0;
-}
-
-/**
- * Markup generated by theme_more_link().
- */
-.more-link {
- text-align: left;
-}
-
-/**
- * Markup generated by theme_more_help_link().
- */
-.more-help-link {
- text-align: left;
-}
-.more-help-link a {
- background-position: 100% 50%;
- padding: 1px 20px 1px 0;
-}
-
-/**
- * Collapsible fieldsets.
- */
-html.js fieldset.collapsible .fieldset-legend {
- background-position: 98% 75%;
- padding-left: 0;
- padding-right: 15px;
-}
-html.js fieldset.collapsed .fieldset-legend {
- background-image: url(../../misc/menu-collapsed-rtl.png);
- background-position: 98% 50%;
-}
-
diff --git a/modules/system/system.theme.css b/modules/system/system.theme.css
deleted file mode 100644
index 73cebee7..00000000
--- a/modules/system/system.theme.css
+++ /dev/null
@@ -1,239 +0,0 @@
-
-/**
- * @file
- * Basic styling for common markup.
- */
-
-/**
- * HTML elements.
- */
-fieldset {
- margin-bottom: 1em;
- padding: 0.5em;
-}
-form {
- margin: 0;
- padding: 0;
-}
-hr {
- border: 1px solid gray;
- height: 1px;
-}
-img {
- border: 0;
-}
-table {
- border-collapse: collapse;
-}
-th {
- border-bottom: 3px solid #ccc;
- padding-right: 1em; /* LTR */
- text-align: left; /* LTR */
-}
-tbody {
- border-top: 1px solid #ccc;
-}
-tr.even,
-tr.odd {
- background-color: #eee;
- border-bottom: 1px solid #ccc;
- padding: 0.1em 0.6em;
-}
-
-/**
- * Markup generated by theme_tablesort_indicator().
- */
-th.active img {
- display: inline;
-}
-td.active {
- background-color: #ddd;
-}
-
-/**
- * Markup generated by theme_item_list().
- */
-.item-list .title {
- font-weight: bold;
-}
-.item-list ul {
- margin: 0 0 0.75em 0;
- padding: 0;
-}
-.item-list ul li {
- margin: 0 0 0.25em 1.5em; /* LTR */
- padding: 0;
-}
-
-/**
- * Markup generated by Form API.
- */
-.form-item,
-.form-actions {
- margin-top: 1em;
- margin-bottom: 1em;
-}
-tr.odd .form-item,
-tr.even .form-item {
- margin-top: 0;
- margin-bottom: 0;
- white-space: nowrap;
-}
-.form-item .description {
- font-size: 0.85em;
-}
-label {
- display: block;
- font-weight: bold;
-}
-label.option {
- display: inline;
- font-weight: normal;
-}
-.form-checkboxes .form-item,
-.form-radios .form-item {
- margin-top: 0.4em;
- margin-bottom: 0.4em;
-}
-.form-type-radio .description,
-.form-type-checkbox .description {
- margin-left: 2.4em;
-}
-input.form-checkbox,
-input.form-radio {
- vertical-align: middle;
-}
-.marker,
-.form-required {
- color: #f00;
-}
-.form-item input.error,
-.form-item textarea.error,
-.form-item select.error {
- border: 2px solid red;
-}
-
-/**
- * Inline items.
- */
-.container-inline .form-actions,
-.container-inline.form-actions {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-/**
- * Markup generated by theme_more_link().
- */
-.more-link {
- text-align: right; /* LTR */
-}
-
-/**
- * Markup generated by theme_more_help_link().
- */
-.more-help-link {
- text-align: right; /* LTR */
-}
-.more-help-link a {
- background: url(../../misc/help.png) 0 50% no-repeat; /* LTR */
- padding: 1px 0 1px 20px; /* LTR */
-}
-
-/**
- * Markup generated by theme_pager().
- */
-.item-list .pager {
- clear: both;
- text-align: center;
-}
-.item-list .pager li {
- background-image: none;
- display: inline;
- list-style-type: none;
- padding: 0.5em;
-}
-.pager-current {
- font-weight: bold;
-}
-
-/**
- * Autocomplete.
- *
- * @see autocomplete.js
- */
-/* Suggestion list */
-#autocomplete li.selected {
- background: #0072b9;
- color: #fff;
-}
-
-/**
- * Collapsible fieldsets.
- *
- * @see collapse.js
- */
-html.js fieldset.collapsible .fieldset-legend {
- background: url(../../misc/menu-expanded.png) 5px 65% no-repeat; /* LTR */
- padding-left: 15px; /* LTR */
-}
-html.js fieldset.collapsed .fieldset-legend {
- background-image: url(../../misc/menu-collapsed.png); /* LTR */
- background-position: 5px 50%; /* LTR */
-}
-.fieldset-legend span.summary {
- color: #999;
- font-size: 0.9em;
- margin-left: 0.5em;
-}
-
-/**
- * TableDrag behavior.
- *
- * @see tabledrag.js
- */
-tr.drag {
- background-color: #fffff0;
-}
-tr.drag-previous {
- background-color: #ffd;
-}
-.tabledrag-toggle-weight {
- font-size: 0.9em;
-}
-body div.tabledrag-changed-warning {
- margin-bottom: 0.5em;
-}
-
-/**
- * TableSelect behavior.
- *
- * @see tableselect.js
-*/
-tr.selected td {
- background: #ffc;
-}
-td.checkbox,
-th.checkbox {
- text-align: center;
-}
-
-/**
- * Progress bar.
- *
- * @see progress.js
- */
-.progress {
- font-weight: bold;
-}
-.progress .bar {
- background: #ccc;
- border-color: #666;
- margin: 0 0.2em;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- border-radius: 3px;
-}
-.progress .filled {
- background: #0072b9 url(../../misc/progress.gif);
-}
diff --git a/modules/system/system.tokens.inc b/modules/system/system.tokens.inc
deleted file mode 100644
index b612d105..00000000
--- a/modules/system/system.tokens.inc
+++ /dev/null
@@ -1,269 +0,0 @@
- t("Site information"),
- 'description' => t("Tokens for site-wide settings and other global information."),
- );
- $types['date'] = array(
- 'name' => t("Dates"),
- 'description' => t("Tokens related to times and dates."),
- );
- $types['file'] = array(
- 'name' => t("Files"),
- 'description' => t("Tokens related to uploaded files."),
- 'needs-data' => 'file',
- );
-
- // Site-wide global tokens.
- $site['name'] = array(
- 'name' => t("Name"),
- 'description' => t("The name of the site."),
- );
- $site['slogan'] = array(
- 'name' => t("Slogan"),
- 'description' => t("The slogan of the site."),
- );
- $site['mail'] = array(
- 'name' => t("Email"),
- 'description' => t("The administrative email address for the site."),
- );
- $site['url'] = array(
- 'name' => t("URL"),
- 'description' => t("The URL of the site's front page."),
- );
- $site['url-brief'] = array(
- 'name' => t("URL (brief)"),
- 'description' => t("The URL of the site's front page without the protocol."),
- );
- $site['login-url'] = array(
- 'name' => t("Login page"),
- 'description' => t("The URL of the site's login page."),
- );
-
- // Date related tokens.
- $date['short'] = array(
- 'name' => t("Short format"),
- 'description' => t("A date in 'short' format. (%date)", array('%date' => format_date(REQUEST_TIME, 'short'))),
- );
- $date['medium'] = array(
- 'name' => t("Medium format"),
- 'description' => t("A date in 'medium' format. (%date)", array('%date' => format_date(REQUEST_TIME, 'medium'))),
- );
- $date['long'] = array(
- 'name' => t("Long format"),
- 'description' => t("A date in 'long' format. (%date)", array('%date' => format_date(REQUEST_TIME, 'long'))),
- );
- $date['custom'] = array(
- 'name' => t("Custom format"),
- 'description' => t("A date in a custom format. See !php-date for details.", array('!php-date' => l(t('the PHP documentation'), 'http://php.net/manual/en/function.date.php'))),
- );
- $date['since'] = array(
- 'name' => t("Time-since"),
- 'description' => t("A date in 'time-since' format. (%date)", array('%date' => format_interval(REQUEST_TIME - 360, 2))),
- );
- $date['raw'] = array(
- 'name' => t("Raw timestamp"),
- 'description' => t("A date in UNIX timestamp format (%date)", array('%date' => REQUEST_TIME)),
- );
-
-
- // File related tokens.
- $file['fid'] = array(
- 'name' => t("File ID"),
- 'description' => t("The unique ID of the uploaded file."),
- );
- $file['name'] = array(
- 'name' => t("File name"),
- 'description' => t("The name of the file on disk."),
- );
- $file['path'] = array(
- 'name' => t("Path"),
- 'description' => t("The location of the file relative to Drupal root."),
- );
- $file['mime'] = array(
- 'name' => t("MIME type"),
- 'description' => t("The MIME type of the file."),
- );
- $file['size'] = array(
- 'name' => t("File size"),
- 'description' => t("The size of the file."),
- );
- $file['url'] = array(
- 'name' => t("URL"),
- 'description' => t("The web-accessible URL for the file."),
- );
- $file['timestamp'] = array(
- 'name' => t("Timestamp"),
- 'description' => t("The date the file was most recently changed."),
- 'type' => 'date',
- );
- $file['owner'] = array(
- 'name' => t("Owner"),
- 'description' => t("The user who originally uploaded the file."),
- 'type' => 'user',
- );
-
- return array(
- 'types' => $types,
- 'tokens' => array(
- 'site' => $site,
- 'date' => $date,
- 'file' => $file,
- ),
- );
-}
-
-/**
- * Implements hook_tokens().
- */
-function system_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $url_options = array('absolute' => TRUE);
- if (isset($options['language'])) {
- $url_options['language'] = $options['language'];
- $language_code = $options['language']->language;
- }
- else {
- $language_code = NULL;
- }
- $sanitize = !empty($options['sanitize']);
-
- $replacements = array();
-
- if ($type == 'site') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'name':
- $site_name = variable_get('site_name', 'Drupal');
- $replacements[$original] = $sanitize ? check_plain($site_name) : $site_name;
- break;
-
- case 'slogan':
- $slogan = variable_get('site_slogan', '');
- $replacements[$original] = $sanitize ? check_plain($slogan) : $slogan;
- break;
-
- case 'mail':
- $replacements[$original] = variable_get('site_mail', '');
- break;
-
- case 'url':
- $replacements[$original] = url('', $url_options);
- break;
-
- case 'url-brief':
- $replacements[$original] = preg_replace(array('!^https?://!', '!/$!'), '', url('', $url_options));
- break;
-
- case 'login-url':
- $replacements[$original] = url('user', $url_options);
- break;
- }
- }
- }
-
- elseif ($type == 'date') {
- if (empty($data['date'])) {
- $date = REQUEST_TIME;
- }
- else {
- $date = $data['date'];
- }
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'short':
- $replacements[$original] = format_date($date, 'short', '', NULL, $language_code);
- break;
-
- case 'medium':
- $replacements[$original] = format_date($date, 'medium', '', NULL, $language_code);
- break;
-
- case 'long':
- $replacements[$original] = format_date($date, 'long', '', NULL, $language_code);
- break;
-
- case 'since':
- $replacements[$original] = format_interval((REQUEST_TIME - $date), 2, $language_code);
- break;
-
- case 'raw':
- $replacements[$original] = $sanitize ? check_plain($date) : $date;
- break;
- }
- }
-
- if ($created_tokens = token_find_with_prefix($tokens, 'custom')) {
- foreach ($created_tokens as $name => $original) {
- $replacements[$original] = format_date($date, 'custom', $name, NULL, $language_code);
- }
- }
- }
-
- elseif ($type == 'file' && !empty($data['file'])) {
- $file = $data['file'];
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- // Basic keys and values.
- case 'fid':
- $replacements[$original] = $file->fid;
- break;
-
- // Essential file data
- case 'name':
- $replacements[$original] = $sanitize ? check_plain($file->filename) : $file->filename;
- break;
-
- case 'path':
- $replacements[$original] = $sanitize ? check_plain($file->uri) : $file->uri;
- break;
-
- case 'mime':
- $replacements[$original] = $sanitize ? check_plain($file->filemime) : $file->filemime;
- break;
-
- case 'size':
- $replacements[$original] = format_size($file->filesize);
- break;
-
- case 'url':
- $replacements[$original] = $sanitize ? check_plain(file_create_url($file->uri)) : file_create_url($file->uri);
- break;
-
- // These tokens are default variations on the chained tokens handled below.
- case 'timestamp':
- $replacements[$original] = format_date($file->timestamp, 'medium', '', NULL, $language_code);
- break;
-
- case 'owner':
- $account = user_load($file->uid);
- $name = format_username($account);
- $replacements[$original] = $sanitize ? check_plain($name) : $name;
- break;
- }
- }
-
- if ($date_tokens = token_find_with_prefix($tokens, 'timestamp')) {
- $replacements += token_generate('date', $date_tokens, array('date' => $file->timestamp), $options);
- }
-
- if (($owner_tokens = token_find_with_prefix($tokens, 'owner')) && $account = user_load($file->uid)) {
- $replacements += token_generate('user', $owner_tokens, array('user' => $account), $options);
- }
- }
-
- return $replacements;
-}
diff --git a/modules/system/system.updater.inc b/modules/system/system.updater.inc
deleted file mode 100644
index a14d788b..00000000
--- a/modules/system/system.updater.inc
+++ /dev/null
@@ -1,150 +0,0 @@
-name)) {
- $relative_path = dirname($relative_path);
- }
- else {
- $relative_path = 'sites/all/modules';
- }
- return DRUPAL_ROOT . '/' . $relative_path;
- }
-
- public function isInstalled() {
- return (bool) drupal_get_path('module', $this->name);
- }
-
- public static function canUpdateDirectory($directory) {
- if (file_scan_directory($directory, '/.*\.module$/')) {
- return TRUE;
- }
- return FALSE;
- }
-
- public static function canUpdate($project_name) {
- return (bool) drupal_get_path('module', $project_name);
- }
-
- /**
- * Return available database schema updates one a new version is installed.
- */
- public function getSchemaUpdates() {
- require_once DRUPAL_ROOT . '/includes/install.inc';
- require_once DRUPAL_ROOT . '/includes/update.inc';
-
- if (_update_get_project_type($project) != 'module') {
- return array();
- }
- module_load_include('install', $project);
-
- if (!$updates = drupal_get_schema_versions($project)) {
- return array();
- }
- $updates_to_run = array();
- $modules_with_updates = update_get_update_list();
- if ($updates = $modules_with_updates[$project]) {
- if ($updates['start']) {
- return $updates['pending'];
- }
- }
- return array();
- }
-
- /**
- * Returns a list of post install actions.
- */
- public function postInstallTasks() {
- return array(
- l(t('Install another module'), 'admin/modules/install'),
- l(t('Enable newly added modules'), 'admin/modules'),
- l(t('Administration pages'), 'admin'),
- );
- }
-
- public function postUpdateTasks() {
- // We don't want to check for DB updates here, we do that once for all
- // updated modules on the landing page.
- }
-
-}
-
-/**
- * Class for updating themes using FileTransfer classes via authorize.php.
- */
-class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
-
- /**
- * Return the directory where a theme should be installed.
- *
- * If the theme is already installed, drupal_get_path() will return
- * a valid path and we should install it there (although we need to use an
- * absolute path, so we prepend DRUPAL_ROOT). If we're installing a new
- * theme, we always want it to go into sites/all/themes, since that's
- * where all the documentation recommends users install their themes, and
- * there's no way that can conflict on a multi-site installation, since
- * the Update manager won't let you install a new theme if it's already
- * found on your system, and if there was a copy in sites/all, we'd see it.
- */
- public function getInstallDirectory() {
- if ($relative_path = drupal_get_path('theme', $this->name)) {
- $relative_path = dirname($relative_path);
- }
- else {
- $relative_path = 'sites/all/themes';
- }
- return DRUPAL_ROOT . '/' . $relative_path;
- }
-
- public function isInstalled() {
- return (bool) drupal_get_path('theme', $this->name);
- }
-
- static function canUpdateDirectory($directory) {
- // This is a lousy test, but don't know how else to confirm it is a theme.
- if (file_scan_directory($directory, '/.*\.module$/')) {
- return FALSE;
- }
- return TRUE;
- }
-
- public static function canUpdate($project_name) {
- return (bool) drupal_get_path('theme', $project_name);
- }
-
- public function postInstall() {
- // Update the system table.
- clearstatcache();
- system_rebuild_theme_data();
-
- }
-
- public function postInstallTasks() {
- return array(
- l(t('Enable newly added themes'), 'admin/appearance'),
- l(t('Administration pages'), 'admin'),
- );
- }
-}
diff --git a/modules/system/theme.api.php b/modules/system/theme.api.php
deleted file mode 100644
index 56e9ba1b..00000000
--- a/modules/system/theme.api.php
+++ /dev/null
@@ -1,240 +0,0 @@
- $header, 'rows' => $rows));
- * Additionally, the theme() function can take an array of theme
- * hooks, which can be used to provide 'fallback' implementations to
- * allow for more specific control of output. For example, the function:
- * theme(array('table__foo', 'table'), $variables) would look to see if
- * 'table__foo' is registered anywhere; if it is not, it would 'fall back'
- * to the generic 'table' implementation. This can be used to attach specific
- * theme functions to named objects, allowing the themer more control over
- * specific types of output.
- *
- * As of Drupal 6, every theme hook is required to be registered by the
- * module that owns it, so that Drupal can tell what to do with it and
- * to make it simple for themes to identify and override the behavior
- * for these calls.
- *
- * The theme hooks are registered via hook_theme(), which returns an
- * array of arrays with information about the hook. It describes the
- * arguments the function or template will need, and provides
- * defaults for the template in case they are not filled in. If the default
- * implementation is a function, by convention it is named theme_HOOK().
- *
- * Each module should provide a default implementation for theme_hooks that
- * it registers. This implementation may be either a function or a template;
- * if it is a function it must be specified via hook_theme(). By convention,
- * default implementations of theme hooks are named theme_HOOK. Default
- * template implementations are stored in the module directory.
- *
- * Drupal's default template renderer is a simple PHP parsing engine that
- * includes the template and stores the output. Drupal's theme engines
- * can provide alternate template engines, such as XTemplate, Smarty and
- * PHPTal. The most common template engine is PHPTemplate (included with
- * Drupal and implemented in phptemplate.engine, which uses Drupal's default
- * template renderer.
- *
- * In order to create theme-specific implementations of these hooks, themes can
- * implement their own version of theme hooks, either as functions or templates.
- * These implementations will be used instead of the default implementation. If
- * using a pure .theme without an engine, the .theme is required to implement
- * its own version of hook_theme() to tell Drupal what it is implementing;
- * themes utilizing an engine will have their well-named theming functions
- * automatically registered for them. While this can vary based upon the theme
- * engine, the standard set by phptemplate is that theme functions should be
- * named THEMENAME_HOOK. For example, for Drupal's default theme (Bartik) to
- * implement the 'table' hook, the phptemplate.engine would find
- * bartik_table().
- *
- * The theme system is described and defined in theme.inc.
- *
- * @see theme()
- * @see hook_theme()
- * @see hooks
- * @see callbacks
- *
- * @} End of "defgroup themeable".
- */
-
-/**
- * Allow themes to alter the theme-specific settings form.
- *
- * With this hook, themes can alter the theme-specific settings form in any way
- * allowable by Drupal's Form API, such as adding form elements, changing
- * default values and removing form elements. See the Form API documentation on
- * api.drupal.org for detailed information.
- *
- * Note that the base theme's form alterations will be run before any sub-theme
- * alterations.
- *
- * @param $form
- * Nested array of form elements that comprise the form.
- * @param $form_state
- * A keyed array containing the current state of the form.
- */
-function hook_form_system_theme_settings_alter(&$form, &$form_state) {
- // Add a checkbox to toggle the breadcrumb trail.
- $form['toggle_breadcrumb'] = array(
- '#type' => 'checkbox',
- '#title' => t('Display the breadcrumb'),
- '#default_value' => theme_get_setting('toggle_breadcrumb'),
- '#description' => t('Show a trail of links from the homepage to the current page.'),
- );
-}
-
-/**
- * Preprocess theme variables for templates.
- *
- * This hook allows modules to preprocess theme variables for theme templates.
- * It is called for all theme hooks implemented as templates, but not for theme
- * hooks implemented as functions. hook_preprocess_HOOK() can be used to
- * preprocess variables for a specific theme hook, whether implemented as a
- * template or function.
- *
- * For more detailed information, see theme().
- *
- * @param $variables
- * The variables array (modify in place).
- * @param $hook
- * The name of the theme hook.
- */
-function hook_preprocess(&$variables, $hook) {
- static $hooks;
-
- // Add contextual links to the variables, if the user has permission.
-
- if (!user_access('access contextual links')) {
- return;
- }
-
- if (!isset($hooks)) {
- $hooks = theme_get_registry();
- }
-
- // Determine the primary theme function argument.
- if (isset($hooks[$hook]['variables'])) {
- $keys = array_keys($hooks[$hook]['variables']);
- $key = $keys[0];
- }
- else {
- $key = $hooks[$hook]['render element'];
- }
-
- if (isset($variables[$key])) {
- $element = $variables[$key];
- }
-
- if (isset($element) && is_array($element) && !empty($element['#contextual_links'])) {
- $variables['title_suffix']['contextual_links'] = contextual_links_view($element);
- if (!empty($variables['title_suffix']['contextual_links'])) {
- $variables['classes_array'][] = 'contextual-links-region';
- }
- }
-}
-
-/**
- * Preprocess theme variables for a specific theme hook.
- *
- * This hook allows modules to preprocess theme variables for a specific theme
- * hook. It should only be used if a module needs to override or add to the
- * theme preprocessing for a theme hook it didn't define.
- *
- * For more detailed information, see theme().
- *
- * @param $variables
- * The variables array (modify in place).
- */
-function hook_preprocess_HOOK(&$variables) {
- // This example is from rdf_preprocess_image(). It adds an RDF attribute
- // to the image hook's variables.
- $variables['attributes']['typeof'] = array('foaf:Image');
-}
-
-/**
- * Process theme variables for templates.
- *
- * This hook allows modules to process theme variables for theme templates. It
- * is called for all theme hooks implemented as templates, but not for theme
- * hooks implemented as functions. hook_process_HOOK() can be used to process
- * variables for a specific theme hook, whether implemented as a template or
- * function.
- *
- * For more detailed information, see theme().
- *
- * @param $variables
- * The variables array (modify in place).
- * @param $hook
- * The name of the theme hook.
- */
-function hook_process(&$variables, $hook) {
- // Wraps variables in RDF wrappers.
- if (!empty($variables['rdf_template_variable_attributes_array'])) {
- foreach ($variables['rdf_template_variable_attributes_array'] as $variable_name => $attributes) {
- $context = array(
- 'hook' => $hook,
- 'variable_name' => $variable_name,
- 'variables' => $variables,
- );
- $variables[$variable_name] = theme('rdf_template_variable_wrapper', array('content' => $variables[$variable_name], 'attributes' => $attributes, 'context' => $context));
- }
- }
-}
-
-/**
- * Process theme variables for a specific theme hook.
- *
- * This hook allows modules to process theme variables for a specific theme
- * hook. It should only be used if a module needs to override or add to the
- * theme processing for a theme hook it didn't define.
- *
- * For more detailed information, see theme().
- *
- * @param $variables
- * The variables array (modify in place).
- */
-function hook_process_HOOK(&$variables) {
- // @todo There are no use-cases in Drupal core for this hook. Find one from a
- // contributed module, or come up with a good example. Coming up with a good
- // example might be tough, since the intent is for nearly everything to be
- // achievable via preprocess functions, and for process functions to only be
- // used when requiring the later execution time.
-}
-
-/**
- * Respond to themes being enabled.
- *
- * @param array $theme_list
- * Array containing the names of the themes being enabled.
- *
- * @see theme_enable()
- */
-function hook_themes_enabled($theme_list) {
- foreach ($theme_list as $theme) {
- block_theme_initialize($theme);
- }
-}
-
-/**
- * Respond to themes being disabled.
- *
- * @param array $theme_list
- * Array containing the names of the themes being disabled.
- *
- * @see theme_disable()
- */
-function hook_themes_disabled($theme_list) {
- // Clear all update module caches.
- _update_cache_clear();
-}
diff --git a/modules/taxonomy/taxonomy-term.tpl.php b/modules/taxonomy/taxonomy-term.tpl.php
deleted file mode 100644
index a225c3a5..00000000
--- a/modules/taxonomy/taxonomy-term.tpl.php
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
diff --git a/modules/taxonomy/taxonomy.admin.inc b/modules/taxonomy/taxonomy.admin.inc
deleted file mode 100644
index 828fde0a..00000000
--- a/modules/taxonomy/taxonomy.admin.inc
+++ /dev/null
@@ -1,984 +0,0 @@
-vid]['#vocabulary'] = $vocabulary;
- $form[$vocabulary->vid]['name'] = array('#markup' => check_plain($vocabulary->name));
- $form[$vocabulary->vid]['weight'] = array(
- '#type' => 'weight',
- '#title' => t('Weight for @title', array('@title' => $vocabulary->name)),
- '#title_display' => 'invisible',
- '#delta' => 10,
- '#default_value' => $vocabulary->weight,
- );
- $form[$vocabulary->vid]['edit'] = array('#type' => 'link', '#title' => t('edit vocabulary'), '#href' => "admin/structure/taxonomy/$vocabulary->machine_name/edit");
- $form[$vocabulary->vid]['list'] = array('#type' => 'link', '#title' => t('list terms'), '#href' => "admin/structure/taxonomy/$vocabulary->machine_name");
- $form[$vocabulary->vid]['add'] = array('#type' => 'link', '#title' => t('add terms'), '#href' => "admin/structure/taxonomy/$vocabulary->machine_name/add");
- }
-
- // Only make this form include a submit button and weight if more than one
- // vocabulary exists.
- if (count($vocabularies) > 1) {
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
- }
- elseif (isset($vocabulary)) {
- unset($form[$vocabulary->vid]['weight']);
- }
- return $form;
-}
-
-/**
- * Submit handler for vocabularies overview. Updates changed vocabulary weights.
- *
- * @see taxonomy_overview_vocabularies()
- */
-function taxonomy_overview_vocabularies_submit($form, &$form_state) {
- foreach ($form_state['values'] as $vid => $vocabulary) {
- if (is_numeric($vid) && $form[$vid]['#vocabulary']->weight != $form_state['values'][$vid]['weight']) {
- $form[$vid]['#vocabulary']->weight = $form_state['values'][$vid]['weight'];
- taxonomy_vocabulary_save($form[$vid]['#vocabulary']);
- }
- }
- drupal_set_message(t('The configuration options have been saved.'));
-}
-
-/**
- * Returns HTML for the vocabulary overview form as a sortable list of vocabularies.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @see taxonomy_overview_vocabularies()
- * @ingroup themeable
- */
-function theme_taxonomy_overview_vocabularies($variables) {
- $form = $variables['form'];
-
- $rows = array();
-
- foreach (element_children($form) as $key) {
- if (isset($form[$key]['name'])) {
- $vocabulary = &$form[$key];
-
- $row = array();
- $row[] = drupal_render($vocabulary['name']);
- if (isset($vocabulary['weight'])) {
- $vocabulary['weight']['#attributes']['class'] = array('vocabulary-weight');
- $row[] = drupal_render($vocabulary['weight']);
- }
- $row[] = drupal_render($vocabulary['edit']);
- $row[] = drupal_render($vocabulary['list']);
- $row[] = drupal_render($vocabulary['add']);
- $rows[] = array('data' => $row, 'class' => array('draggable'));
- }
- }
-
- $header = array(t('Vocabulary name'));
- if (isset($form['actions'])) {
- $header[] = t('Weight');
- drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight');
- }
- $header[] = array('data' => t('Operations'), 'colspan' => '3');
- return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No vocabularies available. Add vocabulary .', array('@link' => url('admin/structure/taxonomy/add'))), 'attributes' => array('id' => 'taxonomy'))) . drupal_render_children($form);
-}
-
-/**
- * Form builder for the vocabulary editing form.
- *
- * @ingroup forms
- * @see taxonomy_form_vocabulary_submit()
- * @see taxonomy_form_vocabulary_validate()
- */
-function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) {
- // During initial form build, add the entity to the form state for use
- // during form building and processing. During a rebuild, use what is in the
- // form state.
- if (!isset($form_state['vocabulary'])) {
- $vocabulary = is_object($edit) ? $edit : (object) $edit;
- $defaults = array(
- 'name' => '',
- 'machine_name' => '',
- 'description' => '',
- 'hierarchy' => 0,
- 'weight' => 0,
- );
- foreach ($defaults as $key => $value) {
- if (!isset($vocabulary->$key)) {
- $vocabulary->$key = $value;
- }
- }
- $form_state['vocabulary'] = $vocabulary;
- }
- else {
- $vocabulary = $form_state['vocabulary'];
- }
-
- // @todo Legacy support. Modules are encouraged to access the entity using
- // $form_state. Remove in Drupal 8.
- $form['#vocabulary'] = $form_state['vocabulary'];
-
- // Check whether we need a deletion confirmation form.
- if (isset($form_state['confirm_delete']) && isset($form_state['values']['vid'])) {
- return taxonomy_vocabulary_confirm_delete($form, $form_state, $form_state['values']['vid']);
- }
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Name'),
- '#default_value' => $vocabulary->name,
- '#maxlength' => 255,
- '#required' => TRUE,
- );
- $form['machine_name'] = array(
- '#type' => 'machine_name',
- '#default_value' => $vocabulary->machine_name,
- '#maxlength' => 255,
- '#machine_name' => array(
- 'exists' => 'taxonomy_vocabulary_machine_name_load',
- ),
- );
- $form['old_machine_name'] = array(
- '#type' => 'value',
- '#value' => $vocabulary->machine_name,
- );
- $form['description'] = array(
- '#type' => 'textfield',
- '#title' => t('Description'),
- '#default_value' => $vocabulary->description,
- );
- // Set the hierarchy to "multiple parents" by default. This simplifies the
- // vocabulary form and standardizes the term form.
- $form['hierarchy'] = array(
- '#type' => 'value',
- '#value' => '0',
- );
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
- if (isset($vocabulary->vid)) {
- $form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
- $form['vid'] = array('#type' => 'value', '#value' => $vocabulary->vid);
- $form['module'] = array('#type' => 'value', '#value' => $vocabulary->module);
- }
- $form['#validate'][] = 'taxonomy_form_vocabulary_validate';
-
- return $form;
-}
-
-/**
- * Form validation handler for taxonomy_form_vocabulary().
- *
- * Makes sure that the machine name of the vocabulary is not in the
- * disallowed list (names that conflict with menu items, such as 'list'
- * and 'add').
- *
- * @see taxonomy_form_vocabulary()
- * @see taxonomy_form_vocabulary_submit()
- */
-function taxonomy_form_vocabulary_validate($form, &$form_state) {
- // During the deletion there is no 'machine_name' key
- if (isset($form_state['values']['machine_name'])) {
- // Do not allow machine names to conflict with taxonomy path arguments.
- $machine_name = $form_state['values']['machine_name'];
- $disallowed = array('add', 'list');
- if (in_array($machine_name, $disallowed)) {
- form_set_error('machine_name', t('The machine-readable name cannot be "add" or "list".'));
- }
- }
-}
-
-/**
- * Form submission handler for taxonomy_form_vocabulary().
- *
- * @see taxonomy_form_vocabulary()
- * @see taxonomy_form_vocabulary_validate()
- */
-function taxonomy_form_vocabulary_submit($form, &$form_state) {
- if ($form_state['triggering_element']['#value'] == t('Delete')) {
- // Rebuild the form to confirm vocabulary deletion.
- $form_state['rebuild'] = TRUE;
- $form_state['confirm_delete'] = TRUE;
- return;
- }
-
- $vocabulary = $form_state['vocabulary'];
- entity_form_submit_build_entity('taxonomy_vocabulary', $vocabulary, $form, $form_state);
-
- switch (taxonomy_vocabulary_save($vocabulary)) {
- case SAVED_NEW:
- drupal_set_message(t('Created new vocabulary %name.', array('%name' => $vocabulary->name)));
- watchdog('taxonomy', 'Created new vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/structure/taxonomy/' . $vocabulary->machine_name . '/edit'));
- break;
-
- case SAVED_UPDATED:
- drupal_set_message(t('Updated vocabulary %name.', array('%name' => $vocabulary->name)));
- watchdog('taxonomy', 'Updated vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/structure/taxonomy/' . $vocabulary->machine_name . '/edit'));
- break;
- }
-
- $form_state['values']['vid'] = $vocabulary->vid;
- $form_state['vid'] = $vocabulary->vid;
- $form_state['redirect'] = 'admin/structure/taxonomy';
-}
-
-/**
- * Form builder for the taxonomy terms overview.
- *
- * Display a tree of all the terms in a vocabulary, with options to edit
- * each one. The form is made drag and drop by the theme function.
- *
- * @ingroup forms
- * @see taxonomy_overview_terms_submit()
- * @see theme_taxonomy_overview_terms()
- */
-function taxonomy_overview_terms($form, &$form_state, $vocabulary) {
- global $pager_page_array, $pager_total, $pager_total_items;
-
- // Check for confirmation forms.
- if (isset($form_state['confirm_reset_alphabetical'])) {
- return taxonomy_vocabulary_confirm_reset_alphabetical($form, $form_state, $vocabulary->vid);
- }
-
- $form['#vocabulary'] = $vocabulary;
- $form['#tree'] = TRUE;
- $form['#parent_fields'] = FALSE;
-
- $page = isset($_GET['page']) ? $_GET['page'] : 0;
- $page_increment = variable_get('taxonomy_terms_per_page_admin', 100); // Number of terms per page.
- $page_entries = 0; // Elements shown on this page.
- $before_entries = 0; // Elements at the root level before this page.
- $after_entries = 0; // Elements at the root level after this page.
- $root_entries = 0; // Elements at the root level on this page.
-
- // Terms from previous and next pages are shown if the term tree would have
- // been cut in the middle. Keep track of how many extra terms we show on each
- // page of terms.
- $back_step = NULL;
- $forward_step = 0;
-
- // An array of the terms to be displayed on this page.
- $current_page = array();
-
- $delta = 0;
- $term_deltas = array();
- $tree = taxonomy_get_tree($vocabulary->vid);
- $term = current($tree);
- do {
- // In case this tree is completely empty.
- if (empty($term)) {
- break;
- }
- $delta++;
- // Count entries before the current page.
- if ($page && ($page * $page_increment) > $before_entries && !isset($back_step)) {
- $before_entries++;
- continue;
- }
- // Count entries after the current page.
- elseif ($page_entries > $page_increment && isset($complete_tree)) {
- $after_entries++;
- continue;
- }
-
- // Do not let a term start the page that is not at the root.
- if (isset($term->depth) && ($term->depth > 0) && !isset($back_step)) {
- $back_step = 0;
- while ($pterm = prev($tree)) {
- $before_entries--;
- $back_step++;
- if ($pterm->depth == 0) {
- prev($tree);
- continue 2; // Jump back to the start of the root level parent.
- }
- }
- }
- $back_step = isset($back_step) ? $back_step : 0;
-
- // Continue rendering the tree until we reach the a new root item.
- if ($page_entries >= $page_increment + $back_step + 1 && $term->depth == 0 && $root_entries > 1) {
- $complete_tree = TRUE;
- // This new item at the root level is the first item on the next page.
- $after_entries++;
- continue;
- }
- if ($page_entries >= $page_increment + $back_step) {
- $forward_step++;
- }
-
- // Finally, if we've gotten down this far, we're rendering a term on this page.
- $page_entries++;
- $term_deltas[$term->tid] = isset($term_deltas[$term->tid]) ? $term_deltas[$term->tid] + 1 : 0;
- $key = 'tid:' . $term->tid . ':' . $term_deltas[$term->tid];
-
- // Keep track of the first term displayed on this page.
- if ($page_entries == 1) {
- $form['#first_tid'] = $term->tid;
- }
- // Keep a variable to make sure at least 2 root elements are displayed.
- if ($term->parents[0] == 0) {
- $root_entries++;
- }
- $current_page[$key] = $term;
- } while ($term = next($tree));
-
- // Because we didn't use a pager query, set the necessary pager variables.
- $total_entries = $before_entries + $page_entries + $after_entries;
- $pager_total_items[0] = $total_entries;
- $pager_page_array[0] = $page;
- $pager_total[0] = ceil($total_entries / $page_increment);
-
- // If this form was already submitted once, it's probably hit a validation
- // error. Ensure the form is rebuilt in the same order as the user submitted.
- if (!empty($form_state['input'])) {
- $order = array_flip(array_keys($form_state['input'])); // Get the $_POST order.
- $current_page = array_merge($order, $current_page); // Update our form with the new order.
- foreach ($current_page as $key => $term) {
- // Verify this is a term for the current page and set at the current depth.
- if (is_array($form_state['input'][$key]) && is_numeric($form_state['input'][$key]['tid'])) {
- $current_page[$key]->depth = $form_state['input'][$key]['depth'];
- }
- else {
- unset($current_page[$key]);
- }
- }
- }
-
- // Build the actual form.
- foreach ($current_page as $key => $term) {
- // Save the term for the current page so we don't have to load it a second time.
- $form[$key]['#term'] = (array) $term;
- if (isset($term->parents)) {
- $form[$key]['#term']['parent'] = $term->parent = $term->parents[0];
- unset($form[$key]['#term']['parents'], $term->parents);
- }
-
- $form[$key]['view'] = array('#type' => 'link', '#title' => $term->name, '#href' => "taxonomy/term/$term->tid");
- if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
- $form['#parent_fields'] = TRUE;
- $form[$key]['tid'] = array(
- '#type' => 'hidden',
- '#value' => $term->tid
- );
- $form[$key]['parent'] = array(
- '#type' => 'hidden',
- // Yes, default_value on a hidden. It needs to be changeable by the javascript.
- '#default_value' => $term->parent,
- );
- $form[$key]['depth'] = array(
- '#type' => 'hidden',
- // Same as above, the depth is modified by javascript, so it's a default_value.
- '#default_value' => $term->depth,
- );
- $form[$key]['weight'] = array(
- '#type' => 'weight',
- '#delta' => $delta,
- '#title_display' => 'invisible',
- '#title' => t('Weight for added term'),
- '#default_value' => $term->weight,
- );
- }
- $form[$key]['edit'] = array('#type' => 'link', '#title' => t('edit'), '#href' => 'taxonomy/term/' . $term->tid . '/edit', '#options' => array('query' => drupal_get_destination()));
- }
-
- $form['#total_entries'] = $total_entries;
- $form['#page_increment'] = $page_increment;
- $form['#page_entries'] = $page_entries;
- $form['#back_step'] = $back_step;
- $form['#forward_step'] = $forward_step;
- $form['#empty_text'] = t('No terms available. Add term .', array('@link' => url('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add')));
-
- if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
- $form['actions'] = array('#type' => 'actions', '#tree' => FALSE);
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save')
- );
- $form['actions']['reset_alphabetical'] = array(
- '#type' => 'submit',
- '#value' => t('Reset to alphabetical')
- );
- $form_state['redirect'] = array($_GET['q'], (isset($_GET['page']) ? array('query' => array('page' => $_GET['page'])) : array()));
- }
-
- return $form;
-}
-
-/**
- * Submit handler for terms overview form.
- *
- * Rather than using a textfield or weight field, this form depends entirely
- * upon the order of form elements on the page to determine new weights.
- *
- * Because there might be hundreds or thousands of taxonomy terms that need to
- * be ordered, terms are weighted from 0 to the number of terms in the
- * vocabulary, rather than the standard -10 to 10 scale. Numbers are sorted
- * lowest to highest, but are not necessarily sequential. Numbers may be skipped
- * when a term has children so that reordering is minimal when a child is
- * added or removed from a term.
- *
- * @see taxonomy_overview_terms()
- */
-function taxonomy_overview_terms_submit($form, &$form_state) {
- 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);
- }
- // Rebuild the form to confirm the reset action.
- $form_state['rebuild'] = TRUE;
- $form_state['confirm_reset_alphabetical'] = TRUE;
- return;
- }
-
- // Sort term order based on weight.
- uasort($form_state['values'], 'drupal_sort_weight');
-
- $vocabulary = $form['#vocabulary'];
- $hierarchy = 0; // Update the current hierarchy type as we go.
-
- $changed_terms = array();
- $tree = taxonomy_get_tree($vocabulary->vid);
-
- if (empty($tree)) {
- return;
- }
-
- // Build a list of all terms that need to be updated on previous pages.
- $weight = 0;
- $term = (array) $tree[0];
- while ($term['tid'] != $form['#first_tid']) {
- if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
- $term['parent'] = $term['parents'][0];
- $term['weight'] = $weight;
- $changed_terms[$term['tid']] = $term;
- }
- $weight++;
- $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
- $term = (array) $tree[$weight];
- }
-
- // Renumber the current page weights and assign any new parents.
- $level_weights = array();
- foreach ($form_state['values'] as $tid => $values) {
- if (isset($form[$tid]['#term'])) {
- $term = $form[$tid]['#term'];
- // Give terms at the root level a weight in sequence with terms on previous pages.
- if ($values['parent'] == 0 && $term['weight'] != $weight) {
- $term['weight'] = $weight;
- $changed_terms[$term['tid']] = $term;
- }
- // Terms not at the root level can safely start from 0 because they're all on this page.
- elseif ($values['parent'] > 0) {
- $level_weights[$values['parent']] = isset($level_weights[$values['parent']]) ? $level_weights[$values['parent']] + 1 : 0;
- if ($level_weights[$values['parent']] != $term['weight']) {
- $term['weight'] = $level_weights[$values['parent']];
- $changed_terms[$term['tid']] = $term;
- }
- }
- // Update any changed parents.
- if ($values['parent'] != $term['parent']) {
- $term['parent'] = $values['parent'];
- $changed_terms[$term['tid']] = $term;
- }
- $hierarchy = $term['parent'] != 0 ? 1 : $hierarchy;
- $weight++;
- }
- }
-
- // Build a list of all terms that need to be updated on following pages.
- for ($weight; $weight < count($tree); $weight++) {
- $term = (array) $tree[$weight];
- if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
- $term['parent'] = $term['parents'][0];
- $term['weight'] = $weight;
- $changed_terms[$term['tid']] = $term;
- }
- $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
- }
-
- // Save all updated terms.
- foreach ($changed_terms as $changed) {
- $term = (object) $changed;
- // Update term_hierachy and term_data directly since we don't have a
- // fully populated term object to save.
- db_update('taxonomy_term_hierarchy')
- ->fields(array('parent' => $term->parent))
- ->condition('tid', $term->tid, '=')
- ->execute();
-
- db_update('taxonomy_term_data')
- ->fields(array('weight' => $term->weight))
- ->condition('tid', $term->tid, '=')
- ->execute();
- }
-
- // Update the vocabulary hierarchy to flat or single hierarchy.
- if ($vocabulary->hierarchy != $hierarchy) {
- $vocabulary->hierarchy = $hierarchy;
- taxonomy_vocabulary_save($vocabulary);
- }
- drupal_set_message(t('The configuration options have been saved.'));
-}
-
-/**
- * Returns HTML for a terms overview form as a sortable list of terms.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @see taxonomy_overview_terms()
- * @ingroup themeable
- */
-function theme_taxonomy_overview_terms($variables) {
- $form = $variables['form'];
-
- $page_increment = $form['#page_increment'];
- $page_entries = $form['#page_entries'];
- $back_step = $form['#back_step'];
- $forward_step = $form['#forward_step'];
-
- // Add drag and drop if parent fields are present in the form.
- if ($form['#parent_fields']) {
- drupal_add_tabledrag('taxonomy', 'match', 'parent', 'term-parent', 'term-parent', 'term-id', FALSE);
- drupal_add_tabledrag('taxonomy', 'depth', 'group', 'term-depth', NULL, NULL, FALSE);
- drupal_add_js(drupal_get_path('module', 'taxonomy') . '/taxonomy.js');
- drupal_add_js(array('taxonomy' => array('backStep' => $back_step, 'forwardStep' => $forward_step)), 'setting');
- drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
- }
- drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'term-weight');
-
- $errors = form_get_errors() != FALSE ? form_get_errors() : array();
- $rows = array();
- foreach (element_children($form) as $key) {
- if (isset($form[$key]['#term'])) {
- $term = &$form[$key];
-
- $row = array();
- $row[] = (isset($term['#term']['depth']) && $term['#term']['depth'] > 0 ? theme('indentation', array('size' => $term['#term']['depth'])) : ''). drupal_render($term['view']);
- if ($form['#parent_fields']) {
- $term['tid']['#attributes']['class'] = array('term-id');
- $term['parent']['#attributes']['class'] = array('term-parent');
- $term['depth']['#attributes']['class'] = array('term-depth');
- $row[0] .= drupal_render($term['parent']) . drupal_render($term['tid']) . drupal_render($term['depth']);
- }
- $term['weight']['#attributes']['class'] = array('term-weight');
- $row[] = drupal_render($term['weight']);
- $row[] = drupal_render($term['edit']);
- $row = array('data' => $row);
- $rows[$key] = $row;
- }
- }
-
- // Add necessary classes to rows.
- $row_position = 0;
- foreach ($rows as $key => $row) {
- $rows[$key]['class'] = array();
- if (isset($form['#parent_fields'])) {
- $rows[$key]['class'][] = 'draggable';
- }
-
- // Add classes that mark which terms belong to previous and next pages.
- if ($row_position < $back_step || $row_position >= $page_entries - $forward_step) {
- $rows[$key]['class'][] = 'taxonomy-term-preview';
- }
-
- if ($row_position !== 0 && $row_position !== count($rows) - 1) {
- if ($row_position == $back_step - 1 || $row_position == $page_entries - $forward_step - 1) {
- $rows[$key]['class'][] = 'taxonomy-term-divider-top';
- }
- elseif ($row_position == $back_step || $row_position == $page_entries - $forward_step) {
- $rows[$key]['class'][] = 'taxonomy-term-divider-bottom';
- }
- }
-
- // Add an error class if this row contains a form error.
- foreach ($errors as $error_key => $error) {
- if (strpos($error_key, $key) === 0) {
- $rows[$key]['class'][] = 'error';
- }
- }
- $row_position++;
- }
-
- if (empty($rows)) {
- $rows[] = array(array('data' => $form['#empty_text'], 'colspan' => '3'));
- }
-
- $header = array(t('Name'), t('Weight'), t('Operations'));
- $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'taxonomy')));
- $output .= drupal_render_children($form);
- $output .= theme('pager');
-
- return $output;
-}
-
-/**
- * Form function for the term edit form.
- *
- * @ingroup forms
- * @see taxonomy_form_term_submit()
- */
-function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary = NULL) {
- // During initial form build, add the term entity to the form state for use
- // during form building and processing. During a rebuild, use what is in the
- // form state.
- if (!isset($form_state['term'])) {
- $term = is_object($edit) ? $edit : (object) $edit;
- if (!isset($vocabulary) && isset($term->vid)) {
- $vocabulary = taxonomy_vocabulary_load($term->vid);
- }
- $defaults = array(
- 'name' => '',
- 'description' => '',
- 'format' => NULL,
- 'vocabulary_machine_name' => isset($vocabulary) ? $vocabulary->machine_name : NULL,
- 'tid' => NULL,
- 'weight' => 0,
- );
- foreach ($defaults as $key => $value) {
- if (!isset($term->$key)) {
- $term->$key = $value;
- }
- }
- $form_state['term'] = $term;
- }
- else {
- $term = $form_state['term'];
- if (!isset($vocabulary) && isset($term->vid)) {
- $vocabulary = taxonomy_vocabulary_load($term->vid);
- }
- }
-
- $parent = array_keys(taxonomy_get_parents($term->tid));
- $form['#term'] = (array) $term;
- $form['#term']['parent'] = $parent;
- $form['#vocabulary'] = $vocabulary;
-
- // Check for confirmation forms.
- if (isset($form_state['confirm_delete'])) {
- return array_merge($form, taxonomy_term_confirm_delete($form, $form_state, $term->tid));
- }
-
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Name'),
- '#default_value' => $term->name,
- '#maxlength' => 255,
- '#required' => TRUE,
- '#weight' => -5,
- );
- $form['description'] = array(
- '#type' => 'text_format',
- '#title' => t('Description'),
- '#default_value' => $term->description,
- '#format' => $term->format,
- '#weight' => 0,
- );
-
- $form['vocabulary_machine_name'] = array(
- '#type' => 'value',
- '#value' => isset($term->vocabulary_machine_name) ? $term->vocabulary_machine_name : $vocabulary->name,
- );
-
- $langcode = entity_language('taxonomy_term', $term);
- field_attach_form('taxonomy_term', $term, $form, $form_state, $langcode);
-
- $form['relations'] = array(
- '#type' => 'fieldset',
- '#title' => t('Relations'),
- '#collapsible' => TRUE,
- '#collapsed' => $vocabulary->hierarchy < 2,
- '#weight' => 10,
- );
-
- // taxonomy_get_tree and taxonomy_get_parents may contain large numbers of
- // items so we check for taxonomy_override_selector before loading the
- // full vocabulary. Contrib modules can then intercept before
- // hook_form_alter to provide scalable alternatives.
- if (!variable_get('taxonomy_override_selector', FALSE)) {
- $parent = array_keys(taxonomy_get_parents($term->tid));
- $children = taxonomy_get_tree($vocabulary->vid, $term->tid);
-
- // A term can't be the child of itself, nor of its children.
- foreach ($children as $child) {
- $exclude[] = $child->tid;
- }
- $exclude[] = $term->tid;
-
- $tree = taxonomy_get_tree($vocabulary->vid);
- $options = array('<' . t('root') . '>');
- if (empty($parent)) {
- $parent = array(0);
- }
- foreach ($tree as $item) {
- if (!in_array($item->tid, $exclude)) {
- $options[$item->tid] = str_repeat('-', $item->depth) . $item->name;
- }
- }
- $form['relations']['parent'] = array(
- '#type' => 'select',
- '#title' => t('Parent terms'),
- '#options' => $options,
- '#default_value' => $parent,
- '#multiple' => TRUE,
- );
-
- }
- $form['relations']['weight'] = array(
- '#type' => 'textfield',
- '#title' => t('Weight'),
- '#size' => 6,
- '#default_value' => $term->weight,
- '#description' => t('Terms are displayed in ascending order by weight.'),
- '#required' => TRUE,
- );
- $form['vid'] = array(
- '#type' => 'value',
- '#value' => $vocabulary->vid,
- );
- $form['tid'] = array(
- '#type' => 'value',
- '#value' => $term->tid,
- );
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- '#weight' => 5,
- );
-
- if ($term->tid) {
- $form['actions']['delete'] = array(
- '#type' => 'submit',
- '#value' => t('Delete'),
- '#access' => user_access("delete terms in $vocabulary->vid") || user_access('administer taxonomy'),
- '#weight' => 10,
- );
- }
- else {
- $form_state['redirect'] = $_GET['q'];
- }
-
- return $form;
-}
-
-/**
- * Validation handler for the term form.
- *
- * @see taxonomy_form_term()
- */
-function taxonomy_form_term_validate($form, &$form_state) {
- entity_form_field_validate('taxonomy_term', $form, $form_state);
-
- // Ensure numeric values.
- if (isset($form_state['values']['weight']) && !is_numeric($form_state['values']['weight'])) {
- form_set_error('weight', t('Weight value must be numeric.'));
- }
-}
-
-/**
- * Submit handler to insert or update a term.
- *
- * @see taxonomy_form_term()
- */
-function taxonomy_form_term_submit($form, &$form_state) {
- 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);
- }
- // Rebuild the form to confirm term deletion.
- $form_state['rebuild'] = TRUE;
- $form_state['confirm_delete'] = TRUE;
- return;
- }
-
- $term = taxonomy_form_term_submit_build_taxonomy_term($form, $form_state);
-
- $status = taxonomy_term_save($term);
- switch ($status) {
- case SAVED_NEW:
- drupal_set_message(t('Created new term %term.', array('%term' => $term->name)));
- watchdog('taxonomy', 'Created new term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
- break;
- case SAVED_UPDATED:
- drupal_set_message(t('Updated term %term.', array('%term' => $term->name)));
- watchdog('taxonomy', 'Updated term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
- // Clear the page and block caches to avoid stale data.
- cache_clear_all();
- break;
- }
-
- $current_parent_count = count($form_state['values']['parent']);
- $previous_parent_count = count($form['#term']['parent']);
- // Root doesn't count if it's the only parent.
- if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) {
- $current_parent_count = 0;
- $form_state['values']['parent'] = array();
- }
-
- // If the number of parents has been reduced to one or none, do a check on the
- // parents of every term in the vocabulary value.
- if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
- taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
- }
- // If we've increased the number of parents and this is a single or flat
- // hierarchy, update the vocabulary immediately.
- elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
- $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
- taxonomy_vocabulary_save($form['#vocabulary']);
- }
-
- $form_state['values']['tid'] = $term->tid;
- $form_state['tid'] = $term->tid;
-}
-
-/**
- * Updates the form state's term entity by processing this submission's values.
- */
-function taxonomy_form_term_submit_build_taxonomy_term($form, &$form_state) {
- $term = $form_state['term'];
- entity_form_submit_build_entity('taxonomy_term', $term, $form, $form_state);
-
- // Convert text_format field into values expected by taxonomy_term_save().
- $description = $form_state['values']['description'];
- $term->description = $description['value'];
- $term->format = $description['format'];
- return $term;
-}
-
-/**
- * Form builder for the term delete form.
- *
- * @ingroup forms
- * @see taxonomy_term_confirm_delete_submit()
- */
-function taxonomy_term_confirm_delete($form, &$form_state, $tid) {
- $term = taxonomy_term_load($tid);
-
- // Always provide entity id in the same form key as in the entity edit form.
- $form['tid'] = array('#type' => 'value', '#value' => $tid);
-
- $form['#term'] = $term;
- $form['type'] = array('#type' => 'value', '#value' => 'term');
- $form['name'] = array('#type' => 'value', '#value' => $term->name);
- $form['vocabulary_machine_name'] = array('#type' => 'value', '#value' => $term->vocabulary_machine_name);
- $form['delete'] = array('#type' => 'value', '#value' => TRUE);
- return confirm_form($form,
- t('Are you sure you want to delete the term %title?',
- array('%title' => $term->name)),
- 'admin/structure/taxonomy',
- t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
- t('Delete'),
- t('Cancel'));
-}
-
-/**
- * Submit handler to delete a term after confirmation.
- *
- * @see taxonomy_term_confirm_delete()
- */
-function taxonomy_term_confirm_delete_submit($form, &$form_state) {
- taxonomy_term_delete($form_state['values']['tid']);
- taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
- drupal_set_message(t('Deleted term %name.', array('%name' => $form_state['values']['name'])));
- watchdog('taxonomy', 'Deleted term %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
- $form_state['redirect'] = 'admin/structure/taxonomy';
- cache_clear_all();
- return;
-}
-
-/**
- * Form builder for the vocabulary delete confirmation form.
- *
- * @ingroup forms
- * @see taxonomy_vocabulary_confirm_delete_submit()
- */
-function taxonomy_vocabulary_confirm_delete($form, &$form_state, $vid) {
- $vocabulary = taxonomy_vocabulary_load($vid);
-
- // Always provide entity id in the same form key as in the entity edit form.
- $form['vid'] = array('#type' => 'value', '#value' => $vid);
-
- $form['#vocabulary'] = $vocabulary;
- $form['#id'] = 'taxonomy_vocabulary_confirm_delete';
- $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
- $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
- $form['#submit'] = array('taxonomy_vocabulary_confirm_delete_submit');
- return confirm_form($form,
- t('Are you sure you want to delete the vocabulary %title?',
- array('%title' => $vocabulary->name)),
- 'admin/structure/taxonomy',
- t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
- t('Delete'),
- t('Cancel'));
-}
-
-/**
- * Submit handler to delete a vocabulary after confirmation.
- *
- * @see taxonomy_vocabulary_confirm_delete()
- */
-function taxonomy_vocabulary_confirm_delete_submit($form, &$form_state) {
- $status = taxonomy_vocabulary_delete($form_state['values']['vid']);
- drupal_set_message(t('Deleted vocabulary %name.', array('%name' => $form_state['values']['name'])));
- watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
- $form_state['redirect'] = 'admin/structure/taxonomy';
- cache_clear_all();
- return;
-}
-
-/**
- * Form builder to confirm resetting a vocabulary to alphabetical order.
- *
- * @ingroup forms
- * @see taxonomy_vocabulary_confirm_reset_alphabetical_submit()
- */
-function taxonomy_vocabulary_confirm_reset_alphabetical($form, &$form_state, $vid) {
- $vocabulary = taxonomy_vocabulary_load($vid);
-
- $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
- $form['vid'] = array('#type' => 'value', '#value' => $vid);
- $form['machine_name'] = array('#type' => 'value', '#value' => $vocabulary->machine_name);
- $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
- $form['reset_alphabetical'] = array('#type' => 'value', '#value' => TRUE);
- return confirm_form($form,
- t('Are you sure you want to reset the vocabulary %title to alphabetical order?',
- array('%title' => $vocabulary->name)),
- 'admin/structure/taxonomy/' . $vocabulary->machine_name,
- t('Resetting a vocabulary will discard all custom ordering and sort items alphabetically.'),
- t('Reset to alphabetical'),
- t('Cancel'));
-}
-
-/**
- * Submit handler to reset a vocabulary to alphabetical order after confirmation.
- *
- * @see taxonomy_vocabulary_confirm_reset_alphabetical()
- */
-function taxonomy_vocabulary_confirm_reset_alphabetical_submit($form, &$form_state) {
- db_update('taxonomy_term_data')
- ->fields(array('weight' => 0))
- ->condition('vid', $form_state['values']['vid'])
- ->execute();
- drupal_set_message(t('Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name'])));
- watchdog('taxonomy', 'Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
- $form_state['redirect'] = 'admin/structure/taxonomy/' . $form_state['values']['machine_name'];
-}
diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php
deleted file mode 100644
index b9c23dbf..00000000
--- a/modules/taxonomy/taxonomy.api.php
+++ /dev/null
@@ -1,231 +0,0 @@
-fields('m', array('vid', 'foo'))
- ->condition('m.vid', array_keys($vocabularies), 'IN')
- ->execute();
- foreach ($result as $record) {
- $vocabularies[$record->vid]->foo = $record->foo;
- }
-}
-
-/**
- * Act on taxonomy vocabularies before they are saved.
- *
- * Modules implementing this hook can act on the vocabulary object before it is
- * inserted or updated.
- *
- * @param $vocabulary
- * A taxonomy vocabulary object.
- */
-function hook_taxonomy_vocabulary_presave($vocabulary) {
- $vocabulary->foo = 'bar';
-}
-
-/**
- * Act on taxonomy vocabularies when inserted.
- *
- * Modules implementing this hook can act on the vocabulary object when saved
- * to the database.
- *
- * @param $vocabulary
- * A taxonomy vocabulary object.
- */
-function hook_taxonomy_vocabulary_insert($vocabulary) {
- if ($vocabulary->machine_name == 'my_vocabulary') {
- $vocabulary->weight = 100;
- }
-}
-
-/**
- * Act on taxonomy vocabularies when updated.
- *
- * Modules implementing this hook can act on the vocabulary object when updated.
- *
- * @param $vocabulary
- * A taxonomy vocabulary object.
- */
-function hook_taxonomy_vocabulary_update($vocabulary) {
- db_update('mytable')
- ->fields(array('foo' => $vocabulary->foo))
- ->condition('vid', $vocabulary->vid)
- ->execute();
-}
-
-/**
- * Respond to the deletion of taxonomy vocabularies.
- *
- * Modules implementing this hook can respond to the deletion of taxonomy
- * vocabularies from the database.
- *
- * @param $vocabulary
- * A taxonomy vocabulary object.
- */
-function hook_taxonomy_vocabulary_delete($vocabulary) {
- db_delete('mytable')
- ->condition('vid', $vocabulary->vid)
- ->execute();
-}
-
-/**
- * Act on taxonomy terms when loaded.
- *
- * Modules implementing this hook can act on the term objects returned by
- * taxonomy_term_load_multiple().
- *
- * For performance reasons, information to be added to term objects should be
- * loaded in a single query for all terms where possible.
- *
- * Since terms are stored and retrieved from cache during a page request, avoid
- * altering properties provided by the {taxonomy_term_data} table, since this
- * may affect the way results are loaded from cache in subsequent calls.
- *
- * @param $terms
- * An array of term objects, indexed by tid.
- */
-function hook_taxonomy_term_load($terms) {
- $result = db_select('mytable', 'm')
- ->fields('m', array('tid', 'foo'))
- ->condition('m.tid', array_keys($terms), 'IN')
- ->execute();
- foreach ($result as $record) {
- $terms[$record->tid]->foo = $record->foo;
- }
-}
-
-/**
- * Act on taxonomy terms before they are saved.
- *
- * Modules implementing this hook can act on the term object before it is
- * inserted or updated.
- *
- * @param $term
- * A term object.
- */
-function hook_taxonomy_term_presave($term) {
- $term->foo = 'bar';
-}
-
-/**
- * Act on taxonomy terms when inserted.
- *
- * Modules implementing this hook can act on the term object when saved to
- * the database.
- *
- * @param $term
- * A taxonomy term object.
- */
-function hook_taxonomy_term_insert($term) {
- db_insert('mytable')
- ->fields(array(
- 'tid' => $term->tid,
- 'foo' => $term->foo,
- ))
- ->execute();
-}
-
-/**
- * Act on taxonomy terms when updated.
- *
- * Modules implementing this hook can act on the term object when updated.
- *
- * @param $term
- * A taxonomy term object.
- */
-function hook_taxonomy_term_update($term) {
- db_update('mytable')
- ->fields(array('foo' => $term->foo))
- ->condition('tid', $term->tid)
- ->execute();
-}
-
-/**
- * Respond to the deletion of taxonomy terms.
- *
- * Modules implementing this hook can respond to the deletion of taxonomy
- * terms from the database.
- *
- * @param $term
- * A taxonomy term object.
- */
-function hook_taxonomy_term_delete($term) {
- db_delete('mytable')
- ->condition('tid', $term->tid)
- ->execute();
-}
-
-/**
- * Act on a taxonomy term that is being assembled before rendering.
- *
- * The module may add elements to $term->content prior to rendering. The
- * structure of $term->content is a renderable array as expected by
- * drupal_render().
- *
- * @param $term
- * The term that is being assembled for rendering.
- * @param $view_mode
- * The $view_mode parameter from taxonomy_term_view().
- * @param $langcode
- * The language code used for rendering.
- *
- * @see hook_entity_view()
- */
-function hook_taxonomy_term_view($term, $view_mode, $langcode) {
- $term->content['my_additional_field'] = array(
- '#markup' => $additional_field,
- '#weight' => 10,
- '#theme' => 'mymodule_my_additional_field',
- );
-}
-
-/**
- * Alter the results of taxonomy_term_view().
- *
- * This hook is called after the content has been assembled in a structured
- * array and may be used for doing processing which requires that the complete
- * taxonomy term content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the term rather than the
- * structured content array, it may use this hook to add a #post_render
- * callback. Alternatively, it could also implement
- * hook_preprocess_taxonomy_term(). See drupal_render() and theme()
- * documentation respectively for details.
- *
- * @param $build
- * A renderable array representing the node content.
- *
- * @see hook_entity_view_alter()
- */
-function hook_taxonomy_term_view_alter(&$build) {
- if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
- // Change its weight.
- $build['an_additional_field']['#weight'] = -10;
- }
-
- // Add a #post_render callback to act on the rendered HTML of the term.
- $build['#post_render'][] = 'my_module_node_post_render';
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/modules/taxonomy/taxonomy.css b/modules/taxonomy/taxonomy.css
deleted file mode 100644
index 36cd641b..00000000
--- a/modules/taxonomy/taxonomy.css
+++ /dev/null
@@ -1,13 +0,0 @@
-
-tr.taxonomy-term-preview {
- background-color: #EEE;
-}
-tr.taxonomy-term-divider-top {
- border-bottom: none;
-}
-tr.taxonomy-term-divider-bottom {
- border-top: 1px dotted #CCC;
-}
-.taxonomy-term-description {
- margin: 5px 0 20px;
-}
diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info
deleted file mode 100644
index 81e93f80..00000000
--- a/modules/taxonomy/taxonomy.info
+++ /dev/null
@@ -1,15 +0,0 @@
-name = Taxonomy
-description = Enables the categorization of content.
-package = Core
-version = VERSION
-core = 7.x
-dependencies[] = options
-files[] = taxonomy.module
-files[] = taxonomy.test
-configure = admin/structure/taxonomy
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install
deleted file mode 100644
index e3603e1a..00000000
--- a/modules/taxonomy/taxonomy.install
+++ /dev/null
@@ -1,917 +0,0 @@
-fetchCol();
- foreach ($vocabularies as $vocabulary) {
- field_attach_delete_bundle('taxonomy_term', $vocabulary);
- }
-}
-
-/**
- * Implements hook_schema().
- */
-function taxonomy_schema() {
- $schema['taxonomy_term_data'] = array(
- 'description' => 'Stores term information.',
- 'fields' => array(
- 'tid' => array(
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'description' => 'Primary Key: Unique term ID.',
- ),
- 'vid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The {taxonomy_vocabulary}.vid of the vocabulary to which the term is assigned.',
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The term name.',
- 'translatable' => TRUE,
- ),
- 'description' => array(
- 'type' => 'text',
- 'not null' => FALSE,
- 'size' => 'big',
- 'description' => 'A description of the term.',
- 'translatable' => TRUE,
- ),
- 'format' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the description.',
- ),
- 'weight' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of this term in relation to other terms.',
- ),
- ),
- 'primary key' => array('tid'),
- 'foreign keys' => array(
- 'vocabulary' => array(
- 'table' => 'taxonomy_vocabulary',
- 'columns' => array('vid' => 'vid'),
- ),
- ),
- 'indexes' => array(
- 'taxonomy_tree' => array('vid', 'weight', 'name'),
- 'vid_name' => array('vid', 'name'),
- 'name' => array('name'),
- ),
- );
-
- $schema['taxonomy_term_hierarchy'] = array(
- 'description' => 'Stores the hierarchical relationship between terms.',
- 'fields' => array(
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: The {taxonomy_term_data}.tid of the term.',
- ),
- 'parent' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => "Primary Key: The {taxonomy_term_data}.tid of the term's parent. 0 indicates no parent.",
- ),
- ),
- 'indexes' => array(
- 'parent' => array('parent'),
- ),
- 'foreign keys' => array(
- 'taxonomy_term_data' => array(
- 'table' => 'taxonomy_term_data',
- 'columns' => array('tid' => 'tid'),
- ),
- ),
- 'primary key' => array('tid', 'parent'),
- );
-
- $schema['taxonomy_vocabulary'] = array(
- 'description' => 'Stores vocabulary information.',
- 'fields' => array(
- 'vid' => array(
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'description' => 'Primary Key: Unique vocabulary ID.',
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Name of the vocabulary.',
- 'translatable' => TRUE,
- ),
- 'machine_name' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The vocabulary machine name.',
- ),
- 'description' => array(
- 'type' => 'text',
- 'not null' => FALSE,
- 'size' => 'big',
- 'description' => 'Description of the vocabulary.',
- 'translatable' => TRUE,
- ),
- 'hierarchy' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'size' => 'tiny',
- 'description' => 'The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)',
- ),
- 'module' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The module which created the vocabulary.',
- ),
- 'weight' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of this vocabulary in relation to other vocabularies.',
- ),
- ),
- 'primary key' => array('vid'),
- 'indexes' => array(
- 'list' => array('weight', 'name'),
- ),
- 'unique keys' => array(
- 'machine_name' => array('machine_name'),
- ),
- );
-
- $schema['taxonomy_index'] = array(
- 'description' => 'Maintains denormalized information about node/term relationships.',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'tid' => array(
- 'description' => 'The term ID.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'sticky' => array(
- 'description' => 'Boolean indicating whether the node is sticky.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'created' => array(
- 'description' => 'The Unix timestamp when the node was created.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default'=> 0,
- ),
- ),
- 'indexes' => array(
- 'term_node' => array('tid', 'sticky', 'created'),
- 'nid' => array('nid'),
- ),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- 'term' => array(
- 'table' => 'taxonomy_term_data',
- 'columns' => array('tid' => 'tid'),
- ),
- ),
- );
-
- return $schema;
-}
-
-/**
- * Implements hook_field_schema().
- */
-function taxonomy_field_schema($field) {
- return array(
- 'columns' => array(
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- ),
- ),
- 'indexes' => array(
- 'tid' => array('tid'),
- ),
- 'foreign keys' => array(
- 'tid' => array(
- 'table' => 'taxonomy_term_data',
- 'columns' => array('tid' => 'tid'),
- ),
- ),
- );
-}
-
-/**
- * Implements hook_update_dependencies().
- */
-function taxonomy_update_dependencies() {
- // taxonomy_update_7004() migrates taxonomy term data to fields and therefore
- // must run after all Field modules have been enabled, which happens in
- // system_update_7027().
- $dependencies['taxonomy'][7004] = array(
- 'system' => 7027,
- );
-
- return $dependencies;
-}
-
-/**
- * Utility function: get the list of vocabularies directly from the database.
- *
- * This function is valid for a database schema version 7002.
- *
- * @ingroup update_api
- */
-function _update_7002_taxonomy_get_vocabularies() {
- return db_query('SELECT v.* FROM {taxonomy_vocabulary} v ORDER BY v.weight, v.name')->fetchAllAssoc('vid', PDO::FETCH_OBJ);
-}
-
-/**
- * Rename taxonomy tables.
- */
-function taxonomy_update_7001() {
- db_rename_table('term_data', 'taxonomy_term_data');
- db_rename_table('term_hierarchy', 'taxonomy_term_hierarchy');
- db_rename_table('term_node', 'taxonomy_term_node');
- db_rename_table('term_relation', 'taxonomy_term_relation');
- db_rename_table('term_synonym', 'taxonomy_term_synonym');
- db_rename_table('vocabulary', 'taxonomy_vocabulary');
- db_rename_table('vocabulary_node_types', 'taxonomy_vocabulary_node_type');
-}
-
-/**
- * Add {vocabulary}.machine_name column.
- */
-function taxonomy_update_7002() {
- $field = array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The vocabulary machine name.',
- );
-
- db_add_field('taxonomy_vocabulary', 'machine_name', $field);
-
- // Do a direct query here, rather than calling taxonomy_get_vocabularies(),
- // in case Taxonomy module is disabled.
- $vids = db_query('SELECT vid FROM {taxonomy_vocabulary}')->fetchCol();
- foreach ($vids as $vid) {
- $machine_name = 'vocabulary_' . $vid;
- db_update('taxonomy_vocabulary')
- ->fields(array('machine_name' => $machine_name))
- ->condition('vid', $vid)
- ->execute();
- }
-
- // The machine_name unique key can only be added after we ensure the
- // machine_name column contains unique values.
- db_add_unique_key('taxonomy_vocabulary', 'machine_name', array('machine_name'));
-}
-
-/**
- * Remove the related terms setting from vocabularies.
- *
- * This setting has not been used since Drupal 6. The {taxonomy_relations} table
- * itself is retained to allow for data to be upgraded.
- */
-function taxonomy_update_7003() {
- db_drop_field('taxonomy_vocabulary', 'relations');
-}
-
-/**
- * Move taxonomy vocabulary associations for nodes to fields and field instances.
- */
-function taxonomy_update_7004() {
- $taxonomy_index = array(
- 'description' => 'Maintains denormalized information about node/term relationships.',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'tid' => array(
- 'description' => 'The term ID.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'sticky' => array(
- 'description' => 'Boolean indicating whether the node is sticky.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'created' => array(
- 'description' => 'The Unix timestamp when the node was created.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default'=> 0,
- ),
- ),
- 'indexes' => array(
- 'term_node' => array('tid', 'sticky', 'created'),
- 'nid' => array('nid'),
- ),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- 'term' => array(
- 'table' => 'taxonomy_term_data',
- 'columns' => array('tid' => 'tid'),
- ),
- ),
- );
- db_create_table('taxonomy_index', $taxonomy_index);
-
- // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
- // we can no longer rely on $vocabulary->nodes from the API function.
- $result = db_query('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid ORDER BY v.weight, v.name');
- $vocabularies = array();
- foreach ($result as $record) {
- // If no node types are associated with a vocabulary, the LEFT JOIN will
- // return a NULL value for type.
- if (isset($record->type)) {
- $node_types[$record->vid][$record->type] = $record->type;
- unset($record->type);
- $record->nodes = $node_types[$record->vid];
- }
- elseif (!isset($record->nodes)) {
- $record->nodes = array();
- }
- $vocabularies[$record->vid] = $record;
- }
-
- foreach ($vocabularies as $vocabulary) {
- $field_name = 'taxonomy_' . $vocabulary->machine_name;
- $field = array(
- 'field_name' => $field_name,
- 'module' => 'taxonomy',
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => $vocabulary->multiple || $vocabulary->tags ? FIELD_CARDINALITY_UNLIMITED : 1,
- 'settings' => array(
- 'required' => $vocabulary->required ? TRUE : FALSE,
- 'allowed_values' => array(
- array(
- 'vocabulary' => $vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- _update_7000_field_create_field($field);
-
- foreach ($vocabulary->nodes as $bundle) {
- $instance = array(
- 'label' => $vocabulary->name,
- 'field_name' => $field_name,
- 'bundle' => $bundle,
- 'entity_type' => 'node',
- 'settings' => array(),
- 'description' => $vocabulary->help,
- 'required' => $vocabulary->required,
- 'widget' => array(),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- 'teaser' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- ),
- );
- if ($vocabulary->tags) {
- $instance['widget'] = array(
- 'type' => 'taxonomy_autocomplete',
- 'module' => 'taxonomy',
- 'settings' => array(
- 'size' => 60,
- 'autocomplete_path' => 'taxonomy/autocomplete',
- ),
- );
- }
- else {
- $instance['widget'] = array(
- 'type' => 'select',
- 'module' => 'options',
- 'settings' => array(),
- );
- }
- _update_7000_field_create_instance($field, $instance);
- }
- }
-
- // Some contrib projects stored term node associations without regard for the
- // selections in the taxonomy_vocabulary_node_types table, or have more terms
- // for a single node than the vocabulary allowed. We construct the
- // taxonomyextra field to store all the extra stuff.
-
- // Allowed values for this extra vocabs field is every vocabulary.
- $allowed_values = array();
- foreach (_update_7002_taxonomy_get_vocabularies() as $vocabulary) {
- $allowed_values[] = array(
- 'vocabulary' => $vocabulary->machine_name,
- 'parent' => 0,
- );
- }
-
- $field_name = 'taxonomyextra';
- $field = array(
- 'field_name' => $field_name,
- 'module' => 'taxonomy',
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'required' => FALSE,
- 'allowed_values' => $allowed_values,
- ),
- );
- _update_7000_field_create_field($field);
-
- foreach (_update_7000_node_get_types() as $bundle) {
- $instance = array(
- 'label' => 'Taxonomy upgrade extras',
- 'field_name' => $field_name,
- 'entity_type' => 'node',
- 'bundle' => $bundle->type,
- 'settings' => array(),
- 'description' => 'Debris left over after upgrade from Drupal 6',
- 'widget' => array(
- 'type' => 'taxonomy_autocomplete',
- 'module' => 'taxonomy',
- 'settings' => array(),
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- 'teaser' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- ),
- );
- _update_7000_field_create_instance($field, $instance);
- }
-
- $fields = array('help', 'multiple', 'required', 'tags');
- foreach ($fields as $field) {
- db_drop_field('taxonomy_vocabulary', $field);
- }
-}
-
-/**
- * Migrate {taxonomy_term_node} table to field storage.
- *
- * @todo: This function can possibly be made much faster by wrapping a
- * transaction around all the inserts.
- */
-function taxonomy_update_7005(&$sandbox) {
- // $sandbox contents:
- // - total: The total number of term_node relationships to migrate.
- // - count: The number of term_node relationships that have been
- // migrated so far.
- // - last: The db_query_range() offset to use when querying
- // term_node; this field is incremented in quantities of $batch
- // (1000) but at the end of each call to this function, last and
- // count are the same.
- // - vocabularies: An associative array mapping vocabulary id and node
- // type to field name. If a voc id/node type pair does not appear
- // in this array but a term_node relationship exists mapping a
- // term in voc id to node of that type, the relationship is
- // assigned to the taxonomymyextra field which allows terms of all
- // vocabularies.
- // - cursor[values], cursor[deltas]: The contents of $values and
- // $deltas at the end of the previous call to this function. These
- // need to be preserved across calls because a single batch of
- // 1000 rows from term_node may end in the middle of the terms for
- // a single node revision.
- //
- // $values is the array of values about to be/most recently inserted
- // into the SQL data table for the taxonomy_term_reference
- // field. Before $values is constructed for each record, the
- // $values from the previous insert is checked to see if the two
- // records are for the same node revision id; this enables knowing
- // when to reset the delta counters which are incremented across all
- // terms for a single field on a single revision, but reset for each
- // new field and revision.
- //
- // $deltas is an associative array mapping field name to the number
- // of term references stored so far for the current revision, which
- // provides the delta value for each term reference data insert. The
- // deltas are reset for each new revision.
-
- $conditions = array(
- 'type' => 'taxonomy_term_reference',
- 'deleted' => 0,
- );
- $field_info = _update_7000_field_read_fields($conditions, 'field_name');
-
- // This is a multi-pass update. On the first call we need to initialize some
- // variables.
- if (!isset($sandbox['total'])) {
- $sandbox['last'] = 0;
- $sandbox['count'] = 0;
-
- // Run the same joins as the query that is used later to retrieve the
- // term_node data, this ensures that bad records in that table - for
- // tids which aren't in taxonomy_term_data or nids which aren't in {node}
- // are not included in the count.
- $sandbox['total'] = db_query('SELECT COUNT(*) FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid INNER JOIN {node} n ON tn.nid = n.nid LEFT JOIN {node} n2 ON tn.vid = n2.vid')->fetchField();
-
- // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since
- // we can no longer rely on $vocabulary->nodes from the API function.
- $result = db_query('SELECT v.vid, v.machine_name, n.type FROM {taxonomy_vocabulary} v INNER JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid');
- $vocabularies = array();
- foreach ($result as $record) {
-
- // If no node types are associated with a vocabulary, the LEFT JOIN will
- // return a NULL value for type.
- if (isset($record->type)) {
- $vocabularies[$record->vid][$record->type] = 'taxonomy_'. $record->machine_name;
- }
- }
-
- if (!empty($vocabularies)) {
- $sandbox['vocabularies'] = $vocabularies;
- }
-
- db_create_table('taxonomy_update_7005', array(
- 'description' => 'Stores temporary data for taxonomy_update_7005.',
- 'fields' => array(
- 'n' => array(
- 'description' => 'Preserve order.',
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'vocab_id' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'tid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'nid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'vid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- 'default' => NULL,
- ),
- 'type' => array(
- 'type' => 'varchar',
- 'length' => 32,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'created' => array(
- 'type' => 'int',
- 'not null' => FALSE,
- ),
- 'sticky' => array(
- 'type' => 'int',
- 'not null' => FALSE,
- ),
- 'status' => array(
- 'type' => 'int',
- 'not null' => FALSE,
- ),
- 'is_current' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- ),
- ),
- 'primary key' => array('n'),
- ));
-
- // Query selects all revisions at once and processes them in revision and
- // term weight order.
- $query = db_select('taxonomy_term_data', 'td');
- // We are migrating term-node relationships. If there are none for a
- // term, we do not need the term_data row.
- $query->join('taxonomy_term_node', 'tn', 'td.tid = tn.tid');
- // If a term-node relationship exists for a nid that does not exist, we
- // cannot migrate it as we have no node to relate it to; thus we do not
- // need that row from term_node.
- $query->join('node', 'n', 'tn.nid = n.nid');
- // If the current term-node relationship is for the current revision of
- // the node, this left join will match and is_current will be non-NULL
- // (we also get the current sticky and created in this case). This
- // tells us whether to insert into the current data tables in addition
- // to the revision data tables.
- $query->leftJoin('node', 'n2', 'tn.vid = n2.vid');
- $query->addField('td', 'vid', 'vocab_id');
- $query->addField('td', 'tid');
- $query->addField('tn', 'nid');
- $query->addField('tn', 'vid');
- $query->addField('n', 'type');
- $query->addField('n2', 'created');
- $query->addField('n2', 'sticky');
- $query->addField('n2', 'status');
- $query->addField('n2', 'nid', 'is_current');
- // This query must return a consistent ordering across multiple calls.
- // We need them ordered by node vid (since we use that to decide when
- // to reset the delta counters) and by term weight so they appear
- // within each node in weight order. However, tn.vid,td.weight is not
- // guaranteed to be unique, so we add tn.tid as an additional sort key
- // because tn.tid,tn.vid is the primary key of the D6 term_node table
- // and so is guaranteed unique. Unfortunately it also happens to be in
- // the wrong order which is less efficient, but c'est la vie.
- $query->orderBy('tn.vid');
- $query->orderBy('td.weight');
- $query->orderBy('tn.tid');
-
- // Work around a bug in the PostgreSQL driver that would result in fatal
- // errors when this subquery is used in the insert query below. See
- // https://drupal.org/node/2057693.
- $fields = &$query->getFields();
- unset($fields['td.weight']);
- unset($fields['tn.tid']);
-
- db_insert('taxonomy_update_7005')
- ->from($query)
- ->execute();
- }
- else {
- // We do each pass in batches of 1000.
- $batch = 1000;
-
- $result = db_query_range('SELECT vocab_id, tid, nid, vid, type, created, sticky, status, is_current FROM {taxonomy_update_7005} ORDER BY n', $sandbox['last'], $batch);
- if (isset($sandbox['cursor'])) {
- $values = $sandbox['cursor']['values'];
- $deltas = $sandbox['cursor']['deltas'];
- }
- else {
- $deltas = array();
- }
- foreach ($result as $record) {
- $sandbox['count'] += 1;
-
- // Use the valid field for this vocabulary and node type or use the
- // overflow vocabulary if there is no valid field.
- $field_name = isset($sandbox['vocabularies'][$record->vocab_id][$record->type]) ? $sandbox['vocabularies'][$record->vocab_id][$record->type] : 'taxonomyextra';
- $field = $field_info[$field_name];
-
- // Start deltas from 0, and increment by one for each term attached to a
- // node.
- if (!isset($deltas[$field_name])) {
- $deltas[$field_name] = 0;
- }
-
- if (isset($values)) {
-
- // If the last inserted revision_id is the same as the current record,
- // use the previous deltas to calculate the next delta.
- if ($record->vid == $values[2]) {
-
- // For limited cardinality fields, the delta must not be allowed to
- // exceed the cardinality during the update. So ensure that the
- // delta about to be inserted is within this limit.
- // @see field_default_validate().
- if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ($deltas[$field_name] + 1) > $field['cardinality']) {
-
- // For excess values of a single-term vocabulary, switch over to
- // the overflow field.
- $field_name = 'taxonomyextra';
- $field = $field_info[$field_name];
- if (!isset($deltas[$field_name])) {
- $deltas[$field_name] = 0;
- }
- }
- }
- else {
-
- // When the record is a new revision, empty the deltas array.
- $deltas = array($field_name => 0);
- }
- }
-
- // Table and column found in the field's storage details. During upgrades,
- // it's always SQL.
- $table_name = "field_data_{$field_name}";
- $revision_name = "field_revision_{$field_name}";
- $value_column = $field_name . '_tid';
-
- // Column names and values in field storage are the same for current and
- // revision.
- $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column);
- $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid);
-
- // Insert rows into the revision table.
- db_insert($revision_name)->fields($columns)->values($values)->execute();
-
- // is_current column is a node ID if this revision is also current.
- if ($record->is_current) {
- db_insert($table_name)->fields($columns)->values($values)->execute();
- // Only insert a record in the taxonomy index if the node is published.
- if ($record->status) {
- // Update the {taxonomy_index} table.
- db_insert('taxonomy_index')
- ->fields(array('nid', 'tid', 'sticky', 'created',))
- ->values(array($record->nid, $record->tid, $record->sticky, $record->created))
- ->execute();
- }
- }
- }
-
- // Store the set of inserted values and the current revision's deltas in the
- // sandbox.
- $sandbox['cursor'] = array(
- 'values' => $values,
- 'deltas' => $deltas,
- );
- $sandbox['last'] += $batch;
- }
-
- if ($sandbox['count'] < $sandbox['total']) {
- $sandbox['#finished'] = FALSE;
- }
- else {
- db_drop_table('taxonomy_vocabulary_node_type');
- db_drop_table('taxonomy_term_node');
-
- // If there are no vocabs, we're done.
- db_drop_table('taxonomy_update_7005');
- $sandbox['#finished'] = TRUE;
-
- // Determine necessity of taxonomyextras field.
- $field = $field_info['taxonomyextra'];
- $revision_name = 'field_revision_' . $field['field_name'];
- $node_types = db_select($revision_name)->distinct()->fields($revision_name, array('bundle'))
- ->execute()->fetchCol();
-
- if (empty($node_types)) {
- // Delete the overflow field if there are no rows in the revision table.
- _update_7000_field_delete_field('taxonomyextra');
- }
- else {
- // Remove instances which are not actually used.
- $bundles = db_query('SELECT bundle FROM {field_config_instance} WHERE field_name = :field_name', array(':field_name' => 'taxonomyextra'))->fetchCol();
- $bundles = array_diff($bundles, $node_types);
- foreach ($bundles as $bundle) {
- _update_7000_field_delete_instance('taxonomyextra', 'node', $bundle);
- }
- }
- }
-}
-
-/**
- * Add {taxonomy_term_data}.format column.
- */
-function taxonomy_update_7006() {
- db_add_field('taxonomy_term_data', 'format', array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the description.',
- ));
-}
-
-/**
- * Add index on {taxonomy_term_data}.name column to speed up taxonomy_get_term_by_name().
- */
-function taxonomy_update_7007() {
- db_add_index('taxonomy_term_data', 'name', array('name'));
-}
-
-/**
- * Change the weight columns to normal int.
- */
-function taxonomy_update_7008() {
- db_drop_index('taxonomy_term_data', 'taxonomy_tree');
- db_change_field('taxonomy_term_data', 'weight', 'weight', array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of this term in relation to other terms.',
- ), array(
- 'indexes' => array(
- 'taxonomy_tree' => array('vid', 'weight', 'name'),
- ),
- ));
-
- db_drop_index('taxonomy_vocabulary', 'list');
- db_change_field('taxonomy_vocabulary', 'weight', 'weight', array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of this vocabulary in relation to other vocabularies.',
- ), array(
- 'indexes' => array(
- 'list' => array('weight', 'name'),
- ),
- ));
-}
-
-/**
- * Change {taxonomy_term_data}.format into varchar.
- */
-function taxonomy_update_7009() {
- db_change_field('taxonomy_term_data', 'format', 'format', array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the description.',
- ));
-}
-
-/**
- * Change {taxonomy_index}.created to support signed int.
-*/
-function taxonomy_update_7010() {
- db_change_field('taxonomy_index', 'created', 'created', array(
- 'description' => 'The Unix timestamp when the node was created.',
- 'type' => 'int',
- 'unsigned' => FALSE,
- 'not null' => TRUE,
- 'default'=> 0,
- ));
-}
-
-/**
- * @addtogroup updates-7.x-extra
- * @{
- */
-
-/**
- * Drop unpublished nodes from the index.
- */
-function taxonomy_update_7011() {
- $nids = db_query('SELECT nid from {node} WHERE status = :status', array(':status' => NODE_NOT_PUBLISHED))->fetchCol();
- if (!empty($nids)) {
- db_delete('taxonomy_index')
- ->condition('nid', $nids)
- ->execute();
- }
-}
-
-/**
- * @} End of "addtogroup updates-7.x-extra".
- */
diff --git a/modules/taxonomy/taxonomy.js b/modules/taxonomy/taxonomy.js
deleted file mode 100644
index 1a0c7908..00000000
--- a/modules/taxonomy/taxonomy.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function ($) {
-
-/**
- * Move a block in the blocks table from one region to another via select list.
- *
- * This behavior is dependent on the tableDrag behavior, since it uses the
- * objects initialized in that behavior to update the row.
- */
-Drupal.behaviors.termDrag = {
- attach: function (context, settings) {
- var table = $('#taxonomy', context);
- var tableDrag = Drupal.tableDrag.taxonomy; // Get the blocks tableDrag object.
- var rows = $('tr', table).length;
-
- // When a row is swapped, keep previous and next page classes set.
- tableDrag.row.prototype.onSwap = function (swappedRow) {
- $('tr.taxonomy-term-preview', table).removeClass('taxonomy-term-preview');
- $('tr.taxonomy-term-divider-top', table).removeClass('taxonomy-term-divider-top');
- $('tr.taxonomy-term-divider-bottom', table).removeClass('taxonomy-term-divider-bottom');
-
- if (settings.taxonomy.backStep) {
- for (var n = 0; n < settings.taxonomy.backStep; n++) {
- $(table[0].tBodies[0].rows[n]).addClass('taxonomy-term-preview');
- }
- $(table[0].tBodies[0].rows[settings.taxonomy.backStep - 1]).addClass('taxonomy-term-divider-top');
- $(table[0].tBodies[0].rows[settings.taxonomy.backStep]).addClass('taxonomy-term-divider-bottom');
- }
-
- if (settings.taxonomy.forwardStep) {
- for (var n = rows - settings.taxonomy.forwardStep - 1; n < rows - 1; n++) {
- $(table[0].tBodies[0].rows[n]).addClass('taxonomy-term-preview');
- }
- $(table[0].tBodies[0].rows[rows - settings.taxonomy.forwardStep - 2]).addClass('taxonomy-term-divider-top');
- $(table[0].tBodies[0].rows[rows - settings.taxonomy.forwardStep - 1]).addClass('taxonomy-term-divider-bottom');
- }
- };
- }
-};
-
-})(jQuery);
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
deleted file mode 100644
index 7ad28e9f..00000000
--- a/modules/taxonomy/taxonomy.module
+++ /dev/null
@@ -1,2048 +0,0 @@
-' . t('About') . '';
- $output .= '' . t('The Taxonomy module allows you to classify the content of your website. To classify content, you define vocabularies that contain related terms , and then assign the vocabularies to content types. For more information, see the online handbook entry for the Taxonomy module .', array('@taxonomy' => 'http://drupal.org/documentation/modules/taxonomy/')) . '
';
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Creating vocabularies') . ' ';
- $output .= '' . t('Users with sufficient permissions can create vocabularies and terms through the Taxonomy page . The page listing the terms provides a drag-and-drop interface for controlling the order of the terms and sub-terms within a vocabulary, in a hierarchical fashion. A controlled vocabulary classifying music by genre with terms and sub-terms could look as follows:', array('@taxo' => url('admin/structure/taxonomy'), '@perm' => url('admin/people/permissions', array('fragment'=>'module-taxonomy'))));
- $output .= '' . t('vocabulary : Music') . ' ';
- $output .= '' . t('term : Jazz') . ' ';
- $output .= '' . t('sub-term : Swing') . ' ';
- $output .= '' . t('sub-term : Fusion') . ' ';
- $output .= '' . t('term : Rock') . ' ';
- $output .= '' . t('sub-term : Country rock') . ' ';
- $output .= '' . t('sub-term : Hard rock') . ' ';
- $output .= t('You can assign a sub-term to multiple parent terms. For example, fusion can be assigned to both rock and jazz .') . ' ';
- $output .= '' . t('Terms in a free-tagging vocabulary can be built gradually as you create or edit content. This is often done used for blogs or photo management applications.') . ' ';
- $output .= '' . t('Assigning vocabularies to content types') . ' ';
- $output .= '' . t('Before you can use a new vocabulary to classify your content, a new Taxonomy term field must be added to a content type on its manage fields page. When adding a taxonomy field, you choose a widget to use to enter the taxonomy information on the content editing page: a select list, checkboxes, radio buttons, or an auto-complete field (to build a free-tagging vocabulary). After choosing the field type and widget, on the subsequent field settings page you can choose the desired vocabulary, whether one or multiple terms can be chosen from the vocabulary, and other settings. The same vocabulary can be added to multiple content types, by using the "Add existing field" section on the manage fields page.', array('@ctedit' => url('admin/structure/types'))) . ' ';
- $output .= '' . t('Classifying content') . ' ';
- $output .= '' . t('After the vocabulary is assigned to the content type, you can start classifying content. The field with terms will appear on the content editing screen when you edit or add new content .', array('@addnode' => url('node/add'))) . ' ';
- $output .= '' . t('Viewing listings and RSS feeds by term') . ' ';
- $output .= '' . t("Each taxonomy term automatically provides a page listing content that has its classification, and a corresponding RSS feed. For example, if the taxonomy term country rock has the ID 123 (you can see this by looking at the URL when hovering on the linked term, which you can click to navigate to the listing page), then you will find this list at the path taxonomy/term/123 . The RSS feed will use the path taxonomy/term/123/feed (the RSS icon for this term's listing will automatically display in your browser's address bar when viewing the listing page).") . ' ';
- $output .= '' . t('Extending Taxonomy module') . ' ';
- $output .= '' . t('There are many contributed modules that extend the behavior of the Taxonomy module for both display and organization of terms.', array('@taxcontrib' => 'http://drupal.org/project/modules?filters=tid:71&solrsort=sis_project_release_usage%20desc'));
- $output .= ' ';
- return $output;
- case 'admin/structure/taxonomy':
- $output = '' . t('Taxonomy is for categorizing content. Terms are grouped into vocabularies. For example, a vocabulary called "Fruit" would contain the terms "Apple" and "Banana".') . '
';
- return $output;
- case 'admin/structure/taxonomy/%':
- $vocabulary = taxonomy_vocabulary_machine_name_load($arg[3]);
- switch ($vocabulary->hierarchy) {
- case 0:
- return '' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '
';
- case 1:
- return '' . t('%capital_name contains terms grouped under parent terms. You can reorganize the terms in %capital_name using their drag-and-drop handles.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '
';
- case 2:
- return '' . t('%capital_name contains terms with multiple parents. Drag and drop of terms with multiple parents is not supported, but you can re-enable drag-and-drop support by editing each term to include only a single parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) . '
';
- }
- }
-}
-
-/**
- * Implements hook_permission().
- */
-function taxonomy_permission() {
- $permissions = array(
- 'administer taxonomy' => array(
- 'title' => t('Administer vocabularies and terms'),
- ),
- );
- foreach (taxonomy_get_vocabularies() as $vocabulary) {
- $permissions += array(
- 'edit terms in ' . $vocabulary->vid => array(
- 'title' => t('Edit terms in %vocabulary', array('%vocabulary' => $vocabulary->name)),
- ),
- );
- $permissions += array(
- 'delete terms in ' . $vocabulary->vid => array(
- 'title' => t('Delete terms from %vocabulary', array('%vocabulary' => $vocabulary->name)),
- ),
- );
- }
- return $permissions;
-}
-
-/**
- * Implements hook_entity_info().
- */
-function taxonomy_entity_info() {
- $return = array(
- 'taxonomy_term' => array(
- 'label' => t('Taxonomy term'),
- 'controller class' => 'TaxonomyTermController',
- 'base table' => 'taxonomy_term_data',
- 'uri callback' => 'taxonomy_term_uri',
- 'fieldable' => TRUE,
- 'entity keys' => array(
- 'id' => 'tid',
- 'bundle' => 'vocabulary_machine_name',
- 'label' => 'name',
- ),
- 'bundle keys' => array(
- 'bundle' => 'machine_name',
- ),
- 'bundles' => array(),
- 'view modes' => array(
- // @todo View mode for display as a field (when attached to nodes etc).
- 'full' => array(
- 'label' => t('Taxonomy term page'),
- 'custom settings' => FALSE,
- ),
- ),
- ),
- );
- foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
- $return['taxonomy_term']['bundles'][$machine_name] = array(
- 'label' => $vocabulary->name,
- 'admin' => array(
- 'path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name',
- 'real path' => 'admin/structure/taxonomy/' . $machine_name,
- 'bundle argument' => 3,
- 'access arguments' => array('administer taxonomy'),
- ),
- );
- }
- $return['taxonomy_vocabulary'] = array(
- 'label' => t('Taxonomy vocabulary'),
- 'controller class' => 'TaxonomyVocabularyController',
- 'base table' => 'taxonomy_vocabulary',
- 'entity keys' => array(
- 'id' => 'vid',
- 'label' => 'name',
- ),
- 'fieldable' => FALSE,
- );
-
- return $return;
-}
-
-/**
- * Implements callback_entity_info_uri().
- */
-function taxonomy_term_uri($term) {
- return array(
- 'path' => 'taxonomy/term/' . $term->tid,
- );
-}
-
-/**
- * Implements hook_field_extra_fields().
- */
-function taxonomy_field_extra_fields() {
- $return = array();
- $info = entity_get_info('taxonomy_term');
- foreach (array_keys($info['bundles']) as $bundle) {
- $return['taxonomy_term'][$bundle] = array(
- 'form' => array(
- 'name' => array(
- 'label' => t('Name'),
- 'description' => t('Term name textfield'),
- 'weight' => -5,
- ),
- 'description' => array(
- 'label' => t('Description'),
- 'description' => t('Term description textarea'),
- 'weight' => 0,
- ),
- ),
- 'display' => array(
- 'description' => array(
- 'label' => t('Description'),
- 'description' => t('Term description'),
- 'weight' => 0,
- ),
- ),
- );
- }
-
- return $return;
-}
-
-/**
- * Return nodes attached to a term across all field instances.
- *
- * This function requires taxonomy module to be maintaining its own tables,
- * and will return an empty array if it is not. If using other field storage
- * methods alternatives methods for listing terms will need to be used.
- *
- * @param $tid
- * The term ID.
- * @param $pager
- * Boolean to indicate whether a pager should be used.
- * @param $limit
- * Integer. The maximum number of nodes to find.
- * Set to FALSE for no limit.
- * @param $order
- * An array of fields and directions.
- *
- * @return
- * An array of nids matching the query.
- */
-function taxonomy_select_nodes($tid, $pager = TRUE, $limit = FALSE, $order = array('t.sticky' => 'DESC', 't.created' => 'DESC')) {
- if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
- return array();
- }
- $query = db_select('taxonomy_index', 't');
- $query->addTag('node_access');
- $query->condition('tid', $tid);
- if ($pager) {
- $count_query = clone $query;
- $count_query->addExpression('COUNT(t.nid)');
-
- $query = $query->extend('PagerDefault');
- if ($limit !== FALSE) {
- $query = $query->limit($limit);
- }
- $query->setCountQuery($count_query);
- }
- else {
- if ($limit !== FALSE) {
- $query->range(0, $limit);
- }
- }
- $query->addField('t', 'nid');
- $query->addField('t', 'tid');
- foreach ($order as $field => $direction) {
- $query->orderBy($field, $direction);
- // ORDER BY fields need to be loaded too, assume they are in the form
- // table_alias.name
- list($table_alias, $name) = explode('.', $field);
- $query->addField($table_alias, $name);
- }
- return $query->execute()->fetchCol();
-}
-
-/**
- * Implements hook_theme().
- */
-function taxonomy_theme() {
- return array(
- 'taxonomy_overview_vocabularies' => array(
- 'render element' => 'form',
- ),
- 'taxonomy_overview_terms' => array(
- 'render element' => 'form',
- ),
- 'taxonomy_term' => array(
- 'render element' => 'elements',
- 'template' => 'taxonomy-term',
- ),
- );
-}
-
-/**
- * Implements hook_menu().
- */
-function taxonomy_menu() {
- $items['admin/structure/taxonomy'] = array(
- 'title' => 'Taxonomy',
- 'description' => 'Manage tagging, categorization, and classification of your content.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_overview_vocabularies'),
- 'access arguments' => array('administer taxonomy'),
- 'file' => 'taxonomy.admin.inc',
- );
- $items['admin/structure/taxonomy/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- $items['admin/structure/taxonomy/add'] = array(
- 'title' => 'Add vocabulary',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_form_vocabulary'),
- 'access arguments' => array('administer taxonomy'),
- 'type' => MENU_LOCAL_ACTION,
- 'file' => 'taxonomy.admin.inc',
- );
-
- $items['taxonomy/term/%taxonomy_term'] = array(
- 'title' => 'Taxonomy term',
- 'title callback' => 'taxonomy_term_title',
- 'title arguments' => array(2),
- 'page callback' => 'taxonomy_term_page',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'file' => 'taxonomy.pages.inc',
- );
- $items['taxonomy/term/%taxonomy_term/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['taxonomy/term/%taxonomy_term/edit'] = array(
- 'title' => 'Edit',
- 'page callback' => 'drupal_get_form',
- // Pass a NULL argument to ensure that additional path components are not
- // passed to taxonomy_form_term() as the vocabulary machine name argument.
- 'page arguments' => array('taxonomy_form_term', 2, NULL),
- 'access callback' => 'taxonomy_term_edit_access',
- 'access arguments' => array(2),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 10,
- 'file' => 'taxonomy.admin.inc',
- );
- $items['taxonomy/term/%taxonomy_term/feed'] = array(
- 'title' => 'Taxonomy term',
- 'title callback' => 'taxonomy_term_title',
- 'title arguments' => array(2),
- 'page callback' => 'taxonomy_term_feed',
- 'page arguments' => array(2),
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- 'file' => 'taxonomy.pages.inc',
- );
- $items['taxonomy/autocomplete'] = array(
- 'title' => 'Autocomplete taxonomy',
- 'page callback' => 'taxonomy_autocomplete',
- 'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
- 'file' => 'taxonomy.pages.inc',
- );
-
- $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array(
- 'title callback' => 'entity_label',
- 'title arguments' => array('taxonomy_vocabulary', 3),
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_overview_terms', 3),
- 'access arguments' => array('administer taxonomy'),
- 'file' => 'taxonomy.admin.inc',
- );
- $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -20,
- );
- $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/edit'] = array(
- 'title' => 'Edit',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_form_vocabulary', 3),
- 'access arguments' => array('administer taxonomy'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => -10,
- 'file' => 'taxonomy.admin.inc',
- );
-
- $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/add'] = array(
- 'title' => 'Add term',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('taxonomy_form_term', array(), 3),
- 'access arguments' => array('administer taxonomy'),
- 'type' => MENU_LOCAL_ACTION,
- 'file' => 'taxonomy.admin.inc',
- );
-
- return $items;
-}
-
-/**
- * Implements hook_admin_paths().
- */
-function taxonomy_admin_paths() {
- $paths = array(
- 'taxonomy/term/*/edit' => TRUE,
- );
- return $paths;
-}
-
-/**
- * Return edit access for a given term.
- */
-function taxonomy_term_edit_access($term) {
- return user_access("edit terms in $term->vid") || user_access('administer taxonomy');
-}
-
-/**
- * Returns the sanitized name of a vocabulary.
- *
- * Deprecated. This function was previously used as a menu item title callback
- * but has been replaced by using entity_label() (which does not
- * sanitize the title, since the menu system does that automatically). In
- * Drupal 7, use that function for title callbacks, and call check_plain()
- * directly if you need a sanitized title.
- */
-function taxonomy_admin_vocabulary_title_callback($vocabulary) {
- return check_plain($vocabulary->name);
-}
-
-/**
- * Saves a vocabulary.
- *
- * @param $vocabulary
- * A vocabulary object with the following properties:
- * - vid: (optional) The ID of the vocabulary (omit if creating a new
- * vocabulary; only use to update an existing vocabulary).
- * - name: The human-readable name of the vocabulary.
- * - machine_name: The machine name of the vocabulary.
- * - description: (optional) The vocabulary's description.
- * - hierarchy: The hierarchy level of the vocabulary.
- * - module: (optional) The module altering the vocabulary.
- * - weight: (optional) The weight of this vocabulary in relation to other
- * vocabularies.
- * - original: (optional) The original vocabulary object before any changes
- * are applied.
- * - old_machine_name: (optional) The original machine name of the
- * vocabulary.
- *
- * @return
- * Status constant indicating whether the vocabulary was inserted (SAVED_NEW)
- * or updated (SAVED_UPDATED).
- */
-function taxonomy_vocabulary_save($vocabulary) {
- // Prevent leading and trailing spaces in vocabulary names.
- if (!empty($vocabulary->name)) {
- $vocabulary->name = trim($vocabulary->name);
- }
- // Load the stored entity, if any.
- if (!empty($vocabulary->vid)) {
- if (!isset($vocabulary->original)) {
- $vocabulary->original = entity_load_unchanged('taxonomy_vocabulary', $vocabulary->vid);
- }
- // Make sure machine name changes are easily detected.
- // @todo: Remove in Drupal 8, as it is deprecated by directly reading from
- // $vocabulary->original.
- $vocabulary->old_machine_name = $vocabulary->original->machine_name;
- }
-
- if (!isset($vocabulary->module)) {
- $vocabulary->module = 'taxonomy';
- }
-
- module_invoke_all('taxonomy_vocabulary_presave', $vocabulary);
- module_invoke_all('entity_presave', $vocabulary, 'taxonomy_vocabulary');
-
- if (!empty($vocabulary->vid) && !empty($vocabulary->name)) {
- $status = drupal_write_record('taxonomy_vocabulary', $vocabulary, 'vid');
- taxonomy_vocabulary_static_reset(array($vocabulary->vid));
- if ($vocabulary->old_machine_name != $vocabulary->machine_name) {
- field_attach_rename_bundle('taxonomy_term', $vocabulary->old_machine_name, $vocabulary->machine_name);
- }
- module_invoke_all('taxonomy_vocabulary_update', $vocabulary);
- module_invoke_all('entity_update', $vocabulary, 'taxonomy_vocabulary');
- }
- elseif (empty($vocabulary->vid)) {
- $status = drupal_write_record('taxonomy_vocabulary', $vocabulary);
- taxonomy_vocabulary_static_reset();
- field_attach_create_bundle('taxonomy_term', $vocabulary->machine_name);
- module_invoke_all('taxonomy_vocabulary_insert', $vocabulary);
- module_invoke_all('entity_insert', $vocabulary, 'taxonomy_vocabulary');
- }
-
- unset($vocabulary->original);
- cache_clear_all();
-
- return $status;
-}
-
-/**
- * Delete a vocabulary.
- *
- * @param $vid
- * A vocabulary ID.
- * @return
- * Constant indicating items were deleted.
- */
-function taxonomy_vocabulary_delete($vid) {
- $vocabulary = taxonomy_vocabulary_load($vid);
-
- $transaction = db_transaction();
- try {
- // Only load terms without a parent, child terms will get deleted too.
- $result = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid = :vid AND th.parent = 0', array(':vid' => $vid))->fetchCol();
- foreach ($result as $tid) {
- taxonomy_term_delete($tid);
- }
- db_delete('taxonomy_vocabulary')
- ->condition('vid', $vid)
- ->execute();
-
- field_attach_delete_bundle('taxonomy_term', $vocabulary->machine_name);
- module_invoke_all('taxonomy_vocabulary_delete', $vocabulary);
- module_invoke_all('entity_delete', $vocabulary, 'taxonomy_vocabulary');
-
- // Load all Taxonomy module fields and delete those which use only this
- // vocabulary.
- $taxonomy_fields = field_read_fields(array('module' => 'taxonomy'));
- foreach ($taxonomy_fields as $field_name => $taxonomy_field) {
- $modified_field = FALSE;
- // Term reference fields may reference terms from more than one
- // vocabulary.
- foreach ($taxonomy_field['settings']['allowed_values'] as $key => $allowed_value) {
- if ($allowed_value['vocabulary'] == $vocabulary->machine_name) {
- unset($taxonomy_field['settings']['allowed_values'][$key]);
- $modified_field = TRUE;
- }
- }
- if ($modified_field) {
- if (empty($taxonomy_field['settings']['allowed_values'])) {
- field_delete_field($field_name);
- }
- else {
- // Update the field definition with the new allowed values.
- field_update_field($taxonomy_field);
- }
- }
- }
-
- cache_clear_all();
- taxonomy_vocabulary_static_reset();
-
- return SAVED_DELETED;
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception('taxonomy', $e);
- throw $e;
- }
-}
-
-/**
- * Implements hook_taxonomy_vocabulary_update().
- */
-function taxonomy_taxonomy_vocabulary_update($vocabulary) {
- // Reflect machine name changes in the definitions of existing 'taxonomy'
- // fields.
- if (!empty($vocabulary->old_machine_name) && $vocabulary->old_machine_name != $vocabulary->machine_name) {
- $fields = field_read_fields();
- foreach ($fields as $field_name => $field) {
- $update = FALSE;
- if ($field['type'] == 'taxonomy_term_reference') {
- foreach ($field['settings']['allowed_values'] as $key => &$value) {
- if ($value['vocabulary'] == $vocabulary->old_machine_name) {
- $value['vocabulary'] = $vocabulary->machine_name;
- $update = TRUE;
- }
- }
- if ($update) {
- field_update_field($field);
- }
- }
- }
- }
-}
-
-/**
- * Checks and updates the hierarchy flag of a vocabulary.
- *
- * Checks the current parents of all terms in a vocabulary and updates the
- * vocabulary's hierarchy setting to the lowest possible level. If no term
- * has parent terms then the vocabulary will be given a hierarchy of 0.
- * If any term has a single parent then the vocabulary will be given a
- * hierarchy of 1. If any term has multiple parents then the vocabulary
- * will be given a hierarchy of 2.
- *
- * @param $vocabulary
- * A vocabulary object.
- * @param $changed_term
- * An array of the term structure that was updated.
- *
- * @return
- * An integer that represents the level of the vocabulary's hierarchy.
- */
-function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
- $tree = taxonomy_get_tree($vocabulary->vid);
- $hierarchy = 0;
- foreach ($tree as $term) {
- // Update the changed term with the new parent value before comparison.
- if ($term->tid == $changed_term['tid']) {
- $term = (object) $changed_term;
- $term->parents = $term->parent;
- }
- // Check this term's parent count.
- if (count($term->parents) > 1) {
- $hierarchy = 2;
- break;
- }
- elseif (count($term->parents) == 1 && !isset($term->parents[0])) {
- $hierarchy = 1;
- }
- }
- if ($hierarchy != $vocabulary->hierarchy) {
- $vocabulary->hierarchy = $hierarchy;
- taxonomy_vocabulary_save($vocabulary);
- }
-
- return $hierarchy;
-}
-
-/**
- * Saves a term object to the database.
- *
- * @param $term
- * The taxonomy term object with the following properties:
- * - vid: The ID of the vocabulary the term is assigned to.
- * - name: The name of the term.
- * - tid: (optional) The unique ID for the term being saved. If $term->tid is
- * empty or omitted, a new term will be inserted.
- * - description: (optional) The term's description.
- * - format: (optional) The text format for the term's description.
- * - weight: (optional) The weight of this term in relation to other terms
- * within the same vocabulary.
- * - parent: (optional) The parent term(s) for this term. This can be a single
- * term ID or an array of term IDs. A value of 0 means this term does not
- * have any parents. When omitting this variable during an update, the
- * existing hierarchy for the term remains unchanged.
- * - vocabulary_machine_name: (optional) The machine name of the vocabulary
- * the term is assigned to. If not given, this value will be set
- * automatically by loading the vocabulary based on $term->vid.
- * - original: (optional) The original taxonomy term object before any changes
- * were applied. When omitted, the unchanged taxonomy term object is
- * loaded from the database and stored in this property.
- * Since a taxonomy term is an entity, any fields contained in the term object
- * are saved alongside the term object.
- *
- * @return
- * Status constant indicating whether term was inserted (SAVED_NEW) or updated
- * (SAVED_UPDATED). When inserting a new term, $term->tid will contain the
- * term ID of the newly created term.
- */
-function taxonomy_term_save($term) {
- // Prevent leading and trailing spaces in term names.
- $term->name = trim($term->name);
- if (!isset($term->vocabulary_machine_name)) {
- $vocabulary = taxonomy_vocabulary_load($term->vid);
- $term->vocabulary_machine_name = $vocabulary->machine_name;
- }
-
- // Load the stored entity, if any.
- if (!empty($term->tid) && !isset($term->original)) {
- $term->original = entity_load_unchanged('taxonomy_term', $term->tid);
- }
-
- field_attach_presave('taxonomy_term', $term);
- module_invoke_all('taxonomy_term_presave', $term);
- module_invoke_all('entity_presave', $term, 'taxonomy_term');
-
- if (empty($term->tid)) {
- $op = 'insert';
- $status = drupal_write_record('taxonomy_term_data', $term);
- field_attach_insert('taxonomy_term', $term);
- if (!isset($term->parent)) {
- $term->parent = array(0);
- }
- }
- else {
- $op = 'update';
- $status = drupal_write_record('taxonomy_term_data', $term, 'tid');
- field_attach_update('taxonomy_term', $term);
- if (isset($term->parent)) {
- db_delete('taxonomy_term_hierarchy')
- ->condition('tid', $term->tid)
- ->execute();
- }
- }
-
- if (isset($term->parent)) {
- if (!is_array($term->parent)) {
- $term->parent = array($term->parent);
- }
- $query = db_insert('taxonomy_term_hierarchy')
- ->fields(array('tid', 'parent'));
- foreach ($term->parent as $parent) {
- if (is_array($parent)) {
- foreach ($parent as $tid) {
- $query->values(array(
- 'tid' => $term->tid,
- 'parent' => $tid
- ));
- }
- }
- else {
- $query->values(array(
- 'tid' => $term->tid,
- 'parent' => $parent
- ));
- }
- }
- $query->execute();
- }
-
- // Reset the taxonomy term static variables.
- taxonomy_terms_static_reset();
-
- // Invoke the taxonomy hooks.
- module_invoke_all("taxonomy_term_$op", $term);
- module_invoke_all("entity_$op", $term, 'taxonomy_term');
- unset($term->original);
-
- return $status;
-}
-
-/**
- * Delete a term.
- *
- * @param $tid
- * The term ID.
- * @return
- * Status constant indicating deletion.
- */
-function taxonomy_term_delete($tid) {
- $transaction = db_transaction();
- try {
- $tids = array($tid);
- while ($tids) {
- $children_tids = $orphans = array();
- foreach ($tids as $tid) {
- // See if any of the term's children are about to be become orphans:
- if ($children = taxonomy_get_children($tid)) {
- foreach ($children as $child) {
- // If the term has multiple parents, we don't delete it.
- $parents = taxonomy_get_parents($child->tid);
- if (count($parents) == 1) {
- $orphans[] = $child->tid;
- }
- }
- }
-
- if ($term = taxonomy_term_load($tid)) {
- db_delete('taxonomy_term_data')
- ->condition('tid', $tid)
- ->execute();
- db_delete('taxonomy_term_hierarchy')
- ->condition('tid', $tid)
- ->execute();
-
- field_attach_delete('taxonomy_term', $term);
- module_invoke_all('taxonomy_term_delete', $term);
- module_invoke_all('entity_delete', $term, 'taxonomy_term');
- taxonomy_terms_static_reset();
- }
- }
-
- $tids = $orphans;
- }
- return SAVED_DELETED;
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception('taxonomy', $e);
- throw $e;
- }
-}
-
-/**
- * Generates an array which displays a term detail page.
- *
- * @param term
- * A taxonomy term object.
- * @return
- * A $page element suitable for use by drupal_page_render().
- */
-function taxonomy_term_show($term) {
- return taxonomy_term_view_multiple(array($term->tid => $term), 'full');
-}
-
-/**
- * Constructs a drupal_render() style array from an array of loaded terms.
- *
- * @param $terms
- * An array of taxonomy terms as returned by taxonomy_term_load_multiple().
- * @param $view_mode
- * View mode, e.g. 'full', 'teaser'...
- * @param $weight
- * An integer representing the weight of the first taxonomy term in the list.
- * @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
- *
- * @return
- * An array in the format expected by drupal_render().
- */
-function taxonomy_term_view_multiple($terms, $view_mode = 'teaser', $weight = 0, $langcode = NULL) {
- field_attach_prepare_view('taxonomy_term', $terms, $view_mode, $langcode);
- entity_prepare_view('taxonomy_term', $terms, $langcode);
- $build = array();
- foreach ($terms as $term) {
- $build['taxonomy_terms'][$term->tid] = taxonomy_term_view($term, $view_mode, $langcode);
- $build['taxonomy_terms'][$term->tid]['#weight'] = $weight;
- $weight++;
- }
- $build['taxonomy_terms']['#sorted'] = TRUE;
- return $build;
-}
-
-/**
- * Builds a structured array representing the term's content.
- *
- * The content built for the taxonomy term (field values, file attachments or
- * other term components) will vary depending on the $view_mode parameter.
- *
- * Drupal core defines the following view modes for terms, with the following
- * default use cases:
- * - full (default): term is displayed on its own page (taxonomy/term/123)
- * Contributed modules might define additional view modes, or use existing
- * view modes in additional contexts.
- *
- * @param $term
- * A taxonomy term object.
- * @param $view_mode
- * View mode, e.g. 'full', 'teaser'...
- * @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
- */
-function taxonomy_term_build_content($term, $view_mode = 'full', $langcode = NULL) {
- if (!isset($langcode)) {
- $langcode = $GLOBALS['language_content']->language;
- }
-
- // Remove previously built content, if exists.
- $term->content = array();
-
- // Allow modules to change the view mode.
- $context = array(
- 'entity_type' => 'taxonomy_term',
- 'entity' => $term,
- 'langcode' => $langcode,
- );
- drupal_alter('entity_view_mode', $view_mode, $context);
-
- // Add the term description if the term has one and it is visible.
- $type = 'taxonomy_term';
- $entity_ids = entity_extract_ids($type, $term);
- $settings = field_view_mode_settings($type, $entity_ids[2]);
- $fields = field_extra_fields_get_display($type, $entity_ids[2], $view_mode);
- if (!empty($term->description) && isset($fields['description']) && $fields['description']['visible']) {
- $term->content['description'] = array(
- '#markup' => check_markup($term->description, $term->format, '', TRUE),
- '#weight' => $fields['description']['weight'],
- '#prefix' => '',
- '#suffix' => '
',
- );
- }
-
- // Build fields content.
- // In case of a multiple view, taxonomy_term_view_multiple() already ran the
- // 'prepare_view' step. An internal flag prevents the operation from running
- // twice.
- field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode);
- entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode);
- $term->content += field_attach_view('taxonomy_term', $term, $view_mode, $langcode);
-
- // Allow modules to make their own additions to the taxonomy term.
- module_invoke_all('taxonomy_term_view', $term, $view_mode, $langcode);
- module_invoke_all('entity_view', $term, 'taxonomy_term', $view_mode, $langcode);
-
- // Make sure the current view mode is stored if no module has already
- // populated the related key.
- $term->content += array('#view_mode' => $view_mode);
-}
-
-/**
- * Generate an array for rendering the given term.
- *
- * @param $term
- * A term object.
- * @param $view_mode
- * View mode, e.g. 'full', 'teaser'...
- * @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
- *
- * @return
- * An array as expected by drupal_render().
- */
-function taxonomy_term_view($term, $view_mode = 'full', $langcode = NULL) {
- if (!isset($langcode)) {
- $langcode = $GLOBALS['language_content']->language;
- }
-
- // Populate $term->content with a render() array.
- taxonomy_term_build_content($term, $view_mode, $langcode);
- $build = $term->content;
-
- // We don't need duplicate rendering info in $term->content.
- unset($term->content);
-
- $build += array(
- '#theme' => 'taxonomy_term',
- '#term' => $term,
- '#view_mode' => $view_mode,
- '#language' => $langcode,
- );
-
- $build['#attached']['css'][] = drupal_get_path('module', 'taxonomy') . '/taxonomy.css';
-
- // Allow modules to modify the structured taxonomy term.
- $type = 'taxonomy_term';
- drupal_alter(array('taxonomy_term_view', 'entity_view'), $build, $type);
-
- return $build;
-}
-
-/**
- * Process variables for taxonomy-term.tpl.php.
- */
-function template_preprocess_taxonomy_term(&$variables) {
- $variables['view_mode'] = $variables['elements']['#view_mode'];
- $variables['term'] = $variables['elements']['#term'];
- $term = $variables['term'];
-
- $uri = entity_uri('taxonomy_term', $term);
- $variables['term_url'] = url($uri['path'], $uri['options']);
- $variables['term_name'] = check_plain($term->name);
- $variables['page'] = $variables['view_mode'] == 'full' && taxonomy_term_is_page($term);
-
- // Flatten the term object's member fields.
- $variables = array_merge((array) $term, $variables);
-
- // Helpful $content variable for templates.
- $variables['content'] = array();
- foreach (element_children($variables['elements']) as $key) {
- $variables['content'][$key] = $variables['elements'][$key];
- }
-
- // field_attach_preprocess() overwrites the $[field_name] variables with the
- // values of the field in the language that was selected for display, instead
- // of the raw values in $term->[field_name], which contain all values in all
- // languages.
- field_attach_preprocess('taxonomy_term', $term, $variables['content'], $variables);
-
- // Gather classes, and clean up name so there are no underscores.
- $vocabulary_name_css = str_replace('_', '-', $term->vocabulary_machine_name);
- $variables['classes_array'][] = 'vocabulary-' . $vocabulary_name_css;
-
- $variables['theme_hook_suggestions'][] = 'taxonomy_term__' . $term->vocabulary_machine_name;
- $variables['theme_hook_suggestions'][] = 'taxonomy_term__' . $term->tid;
-}
-
-/**
- * Returns whether the current page is the page of the passed-in term.
- *
- * @param $term
- * A term object.
- */
-function taxonomy_term_is_page($term) {
- $page_term = menu_get_object('taxonomy_term', 2);
- return (!empty($page_term) ? $page_term->tid == $term->tid : FALSE);
-}
-
-/**
- * Clear all static cache variables for terms.
- */
-function taxonomy_terms_static_reset() {
- drupal_static_reset('taxonomy_term_count_nodes');
- drupal_static_reset('taxonomy_get_tree');
- drupal_static_reset('taxonomy_get_tree:parents');
- drupal_static_reset('taxonomy_get_tree:terms');
- drupal_static_reset('taxonomy_get_parents');
- drupal_static_reset('taxonomy_get_parents_all');
- drupal_static_reset('taxonomy_get_children');
- entity_get_controller('taxonomy_term')->resetCache();
-}
-
-/**
- * Clear all static cache variables for vocabularies.
- *
- * @param $ids
- * An array of ids to reset in entity controller cache.
- */
-function taxonomy_vocabulary_static_reset($ids = NULL) {
- drupal_static_reset('taxonomy_vocabulary_get_names');
- entity_get_controller('taxonomy_vocabulary')->resetCache($ids);
-}
-
-/**
- * Return an array of all vocabulary objects.
- *
- * @return
- * An array of all vocabulary objects, indexed by vid.
- */
-function taxonomy_get_vocabularies() {
- return taxonomy_vocabulary_load_multiple(FALSE, array());
-}
-
-/**
- * Get names for all taxonomy vocabularies.
- *
- * @return
- * An associative array of objects keyed by vocabulary machine name with
- * information about taxonomy vocabularies. Each object has properties:
- * - name: The vocabulary name.
- * - machine_name: The machine name.
- * - vid: The vocabulary ID.
- */
-function taxonomy_vocabulary_get_names() {
- $names = &drupal_static(__FUNCTION__);
-
- if (!isset($names)) {
- $names = db_query('SELECT name, machine_name, vid FROM {taxonomy_vocabulary}')->fetchAllAssoc('machine_name');
- }
-
- return $names;
-}
-
-/**
- * Finds all parents of a given term ID.
- *
- * @param $tid
- * A taxonomy term ID.
- *
- * @return
- * An array of term objects which are the parents of the term $tid, or an
- * empty array if parents are not found.
- */
-function taxonomy_get_parents($tid) {
- $parents = &drupal_static(__FUNCTION__, array());
-
- if ($tid && !isset($parents[$tid])) {
- $query = db_select('taxonomy_term_data', 't');
- $query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
- $query->addField('t', 'tid');
- $query->condition('h.tid', $tid);
- $query->addTag('term_access');
- $query->orderBy('t.weight');
- $query->orderBy('t.name');
- $tids = $query->execute()->fetchCol();
- $parents[$tid] = taxonomy_term_load_multiple($tids);
- }
-
- return isset($parents[$tid]) ? $parents[$tid] : array();
-}
-
-/**
- * Find all ancestors of a given term ID.
- */
-function taxonomy_get_parents_all($tid) {
- $cache = &drupal_static(__FUNCTION__, array());
-
- if (isset($cache[$tid])) {
- return $cache[$tid];
- }
-
- $parents = array();
- if ($term = taxonomy_term_load($tid)) {
- $parents[] = $term;
- $n = 0;
- while ($parent = taxonomy_get_parents($parents[$n]->tid)) {
- $parents = array_merge($parents, $parent);
- $n++;
- }
- }
-
- $cache[$tid] = $parents;
-
- return $parents;
-}
-
-/**
- * Finds all children of a term ID.
- *
- * @param $tid
- * A taxonomy term ID.
- * @param $vid
- * An optional vocabulary ID to restrict the child search.
- *
- * @return
- * An array of term objects that are the children of the term $tid, or an
- * empty array when no children exist.
- */
-function taxonomy_get_children($tid, $vid = 0) {
- $children = &drupal_static(__FUNCTION__, array());
-
- if ($tid && !isset($children[$tid])) {
- $query = db_select('taxonomy_term_data', 't');
- $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
- $query->addField('t', 'tid');
- $query->condition('h.parent', $tid);
- if ($vid) {
- $query->condition('t.vid', $vid);
- }
- $query->addTag('term_access');
- $query->orderBy('t.weight');
- $query->orderBy('t.name');
- $tids = $query->execute()->fetchCol();
- $children[$tid] = taxonomy_term_load_multiple($tids);
- }
-
- return isset($children[$tid]) ? $children[$tid] : array();
-}
-
-/**
- * Create a hierarchical representation of a vocabulary.
- *
- * @param $vid
- * Which vocabulary to generate the tree for.
- * @param $parent
- * The term ID under which to generate the tree. If 0, generate the tree
- * for the entire vocabulary.
- * @param $max_depth
- * The number of levels of the tree to return. Leave NULL to return all levels.
- * @param $load_entities
- * If TRUE, a full entity load will occur on the term objects. Otherwise they
- * are partial objects queried directly from the {taxonomy_term_data} table to
- * save execution time and memory consumption when listing large numbers of
- * terms. Defaults to FALSE.
- *
- * @return
- * An array of all term objects in the tree. Each term object is extended
- * to have "depth" and "parents" attributes in addition to its normal ones.
- * Results are statically cached. Term objects will be partial or complete
- * depending on the $load_entities parameter.
- */
-function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) {
- $children = &drupal_static(__FUNCTION__, array());
- $parents = &drupal_static(__FUNCTION__ . ':parents', array());
- $terms = &drupal_static(__FUNCTION__ . ':terms', array());
-
- // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a
- // term and its children, too.
- if (!isset($children[$vid])) {
- $children[$vid] = array();
- $parents[$vid] = array();
- $terms[$vid] = array();
-
- $query = db_select('taxonomy_term_data', 't');
- $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
- $result = $query
- ->addTag('translatable')
- ->addTag('term_access')
- ->fields('t')
- ->fields('h', array('parent'))
- ->condition('t.vid', $vid)
- ->orderBy('t.weight')
- ->orderBy('t.name')
- ->execute();
-
- foreach ($result as $term) {
- $children[$vid][$term->parent][] = $term->tid;
- $parents[$vid][$term->tid][] = $term->parent;
- $terms[$vid][$term->tid] = $term;
- }
- }
-
- // Load full entities, if necessary. The entity controller statically
- // caches the results.
- if ($load_entities) {
- $term_entities = taxonomy_term_load_multiple(array_keys($terms[$vid]));
- }
-
- $max_depth = (!isset($max_depth)) ? count($children[$vid]) : $max_depth;
- $tree = array();
-
- // Keeps track of the parents we have to process, the last entry is used
- // for the next processing step.
- $process_parents = array();
- $process_parents[] = $parent;
-
- // Loops over the parent terms and adds its children to the tree array.
- // Uses a loop instead of a recursion, because it's more efficient.
- while (count($process_parents)) {
- $parent = array_pop($process_parents);
- // The number of parents determines the current depth.
- $depth = count($process_parents);
- if ($max_depth > $depth && !empty($children[$vid][$parent])) {
- $has_children = FALSE;
- $child = current($children[$vid][$parent]);
- do {
- if (empty($child)) {
- break;
- }
- $term = $load_entities ? $term_entities[$child] : $terms[$vid][$child];
- if (isset($parents[$vid][$term->tid])) {
- // Clone the term so that the depth attribute remains correct
- // in the event of multiple parents.
- $term = clone $term;
- }
- $term->depth = $depth;
- unset($term->parent);
- $term->parents = $parents[$vid][$term->tid];
- $tree[] = $term;
- if (!empty($children[$vid][$term->tid])) {
- $has_children = TRUE;
-
- // We have to continue with this parent later.
- $process_parents[] = $parent;
- // Use the current term as parent for the next iteration.
- $process_parents[] = $term->tid;
-
- // Reset pointers for child lists because we step in there more often
- // with multi parents.
- reset($children[$vid][$term->tid]);
- // Move pointer so that we get the correct term the next time.
- next($children[$vid][$parent]);
- break;
- }
- } while ($child = next($children[$vid][$parent]));
-
- if (!$has_children) {
- // We processed all terms in this hierarchy-level, reset pointer
- // so that this function works the next time it gets called.
- reset($children[$vid][$parent]);
- }
- }
- }
-
- return $tree;
-}
-
-/**
- * Try to map a string to an existing term, as for glossary use.
- *
- * Provides a case-insensitive and trimmed mapping, to maximize the
- * likelihood of a successful match.
- *
- * @param $name
- * Name of the term to search for.
- * @param $vocabulary
- * (optional) Vocabulary machine name to limit the search. Defaults to NULL.
- *
- * @return
- * An array of matching term objects.
- */
-function taxonomy_get_term_by_name($name, $vocabulary = NULL) {
- $conditions = array('name' => trim($name));
- if (isset($vocabulary)) {
- $vocabularies = taxonomy_vocabulary_get_names();
- if (isset($vocabularies[$vocabulary])) {
- $conditions['vid'] = $vocabularies[$vocabulary]->vid;
- }
- else {
- // Return an empty array when filtering by a non-existing vocabulary.
- return array();
- }
- }
- return taxonomy_term_load_multiple(array(), $conditions);
-}
-
-/**
- * Controller class for taxonomy terms.
- *
- * This extends the DrupalDefaultEntityController class. Only alteration is
- * that we match the condition on term name case-independently.
- */
-class TaxonomyTermController extends DrupalDefaultEntityController {
-
- protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
- $query = parent::buildQuery($ids, $conditions, $revision_id);
- $query->addTag('translatable');
- $query->addTag('term_access');
- // When name is passed as a condition use LIKE.
- if (isset($conditions['name'])) {
- $query_conditions = &$query->conditions();
- foreach ($query_conditions as $key => $condition) {
- if (is_array($condition) && $condition['field'] == 'base.name') {
- $query_conditions[$key]['operator'] = 'LIKE';
- $query_conditions[$key]['value'] = db_like($query_conditions[$key]['value']);
- }
- }
- }
- // Add the machine name field from the {taxonomy_vocabulary} table.
- $query->innerJoin('taxonomy_vocabulary', 'v', 'base.vid = v.vid');
- $query->addField('v', 'machine_name', 'vocabulary_machine_name');
- return $query;
- }
-
- protected function cacheGet($ids, $conditions = array()) {
- $terms = parent::cacheGet($ids, $conditions);
- // Name matching is case insensitive, note that with some collations
- // LOWER() and drupal_strtolower() may return different results.
- foreach ($terms as $term) {
- $term_values = (array) $term;
- if (isset($conditions['name']) && drupal_strtolower($conditions['name'] != drupal_strtolower($term_values['name']))) {
- unset($terms[$term->tid]);
- }
- }
- return $terms;
- }
-}
-
-/**
- * Controller class for taxonomy vocabularies.
- *
- * This extends the DrupalDefaultEntityController class, adding required
- * special handling for taxonomy vocabulary objects.
- */
-class TaxonomyVocabularyController extends DrupalDefaultEntityController {
-
- protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
- $query = parent::buildQuery($ids, $conditions, $revision_id);
- $query->addTag('translatable');
- $query->orderBy('base.weight');
- $query->orderBy('base.name');
- return $query;
- }
-}
-
-/**
- * Load multiple taxonomy terms based on certain conditions.
- *
- * This function should be used whenever you need to load more than one term
- * from the database. Terms are loaded into memory and will not require
- * database access if loaded again during the same page request.
- *
- * @see entity_load()
- * @see EntityFieldQuery
- *
- * @param $tids
- * An array of taxonomy term IDs.
- * @param $conditions
- * (deprecated) An associative array of conditions on the {taxonomy_term}
- * table, where the keys are the database fields and the values are the
- * values those fields must have. Instead, it is preferable to use
- * EntityFieldQuery to retrieve a list of entity IDs loadable by
- * this function.
- *
- * @return
- * An array of term objects, indexed by tid. When no results are found, an
- * empty array is returned.
- *
- * @todo Remove $conditions in Drupal 8.
- */
-function taxonomy_term_load_multiple($tids = array(), $conditions = array()) {
- return entity_load('taxonomy_term', $tids, $conditions);
-}
-
-/**
- * Load multiple taxonomy vocabularies based on certain conditions.
- *
- * This function should be used whenever you need to load more than one
- * vocabulary from the database. Terms are loaded into memory and will not
- * require database access if loaded again during the same page request.
- *
- * @see entity_load()
- *
- * @param $vids
- * An array of taxonomy vocabulary IDs, or FALSE to load all vocabularies.
- * @param $conditions
- * An array of conditions to add to the query.
- *
- * @return
- * An array of vocabulary objects, indexed by vid.
- */
-function taxonomy_vocabulary_load_multiple($vids = array(), $conditions = array()) {
- return entity_load('taxonomy_vocabulary', $vids, $conditions);
-}
-
-/**
- * Return the vocabulary object matching a vocabulary ID.
- *
- * @param $vid
- * The vocabulary's ID.
- *
- * @return
- * The vocabulary object with all of its metadata, if exists, FALSE otherwise.
- * Results are statically cached.
- *
- * @see taxonomy_vocabulary_machine_name_load()
- */
-function taxonomy_vocabulary_load($vid) {
- $vocabularies = taxonomy_vocabulary_load_multiple(array($vid));
- return reset($vocabularies);
-}
-
-/**
- * Return the vocabulary object matching a vocabulary machine name.
- *
- * @param $name
- * The vocabulary's machine name.
- *
- * @return
- * The vocabulary object with all of its metadata, if exists, FALSE otherwise.
- * Results are statically cached.
- *
- * @see taxonomy_vocabulary_load()
- */
-function taxonomy_vocabulary_machine_name_load($name) {
- $vocabularies = taxonomy_vocabulary_load_multiple(NULL, array('machine_name' => $name));
- return reset($vocabularies);
-}
-
-/**
- * Return the term object matching a term ID.
- *
- * @param $tid
- * A term's ID
- *
- * @return
- * A taxonomy term object, or FALSE if the term was not found. Results are
- * statically cached.
- */
-function taxonomy_term_load($tid) {
- if (!is_numeric($tid)) {
- return FALSE;
- }
- $term = taxonomy_term_load_multiple(array($tid), array());
- return $term ? $term[$tid] : FALSE;
-}
-
-/**
- * Helper function for array_map purposes.
- */
-function _taxonomy_get_tid_from_term($term) {
- return $term->tid;
-}
-
-/**
- * Implodes a list of tags of a certain vocabulary into a string.
- *
- * @see drupal_explode_tags()
- */
-function taxonomy_implode_tags($tags, $vid = NULL) {
- $typed_tags = array();
- foreach ($tags as $tag) {
- // Extract terms belonging to the vocabulary in question.
- if (!isset($vid) || $tag->vid == $vid) {
- // Make sure we have a completed loaded taxonomy term.
- if (isset($tag->name)) {
- // Commas and quotes in tag names are special cases, so encode 'em.
- if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
- $typed_tags[] = '"' . str_replace('"', '""', $tag->name) . '"';
- }
- else {
- $typed_tags[] = $tag->name;
- }
- }
- }
- }
- return implode(', ', $typed_tags);
-}
-
-/**
- * Implements hook_field_info().
- *
- * Field settings:
- * - allowed_values: a list array of one or more vocabulary trees:
- * - vocabulary: a vocabulary machine name.
- * - parent: a term ID of a term whose children are allowed. This should be
- * '0' if all terms in a vocabulary are allowed. The allowed values do not
- * include the parent term.
- *
- */
-function taxonomy_field_info() {
- return array(
- 'taxonomy_term_reference' => array(
- 'label' => t('Term reference'),
- 'description' => t('This field stores a reference to a taxonomy term.'),
- 'default_widget' => 'options_select',
- 'default_formatter' => 'taxonomy_term_reference_link',
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => '',
- 'parent' => '0',
- ),
- ),
- ),
- ),
- );
-}
-
-/**
- * Implements hook_field_widget_info().
- */
-function taxonomy_field_widget_info() {
- return array(
- 'taxonomy_autocomplete' => array(
- 'label' => t('Autocomplete term widget (tagging)'),
- 'field types' => array('taxonomy_term_reference'),
- 'settings' => array(
- 'size' => 60,
- 'autocomplete_path' => 'taxonomy/autocomplete',
- ),
- 'behaviors' => array(
- 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
- ),
- ),
- );
-}
-
-/**
- * Implements hook_field_widget_info_alter().
- */
-function taxonomy_field_widget_info_alter(&$info) {
- $info['options_select']['field types'][] = 'taxonomy_term_reference';
- $info['options_buttons']['field types'][] = 'taxonomy_term_reference';
-}
-
-/**
- * Implements hook_options_list().
- */
-function taxonomy_options_list($field, $instance, $entity_type, $entity) {
- $function = !empty($field['settings']['options_list_callback']) ? $field['settings']['options_list_callback'] : 'taxonomy_allowed_values';
- return $function($field);
-}
-
-/**
- * Implements hook_field_validate().
- *
- * Taxonomy field settings allow for either a single vocabulary ID, multiple
- * vocabulary IDs, or sub-trees of a vocabulary to be specified as allowed
- * values, although only the first of these is supported via the field UI.
- * Confirm that terms entered as values meet at least one of these conditions.
- *
- * Possible error codes:
- * - 'taxonomy_term_illegal_value': The value is not part of the list of allowed values.
- */
-function taxonomy_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
- // Build an array of existing term IDs so they can be loaded with
- // taxonomy_term_load_multiple();
- foreach ($items as $delta => $item) {
- if (!empty($item['tid']) && $item['tid'] != 'autocreate') {
- $tids[] = $item['tid'];
- }
- }
- if (!empty($tids)) {
- $terms = taxonomy_term_load_multiple($tids);
-
- // Check each existing item to ensure it can be found in the
- // allowed values for this field.
- foreach ($items as $delta => $item) {
- $validate = TRUE;
- if (!empty($item['tid']) && $item['tid'] != 'autocreate') {
- $validate = FALSE;
- foreach ($field['settings']['allowed_values'] as $settings) {
- // If no parent is specified, check if the term is in the vocabulary.
- if (isset($settings['vocabulary']) && empty($settings['parent'])) {
- if ($settings['vocabulary'] == $terms[$item['tid']]->vocabulary_machine_name) {
- $validate = TRUE;
- break;
- }
- }
- // If a parent is specified, then to validate it must appear in the
- // array returned by taxonomy_get_parents_all().
- elseif (!empty($settings['parent'])) {
- $ancestors = taxonomy_get_parents_all($item['tid']);
- foreach ($ancestors as $ancestor) {
- if ($ancestor->tid == $settings['parent']) {
- $validate = TRUE;
- break 2;
- }
- }
- }
- }
- }
- if (!$validate) {
- $errors[$field['field_name']][$langcode][$delta][] = array(
- 'error' => 'taxonomy_term_reference_illegal_value',
- 'message' => t('%name: illegal value.', array('%name' => $instance['label'])),
- );
- }
- }
- }
-}
-
-/**
- * Implements hook_field_is_empty().
- */
-function taxonomy_field_is_empty($item, $field) {
- if (!is_array($item) || (empty($item['tid']) && (string) $item['tid'] !== '0')) {
- return TRUE;
- }
- return FALSE;
-}
-
-/**
- * Implements hook_field_formatter_info().
- */
-function taxonomy_field_formatter_info() {
- return array(
- 'taxonomy_term_reference_link' => array(
- 'label' => t('Link'),
- 'field types' => array('taxonomy_term_reference'),
- ),
- 'taxonomy_term_reference_plain' => array(
- 'label' => t('Plain text'),
- 'field types' => array('taxonomy_term_reference'),
- ),
- 'taxonomy_term_reference_rss_category' => array(
- 'label' => t('RSS category'),
- 'field types' => array('taxonomy_term_reference'),
- ),
- );
-}
-
-/**
- * Implements hook_field_formatter_view().
- */
-function taxonomy_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
- $element = array();
-
- // Terms whose tid is 'autocreate' do not exist
- // yet and $item['taxonomy_term'] is not set. Theme such terms as
- // just their name.
-
- switch ($display['type']) {
- case 'taxonomy_term_reference_link':
- foreach ($items as $delta => $item) {
- if ($item['tid'] == 'autocreate') {
- $element[$delta] = array(
- '#markup' => check_plain($item['name']),
- );
- }
- else {
- $term = $item['taxonomy_term'];
- $uri = entity_uri('taxonomy_term', $term);
- $element[$delta] = array(
- '#type' => 'link',
- '#title' => $term->name,
- '#href' => $uri['path'],
- '#options' => $uri['options'],
- );
- }
- }
- break;
-
- case 'taxonomy_term_reference_plain':
- foreach ($items as $delta => $item) {
- $name = ($item['tid'] != 'autocreate' ? $item['taxonomy_term']->name : $item['name']);
- $element[$delta] = array(
- '#markup' => check_plain($name),
- );
- }
- break;
-
- case 'taxonomy_term_reference_rss_category':
- foreach ($items as $delta => $item) {
- $entity->rss_elements[] = array(
- 'key' => 'category',
- 'value' => $item['tid'] != 'autocreate' ? $item['taxonomy_term']->name : $item['name'],
- 'attributes' => array(
- 'domain' => $item['tid'] != 'autocreate' ? url('taxonomy/term/' . $item['tid'], array('absolute' => TRUE)) : '',
- ),
- );
- }
- break;
- }
-
- return $element;
-}
-
-/**
- * Returns the set of valid terms for a taxonomy field.
- *
- * @param $field
- * The field definition.
- * @return
- * The array of valid terms for this field, keyed by term id.
- */
-function taxonomy_allowed_values($field) {
- $options = array();
- foreach ($field['settings']['allowed_values'] as $tree) {
- if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
- if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'])) {
- foreach ($terms as $term) {
- $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
- }
- }
- }
- }
- return $options;
-}
-
-/**
- * Implements hook_field_formatter_prepare_view().
- *
- * This preloads all taxonomy terms for multiple loaded objects at once and
- * unsets values for invalid terms that do not exist.
- */
-function taxonomy_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
- $tids = array();
-
- // Collect every possible term attached to any of the fieldable entities.
- foreach ($entities as $id => $entity) {
- foreach ($items[$id] as $delta => $item) {
- // Force the array key to prevent duplicates.
- if ($item['tid'] != 'autocreate') {
- $tids[$item['tid']] = $item['tid'];
- }
- }
- }
- if ($tids) {
- $terms = taxonomy_term_load_multiple($tids);
-
- // Iterate through the fieldable entities again to attach the loaded term data.
- foreach ($entities as $id => $entity) {
- $rekey = FALSE;
-
- foreach ($items[$id] as $delta => $item) {
- // Check whether the taxonomy term field instance value could be loaded.
- if (isset($terms[$item['tid']])) {
- // Replace the instance value with the term data.
- $items[$id][$delta]['taxonomy_term'] = $terms[$item['tid']];
- }
- // Terms to be created are not in $terms, but are still legitimate.
- elseif ($item['tid'] == 'autocreate') {
- // Leave the item in place.
- }
- // Otherwise, unset the instance value, since the term does not exist.
- else {
- unset($items[$id][$delta]);
- $rekey = TRUE;
- }
- }
-
- if ($rekey) {
- // Rekey the items array.
- $items[$id] = array_values($items[$id]);
- }
- }
- }
-}
-
-/**
- * Title callback for term pages.
- *
- * @param $term
- * A term object.
- *
- * @return
- * The term name to be used as the page title.
- */
-function taxonomy_term_title($term) {
- return $term->name;
-}
-
-/**
- * Implements hook_field_widget_form().
- */
-function taxonomy_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
- $tags = array();
- foreach ($items as $item) {
- $tags[$item['tid']] = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
- }
-
- $element += array(
- '#type' => 'textfield',
- '#default_value' => taxonomy_implode_tags($tags),
- '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $field['field_name'],
- '#size' => $instance['widget']['settings']['size'],
- '#maxlength' => 1024,
- '#element_validate' => array('taxonomy_autocomplete_validate'),
- );
-
- return $element;
-}
-
-/**
- * Form element validate handler for taxonomy term autocomplete element.
- */
-function taxonomy_autocomplete_validate($element, &$form_state) {
- // Autocomplete widgets do not send their tids in the form, so we must detect
- // them here and process them independently.
- $value = array();
- if ($tags = $element['#value']) {
- // Collect candidate vocabularies.
- $field = field_widget_field($element, $form_state);
- $vocabularies = array();
- foreach ($field['settings']['allowed_values'] as $tree) {
- if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
- $vocabularies[$vocabulary->vid] = $vocabulary;
- }
- }
-
- // Translate term names into actual terms.
- $typed_terms = drupal_explode_tags($tags);
- foreach ($typed_terms as $typed_term) {
- // See if the term exists in the chosen vocabulary and return the tid;
- // otherwise, create a new 'autocreate' term for insert/update.
- if ($possibilities = taxonomy_term_load_multiple(array(), array('name' => trim($typed_term), 'vid' => array_keys($vocabularies)))) {
- $term = array_pop($possibilities);
- }
- else {
- $vocabulary = reset($vocabularies);
- $term = array(
- 'tid' => 'autocreate',
- 'vid' => $vocabulary->vid,
- 'name' => $typed_term,
- 'vocabulary_machine_name' => $vocabulary->machine_name,
- );
- }
- $value[] = (array)$term;
- }
- }
-
- form_set_value($element, $value, $form_state);
-}
-
-/**
- * Implements hook_field_widget_error().
- */
-function taxonomy_field_widget_error($element, $error, $form, &$form_state) {
- form_error($element, $error['message']);
-}
-/**
- * Implements hook_field_settings_form().
- */
-function taxonomy_field_settings_form($field, $instance, $has_data) {
- // Get proper values for 'allowed_values_function', which is a core setting.
- $vocabularies = taxonomy_get_vocabularies();
- $options = array();
- foreach ($vocabularies as $vocabulary) {
- $options[$vocabulary->machine_name] = $vocabulary->name;
- }
- $form['allowed_values'] = array(
- '#tree' => TRUE,
- );
-
- foreach ($field['settings']['allowed_values'] as $delta => $tree) {
- $form['allowed_values'][$delta]['vocabulary'] = array(
- '#type' => 'select',
- '#title' => t('Vocabulary'),
- '#default_value' => $tree['vocabulary'],
- '#options' => $options,
- '#required' => TRUE,
- '#description' => t('The vocabulary which supplies the options for this field.'),
- '#disabled' => $has_data,
- );
- $form['allowed_values'][$delta]['parent'] = array(
- '#type' => 'value',
- '#value' => $tree['parent'],
- );
- }
-
- return $form;
-}
-
-/**
- * Implements hook_rdf_mapping().
- *
- * @return array
- * The rdf mapping for vocabularies and terms.
- */
-function taxonomy_rdf_mapping() {
- return array(
- array(
- 'type' => 'taxonomy_term',
- 'bundle' => RDF_DEFAULT_BUNDLE,
- 'mapping' => array(
- 'rdftype' => array('skos:Concept'),
- 'name' => array(
- 'predicates' => array('rdfs:label', 'skos:prefLabel'),
- ),
- 'description' => array(
- 'predicates' => array('skos:definition'),
- ),
- 'vid' => array(
- 'predicates' => array('skos:inScheme'),
- 'type' => 'rel',
- ),
- 'parent' => array(
- 'predicates' => array('skos:broader'),
- 'type' => 'rel',
- ),
- ),
- ),
- array(
- 'type' => 'taxonomy_vocabulary',
- 'bundle' => RDF_DEFAULT_BUNDLE,
- 'mapping' => array(
- 'rdftype' => array('skos:ConceptScheme'),
- 'name' => array(
- 'predicates' => array('dc:title'),
- ),
- 'description' => array(
- 'predicates' => array('rdfs:comment'),
- ),
- ),
- ),
- );
-}
-
-/**
- * @defgroup taxonomy_index Taxonomy indexing
- * @{
- * Functions to maintain taxonomy indexing.
- *
- * Taxonomy uses default field storage to store canonical relationships
- * between terms and fieldable entities. However its most common use case
- * requires listing all content associated with a term or group of terms
- * sorted by creation date. To avoid slow queries due to joining across
- * multiple node and field tables with various conditions and order by criteria,
- * we maintain a denormalized table with all relationships between terms,
- * published nodes and common sort criteria such as sticky and created.
- * This is used as a lookup table by taxonomy_select_nodes(). When using other
- * field storage engines or alternative methods of denormalizing this data
- * you should set the variable 'taxonomy_maintain_index_table' to FALSE
- * to avoid unnecessary writes in SQL.
- */
-
-/**
- * Implements hook_field_presave().
- *
- * Create any new terms defined in a freetagging vocabulary.
- */
-function taxonomy_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
- foreach ($items as $delta => $item) {
- if ($item['tid'] == 'autocreate') {
- $term = (object) $item;
- unset($term->tid);
- taxonomy_term_save($term);
- $items[$delta]['tid'] = $term->tid;
- }
- }
-}
-
-/**
- * Implements hook_node_insert().
- */
-function taxonomy_node_insert($node) {
- // Add taxonomy index entries for the node.
- taxonomy_build_node_index($node);
-}
-
-/**
- * Builds and inserts taxonomy index entries for a given node.
- *
- * The index lists all terms that are related to a given node entity, and is
- * therefore maintained at the entity level.
- *
- * @param $node
- * The node object.
- */
-function taxonomy_build_node_index($node) {
- // We maintain a denormalized table of term/node relationships, containing
- // only data for current, published nodes.
- $status = NULL;
- if (variable_get('taxonomy_maintain_index_table', TRUE)) {
- // If a node property is not set in the node object when node_save() is
- // called, the old value from $node->original is used.
- if (!empty($node->original)) {
- $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
- $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
- }
- else {
- $status = (int)(!empty($node->status));
- $sticky = (int)(!empty($node->sticky));
- }
- }
- // We only maintain the taxonomy index for published nodes.
- if ($status) {
- // Collect a unique list of all the term IDs from all node fields.
- $tid_all = array();
- foreach (field_info_instances('node', $node->type) as $instance) {
- $field_name = $instance['field_name'];
- $field = field_info_field($field_name);
- if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
- // If a field value is not set in the node object when node_save() is
- // called, the old value from $node->original is used.
- if (isset($node->{$field_name})) {
- $items = $node->{$field_name};
- }
- elseif (isset($node->original->{$field_name})) {
- $items = $node->original->{$field_name};
- }
- else {
- continue;
- }
- foreach (field_available_languages('node', $field) as $langcode) {
- if (!empty($items[$langcode])) {
- foreach ($items[$langcode] as $item) {
- $tid_all[$item['tid']] = $item['tid'];
- }
- }
- }
- }
- }
- // Insert index entries for all the node's terms.
- if (!empty($tid_all)) {
- $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
- foreach ($tid_all as $tid) {
- $query->values(array(
- 'nid' => $node->nid,
- 'tid' => $tid,
- 'sticky' => $sticky,
- 'created' => $node->created,
- ));
- }
- $query->execute();
- }
- }
-}
-
-/**
- * Implements hook_node_update().
- */
-function taxonomy_node_update($node) {
- // Always rebuild the node's taxonomy index entries on node save.
- taxonomy_delete_node_index($node);
- taxonomy_build_node_index($node);
-}
-
-/**
- * Implements hook_node_delete().
- */
-function taxonomy_node_delete($node) {
- // Clean up the {taxonomy_index} table when nodes are deleted.
- taxonomy_delete_node_index($node);
-}
-
-/**
- * Deletes taxonomy index entries for a given node.
- *
- * @param $node
- * The node object.
- */
-function taxonomy_delete_node_index($node) {
- if (variable_get('taxonomy_maintain_index_table', TRUE)) {
- db_delete('taxonomy_index')->condition('nid', $node->nid)->execute();
- }
-}
-
-/**
- * Implements hook_taxonomy_term_delete().
- */
-function taxonomy_taxonomy_term_delete($term) {
- if (variable_get('taxonomy_maintain_index_table', TRUE)) {
- // Clean up the {taxonomy_index} table when terms are deleted.
- db_delete('taxonomy_index')->condition('tid', $term->tid)->execute();
- }
-}
-
-/**
- * @} End of "defgroup taxonomy_index".
- */
-
-/**
- * Implements hook_entity_query_alter().
- *
- * Converts EntityFieldQuery instances on taxonomy terms that have an entity
- * condition on term bundles (vocabulary machine names). Since the vocabulary
- * machine name is not present in the {taxonomy_term_data} table itself, we have
- * to convert the bundle condition into a property condition of vocabulary IDs
- * to match against {taxonomy_term_data}.vid.
- */
-function taxonomy_entity_query_alter($query) {
- $conditions = &$query->entityConditions;
-
- // Alter only taxonomy term queries with bundle conditions.
- if (isset($conditions['entity_type']) && $conditions['entity_type']['value'] == 'taxonomy_term' && isset($conditions['bundle'])) {
- // Convert vocabulary machine names to vocabulary IDs.
- $vocabulary_data = taxonomy_vocabulary_get_names();
- $vids = array();
- if (is_array($conditions['bundle']['value'])) {
- foreach ($conditions['bundle']['value'] as $vocabulary_machine_name) {
- $vids[] = $vocabulary_data[$vocabulary_machine_name]->vid;
- }
- }
- else {
- $vocabulary_machine_name = $conditions['bundle']['value'];
- $vids = $vocabulary_data[$vocabulary_machine_name]->vid;
- }
-
- $query->propertyCondition('vid', $vids, $conditions['bundle']['operator']);
- unset($conditions['bundle']);
- }
-}
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
deleted file mode 100644
index 975ff120..00000000
--- a/modules/taxonomy/taxonomy.pages.inc
+++ /dev/null
@@ -1,181 +0,0 @@
-name);
-
- // Build breadcrumb based on the hierarchy of the term.
- $current = (object) array(
- 'tid' => $term->tid,
- );
- // @todo This overrides any other possible breadcrumb and is a pure hard-coded
- // presumption. Make this behavior configurable per vocabulary or term.
- $breadcrumb = array();
- while ($parents = taxonomy_get_parents($current->tid)) {
- $current = array_shift($parents);
- $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid);
- }
- $breadcrumb[] = l(t('Home'), NULL);
- $breadcrumb = array_reverse($breadcrumb);
- drupal_set_breadcrumb($breadcrumb);
- drupal_add_feed('taxonomy/term/' . $term->tid . '/feed', 'RSS - ' . $term->name);
-
- // Set the term path as the canonical URL to prevent duplicate content.
- $uri = entity_uri('taxonomy_term', $term);
- drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
- // Set the non-aliased path as a default shortlink.
- drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
-
- // Normally we would call taxonomy_term_show() here, but for backwards
- // compatibility in Drupal 7 we do not want to do that (it produces different
- // data structures and HTML markup than what Drupal 7 released with). Calling
- // taxonomy_term_view() directly provides essentially the same thing, but
- // allows us to wrap the rendered term in our desired array structure.
- $build['term_heading'] = array(
- '#prefix' => '',
- '#suffix' => '
',
- 'term' => taxonomy_term_view($term, 'full'),
- );
-
- if ($nids = taxonomy_select_nodes($term->tid, TRUE, variable_get('default_nodes_main', 10))) {
- $nodes = node_load_multiple($nids);
- $build += node_view_multiple($nodes);
- $build['pager'] = array(
- '#theme' => 'pager',
- '#weight' => 5,
- );
- }
- else {
- $build['no_content'] = array(
- '#prefix' => '',
- '#markup' => t('There is currently no content classified with this term.'),
- '#suffix' => '
',
- );
- }
- return $build;
-}
-
-/**
- * Generate the content feed for a taxonomy term.
- *
- * @param $term
- * The taxonomy term.
- */
-function taxonomy_term_feed($term) {
- $channel['link'] = url('taxonomy/term/' . $term->tid, array('absolute' => TRUE));
- $channel['title'] = variable_get('site_name', 'Drupal') . ' - ' . $term->name;
- // Only display the description if we have a single term, to avoid clutter and confusion.
- // HTML will be removed from feed description.
- $channel['description'] = check_markup($term->description, $term->format, '', TRUE);
- $nids = taxonomy_select_nodes($term->tid, FALSE, variable_get('feed_default_items', 10));
-
- node_feed($nids, $channel);
-}
-
-/**
- * Page callback: Outputs JSON for taxonomy autocomplete suggestions.
- *
- * Path: taxonomy/autocomplete
- *
- * This callback outputs term name suggestions in response to Ajax requests
- * made by the taxonomy autocomplete widget for taxonomy term reference
- * fields. The output is a JSON object of plain-text term suggestions, keyed by
- * the user-entered value with the completed term name appended. Term names
- * containing commas are wrapped in quotes.
- *
- * For example, suppose the user has entered the string 'red fish, blue' in the
- * field, and there are two taxonomy terms, 'blue fish' and 'blue moon'. The
- * JSON output would have the following structure:
- * @code
- * {
- * "red fish, blue fish": "blue fish",
- * "red fish, blue moon": "blue moon",
- * };
- * @endcode
- *
- * @param $field_name
- * The name of the term reference field.
- * @param $tags_typed
- * (optional) A comma-separated list of term names entered in the
- * autocomplete form element. Only the last term is used for autocompletion.
- * Defaults to '' (an empty string).
- *
- * @see taxonomy_menu()
- * @see taxonomy_field_widget_info()
- */
-function taxonomy_autocomplete($field_name = '', $tags_typed = '') {
- // If the request has a '/' in the search text, then the menu system will have
- // split it into multiple arguments, recover the intended $tags_typed.
- $args = func_get_args();
- // Shift off the $field_name argument.
- array_shift($args);
- $tags_typed = implode('/', $args);
-
- // Make sure the field exists and is a taxonomy field.
- if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') {
- // Error string. The JavaScript handler will realize this is not JSON and
- // will display it as debugging information.
- print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name));
- exit;
- }
-
- // The user enters a comma-separated list of tags. We only autocomplete the last tag.
- $tags_typed = drupal_explode_tags($tags_typed);
- $tag_last = drupal_strtolower(array_pop($tags_typed));
-
- $term_matches = array();
- if ($tag_last != '') {
-
- // Part of the criteria for the query come from the field's own settings.
- $vids = array();
- $vocabularies = taxonomy_vocabulary_get_names();
- foreach ($field['settings']['allowed_values'] as $tree) {
- $vids[] = $vocabularies[$tree['vocabulary']]->vid;
- }
-
- $query = db_select('taxonomy_term_data', 't');
- $query->addTag('translatable');
- $query->addTag('term_access');
-
- // Do not select already entered terms.
- if (!empty($tags_typed)) {
- $query->condition('t.name', $tags_typed, 'NOT IN');
- }
- // Select rows that match by term name.
- $tags_return = $query
- ->fields('t', array('tid', 'name'))
- ->condition('t.vid', $vids)
- ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')
- ->range(0, 10)
- ->execute()
- ->fetchAllKeyed();
-
- $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
-
- foreach ($tags_return as $tid => $name) {
- $n = $name;
- // Term names containing commas or quotes must be wrapped in quotes.
- if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
- $n = '"' . str_replace('"', '""', $name) . '"';
- }
- $term_matches[$prefix . $n] = check_plain($name);
- }
- }
-
- drupal_json_output($term_matches);
-}
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
deleted file mode 100644
index 665f9aeb..00000000
--- a/modules/taxonomy/taxonomy.test
+++ /dev/null
@@ -1,1980 +0,0 @@
-name = $this->randomName();
- $vocabulary->description = $this->randomName();
- $vocabulary->machine_name = drupal_strtolower($this->randomName());
- $vocabulary->help = '';
- $vocabulary->nodes = array('article' => 'article');
- $vocabulary->weight = mt_rand(0, 10);
- taxonomy_vocabulary_save($vocabulary);
- return $vocabulary;
- }
-
- /**
- * Returns a new term with random properties in vocabulary $vid.
- */
- function createTerm($vocabulary) {
- $term = new stdClass();
- $term->name = $this->randomName();
- $term->description = $this->randomName();
- // Use the first available text format.
- $term->format = db_query_range('SELECT format FROM {filter_format}', 0, 1)->fetchField();
- $term->vid = $vocabulary->vid;
- taxonomy_term_save($term);
- return $term;
- }
-
-}
-
-/**
- * Tests the taxonomy vocabulary interface.
- */
-class TaxonomyVocabularyFunctionalTest extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy vocabulary interface',
- 'description' => 'Test the taxonomy vocabulary interface.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy'));
- $this->drupalLogin($this->admin_user);
- $this->vocabulary = $this->createVocabulary();
- }
-
- /**
- * Create, edit and delete a vocabulary via the user interface.
- */
- function testVocabularyInterface() {
- // Visit the main taxonomy administration page.
- $this->drupalGet('admin/structure/taxonomy');
-
- // Create a new vocabulary.
- $this->clickLink(t('Add vocabulary'));
- $edit = array();
- $machine_name = drupal_strtolower($this->randomName());
- $edit['name'] = $this->randomName();
- $edit['description'] = $this->randomName();
- $edit['machine_name'] = $machine_name;
- $this->drupalPost(NULL, $edit, t('Save'));
- $this->assertRaw(t('Created new vocabulary %name.', array('%name' => $edit['name'])), 'Vocabulary created successfully.');
-
- // Edit the vocabulary.
- $this->drupalGet('admin/structure/taxonomy');
- $this->assertText($edit['name'], 'Vocabulary found in the vocabulary overview listing.');
- $this->clickLink(t('edit vocabulary'));
- $edit = array();
- $edit['name'] = $this->randomName();
- $this->drupalPost(NULL, $edit, t('Save'));
- $this->drupalGet('admin/structure/taxonomy');
- $this->assertText($edit['name'], 'Vocabulary found in the vocabulary overview listing.');
-
- // Try to submit a vocabulary with a duplicate machine name.
- $edit['machine_name'] = $machine_name;
- $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save'));
- $this->assertText(t('The machine-readable name is already in use. It must be unique.'));
-
- // Try to submit an invalid machine name.
- $edit['machine_name'] = '!&^%';
- $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save'));
- $this->assertText(t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
-
- // Ensure that vocabulary titles are escaped properly.
- $edit = array();
- $edit['name'] = 'Don\'t Panic';
- $edit['description'] = $this->randomName();
- $edit['machine_name'] = 'don_t_panic';
- $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save'));
-
- $site_name = variable_get('site_name', 'Drupal');
- $this->drupalGet('admin/structure/taxonomy/don_t_panic');
- $this->assertTitle(t('Don\'t Panic | @site-name', array('@site-name' => $site_name)));
- $this->assertNoTitle(t('Don't Panic | @site-name', array('@site-name' => $site_name)));
- }
-
- /**
- * Changing weights on the vocabulary overview with two or more vocabularies.
- */
- function testTaxonomyAdminChangingWeights() {
- // Create some vocabularies.
- for ($i = 0; $i < 10; $i++) {
- $this->createVocabulary();
- }
- // Get all vocabularies and change their weights.
- $vocabularies = taxonomy_get_vocabularies();
- $edit = array();
- foreach ($vocabularies as $key => $vocabulary) {
- $vocabulary->weight = -$vocabulary->weight;
- $vocabularies[$key]->weight = $vocabulary->weight;
- $edit[$key . '[weight]'] = $vocabulary->weight;
- }
- // Saving the new weights via the interface.
- $this->drupalPost('admin/structure/taxonomy', $edit, t('Save'));
-
- // Load the vocabularies from the database.
- $new_vocabularies = taxonomy_get_vocabularies();
-
- // Check that the weights are saved in the database correctly.
- foreach ($vocabularies as $key => $vocabulary) {
- $this->assertEqual($new_vocabularies[$key]->weight, $vocabularies[$key]->weight, 'The vocabulary weight was changed.');
- }
- }
-
- /**
- * Test the vocabulary overview with no vocabularies.
- */
- function testTaxonomyAdminNoVocabularies() {
- // Delete all vocabularies.
- $vocabularies = taxonomy_get_vocabularies();
- foreach ($vocabularies as $key => $vocabulary) {
- taxonomy_vocabulary_delete($key);
- }
- // Confirm that no vocabularies are found in the database.
- $this->assertFalse(taxonomy_get_vocabularies(), 'No vocabularies found in the database.');
- $this->drupalGet('admin/structure/taxonomy');
- // Check the default message for no vocabularies.
- $this->assertText(t('No vocabularies available.'), 'No vocabularies were found.');
- }
-
- /**
- * Deleting a vocabulary.
- */
- function testTaxonomyAdminDeletingVocabulary() {
- // Create a vocabulary.
- $edit = array(
- 'name' => $this->randomName(),
- 'machine_name' => drupal_strtolower($this->randomName()),
- );
- $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save'));
- $this->assertText(t('Created new vocabulary'), 'New vocabulary was created.');
-
- // Check the created vocabulary.
- $vocabularies = taxonomy_get_vocabularies();
- $vocabularies_keys = array_keys($vocabularies);
- $vid = $vocabularies[end($vocabularies_keys)]->vid;
- entity_get_controller('taxonomy_vocabulary')->resetCache();
- $vocabulary = taxonomy_vocabulary_load($vid);
- $this->assertTrue($vocabulary, 'Vocabulary found in database.');
-
- // Delete the vocabulary.
- $edit = array();
- $this->drupalPost('admin/structure/taxonomy/' . $vocabulary->machine_name . '/edit', $edit, t('Delete'));
- $this->assertRaw(t('Are you sure you want to delete the vocabulary %name?', array('%name' => $vocabulary->name)), '[confirm deletion] Asks for confirmation.');
- $this->assertText(t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'), '[confirm deletion] Inform that all terms will be deleted.');
-
- // Confirm deletion.
- $this->drupalPost(NULL, NULL, t('Delete'));
- $this->assertRaw(t('Deleted vocabulary %name.', array('%name' => $vocabulary->name)), 'Vocabulary deleted.');
- entity_get_controller('taxonomy_vocabulary')->resetCache();
- $this->assertFalse(taxonomy_vocabulary_load($vid), 'Vocabulary is not found in the database.');
- }
-
-}
-
-/**
- * Tests for taxonomy vocabulary functions.
- */
-class TaxonomyVocabularyTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy vocabularies',
- 'description' => 'Test loading, saving and deleting vocabularies.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy', 'field_test');
- $admin_user = $this->drupalCreateUser(array('create article content', 'administer taxonomy'));
- $this->drupalLogin($admin_user);
- $this->vocabulary = $this->createVocabulary();
- }
-
- /**
- * Ensure that when an invalid vocabulary vid is loaded, it is possible
- * to load the same vid successfully if it subsequently becomes valid.
- */
- function testTaxonomyVocabularyLoadReturnFalse() {
- // Load a vocabulary that doesn't exist.
- $vocabularies = taxonomy_get_vocabularies();
- $vid = count($vocabularies) + 1;
- $vocabulary = taxonomy_vocabulary_load($vid);
- // This should not return an object because no such vocabulary exists.
- $this->assertTrue(empty($vocabulary), 'No object loaded.');
-
- // Create a new vocabulary.
- $this->createVocabulary();
- // Load the vocabulary with the same $vid from earlier.
- // This should return a vocabulary object since it now matches a real vid.
- $vocabulary = taxonomy_vocabulary_load($vid);
- $this->assertTrue(!empty($vocabulary) && is_object($vocabulary), 'Vocabulary is an object.');
- $this->assertEqual($vocabulary->vid, $vid, 'Valid vocabulary vid is the same as our previously invalid one.');
- }
-
- /**
- * Test deleting a taxonomy that contains terms.
- */
- function testTaxonomyVocabularyDeleteWithTerms() {
- // Delete any existing vocabularies.
- foreach (taxonomy_get_vocabularies() as $vocabulary) {
- taxonomy_vocabulary_delete($vocabulary->vid);
- }
-
- // Assert that there are no terms left.
- $this->assertEqual(0, db_query('SELECT COUNT(*) FROM {taxonomy_term_data}')->fetchField());
-
- // Create a new vocabulary and add a few terms to it.
- $vocabulary = $this->createVocabulary();
- $terms = array();
- for ($i = 0; $i < 5; $i++) {
- $terms[$i] = $this->createTerm($vocabulary);
- }
-
- // Set up hierarchy. term 2 is a child of 1 and 4 a child of 1 and 2.
- $terms[2]->parent = array($terms[1]->tid);
- taxonomy_term_save($terms[2]);
- $terms[4]->parent = array($terms[1]->tid, $terms[2]->tid);
- taxonomy_term_save($terms[4]);
-
- // Assert that there are now 5 terms.
- $this->assertEqual(5, db_query('SELECT COUNT(*) FROM {taxonomy_term_data}')->fetchField());
-
- taxonomy_vocabulary_delete($vocabulary->vid);
-
- // Assert that there are no terms left.
- $this->assertEqual(0, db_query('SELECT COUNT(*) FROM {taxonomy_term_data}')->fetchField());
- }
-
- /**
- * Ensure that the vocabulary static reset works correctly.
- */
- function testTaxonomyVocabularyLoadStaticReset() {
- $original_vocabulary = taxonomy_vocabulary_load($this->vocabulary->vid);
- $this->assertTrue(is_object($original_vocabulary), 'Vocabulary loaded successfully.');
- $this->assertEqual($this->vocabulary->name, $original_vocabulary->name, 'Vocabulary loaded successfully.');
-
- // Change the name and description.
- $vocabulary = $original_vocabulary;
- $vocabulary->name = $this->randomName();
- $vocabulary->description = $this->randomName();
- taxonomy_vocabulary_save($vocabulary);
-
- // Load the vocabulary.
- $new_vocabulary = taxonomy_vocabulary_load($original_vocabulary->vid);
- $this->assertEqual($new_vocabulary->name, $vocabulary->name);
- $this->assertEqual($new_vocabulary->name, $vocabulary->name);
-
- // Delete the vocabulary.
- taxonomy_vocabulary_delete($this->vocabulary->vid);
- $vocabularies = taxonomy_get_vocabularies();
- $this->assertTrue(!isset($vocabularies[$this->vocabulary->vid]), 'The vocabulary was deleted.');
- }
-
- /**
- * Tests for loading multiple vocabularies.
- */
- function testTaxonomyVocabularyLoadMultiple() {
-
- // Delete any existing vocabularies.
- foreach (taxonomy_get_vocabularies() as $vocabulary) {
- taxonomy_vocabulary_delete($vocabulary->vid);
- }
-
- // Create some vocabularies and assign weights.
- $vocabulary1 = $this->createVocabulary();
- $vocabulary1->weight = 0;
- taxonomy_vocabulary_save($vocabulary1);
- $vocabulary2 = $this->createVocabulary();
- $vocabulary2->weight = 1;
- taxonomy_vocabulary_save($vocabulary2);
- $vocabulary3 = $this->createVocabulary();
- $vocabulary3->weight = 2;
- taxonomy_vocabulary_save($vocabulary3);
-
- // Fetch the names for all vocabularies, confirm that they are keyed by
- // machine name.
- $names = taxonomy_vocabulary_get_names();
- $this->assertEqual($names[$vocabulary1->machine_name]->name, $vocabulary1->name, 'Vocabulary 1 name found.');
-
- // Fetch all of the vocabularies using taxonomy_get_vocabularies().
- // Confirm that the vocabularies are ordered by weight.
- $vocabularies = taxonomy_get_vocabularies();
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary1->vid, 'Vocabulary was found in the vocabularies array.');
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary2->vid, 'Vocabulary was found in the vocabularies array.');
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary3->vid, 'Vocabulary was found in the vocabularies array.');
-
- // Fetch the vocabularies with taxonomy_vocabulary_load_multiple(), specifying IDs.
- // Ensure they are returned in the same order as the original array.
- $vocabularies = taxonomy_vocabulary_load_multiple(array($vocabulary3->vid, $vocabulary2->vid, $vocabulary1->vid));
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary3->vid, 'Vocabulary loaded successfully by ID.');
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary2->vid, 'Vocabulary loaded successfully by ID.');
- $this->assertEqual(array_shift($vocabularies)->vid, $vocabulary1->vid, 'Vocabulary loaded successfully by ID.');
-
- // Fetch vocabulary 1 by name.
- $vocabulary = current(taxonomy_vocabulary_load_multiple(array(), array('name' => $vocabulary1->name)));
- $this->assertEqual($vocabulary->vid, $vocabulary1->vid, 'Vocabulary loaded successfully by name.');
-
- // Fetch vocabulary 1 by name and ID.
- $this->assertEqual(current(taxonomy_vocabulary_load_multiple(array($vocabulary1->vid), array('name' => $vocabulary1->name)))->vid, $vocabulary1->vid, 'Vocabulary loaded successfully by name and ID.');
- }
-
- /**
- * Tests that machine name changes are properly reflected.
- */
- function testTaxonomyVocabularyChangeMachineName() {
- // Add a field instance to the vocabulary.
- $field = array(
- 'field_name' => 'field_test',
- 'type' => 'test_field',
- );
- field_create_field($field);
- $instance = array(
- 'field_name' => 'field_test',
- 'entity_type' => 'taxonomy_term',
- 'bundle' => $this->vocabulary->machine_name,
- );
- field_create_instance($instance);
-
- // Change the machine name.
- $new_name = drupal_strtolower($this->randomName());
- $this->vocabulary->machine_name = $new_name;
- taxonomy_vocabulary_save($this->vocabulary);
-
- // Check that the field instance is still attached to the vocabulary.
- $this->assertTrue(field_info_instance('taxonomy_term', 'field_test', $new_name), 'The bundle name was updated correctly.');
- }
-
- /**
- * Test uninstall and reinstall of the taxonomy module.
- */
- function testUninstallReinstall() {
- // Fields and field instances attached to taxonomy term bundles should be
- // removed when the module is uninstalled.
- $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
- $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
- $this->field = field_create_field($this->field);
- $this->instance = array(
- 'field_name' => $this->field_name,
- 'entity_type' => 'taxonomy_term',
- 'bundle' => $this->vocabulary->machine_name,
- 'label' => $this->randomName() . '_label',
- );
- field_create_instance($this->instance);
-
- module_disable(array('taxonomy'));
- require_once DRUPAL_ROOT . '/includes/install.inc';
- drupal_uninstall_modules(array('taxonomy'));
- module_enable(array('taxonomy'));
-
- // Now create a vocabulary with the same name. All field instances
- // connected to this vocabulary name should have been removed when the
- // module was uninstalled. Creating a new field with the same name and
- // an instance of this field on the same bundle name should be successful.
- unset($this->vocabulary->vid);
- taxonomy_vocabulary_save($this->vocabulary);
- unset($this->field['id']);
- field_create_field($this->field);
- field_create_instance($this->instance);
- }
-
-}
-
-/**
- * Unit tests for taxonomy term functions.
- */
-class TaxonomyTermFunctionTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term unit tests',
- 'description' => 'Unit tests for taxonomy term functions.',
- 'group' => 'Taxonomy',
- );
- }
-
- function testTermDelete() {
- $vocabulary = $this->createVocabulary();
- $valid_term = $this->createTerm($vocabulary);
- // Delete a valid term.
- taxonomy_term_delete($valid_term->tid);
- $terms = taxonomy_term_load_multiple(array(), array('vid' => $vocabulary->vid));
- $this->assertTrue(empty($terms), 'Vocabulary is empty after deletion.');
-
- // Delete an invalid term. Should not throw any notices.
- taxonomy_term_delete(42);
- }
-
- /**
- * Test a taxonomy with terms that have multiple parents of different depths.
- */
- function testTaxonomyVocabularyTree() {
- // Create a new vocabulary with 6 terms.
- $vocabulary = $this->createVocabulary();
- $term = array();
- for ($i = 0; $i < 6; $i++) {
- $term[$i] = $this->createTerm($vocabulary);
- }
-
- // $term[2] is a child of 1 and 5.
- $term[2]->parent = array($term[1]->tid, $term[5]->tid);
- taxonomy_term_save($term[2]);
- // $term[3] is a child of 2.
- $term[3]->parent = array($term[2]->tid);
- taxonomy_term_save($term[3]);
- // $term[5] is a child of 4.
- $term[5]->parent = array($term[4]->tid);
- taxonomy_term_save($term[5]);
-
- /**
- * Expected tree:
- * term[0] | depth: 0
- * term[1] | depth: 0
- * -- term[2] | depth: 1
- * ---- term[3] | depth: 2
- * term[4] | depth: 0
- * -- term[5] | depth: 1
- * ---- term[2] | depth: 2
- * ------ term[3] | depth: 3
- */
- // Count $term[1] parents with $max_depth = 1.
- $tree = taxonomy_get_tree($vocabulary->vid, $term[1]->tid, 1);
- $this->assertEqual(1, count($tree), 'We have one parent with depth 1.');
-
- // Count all vocabulary tree elements.
- $tree = taxonomy_get_tree($vocabulary->vid);
- $this->assertEqual(8, count($tree), 'We have all vocabulary tree elements.');
-
- // Count elements in every tree depth.
- foreach ($tree as $element) {
- if (!isset($depth_count[$element->depth])) {
- $depth_count[$element->depth] = 0;
- }
- $depth_count[$element->depth]++;
- }
- $this->assertEqual(3, $depth_count[0], 'Three elements in taxonomy tree depth 0.');
- $this->assertEqual(2, $depth_count[1], 'Two elements in taxonomy tree depth 1.');
- $this->assertEqual(2, $depth_count[2], 'Two elements in taxonomy tree depth 2.');
- $this->assertEqual(1, $depth_count[3], 'One element in taxonomy tree depth 3.');
- }
-
-}
-
-/**
- * Test for legacy node bug.
- */
-class TaxonomyLegacyTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Test for legacy node bug.',
- 'description' => 'Posts an article with a taxonomy term and a date prior to 1970.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy');
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'administer nodes', 'bypass node access'));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Test taxonomy functionality with nodes prior to 1970.
- */
- function testTaxonomyLegacyNode() {
- // Posts an article with a taxonomy term and a date prior to 1970.
- $langcode = LANGUAGE_NONE;
- $edit = array();
- $edit['title'] = $this->randomName();
- $edit['date'] = '1969-01-01 00:00:00 -0500';
- $edit["body[$langcode][0][value]"] = $this->randomName();
- $edit["field_tags[$langcode]"] = $this->randomName();
- $this->drupalPost('node/add/article', $edit, t('Save'));
- // Checks that the node has been saved.
- $node = $this->drupalGetNodeByTitle($edit['title']);
- $this->assertEqual($node->created, strtotime($edit['date']), 'Legacy node was saved with the right date.');
- }
-
-}
-
-/**
- * Tests for taxonomy term functions.
- */
-class TaxonomyTermTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term functions and forms.',
- 'description' => 'Test load, save and delete for taxonomy terms.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy');
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
- $this->drupalLogin($this->admin_user);
- $this->vocabulary = $this->createVocabulary();
-
- $field = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($field);
-
- $this->instance = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'bundle' => 'article',
- 'entity_type' => 'node',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance);
- }
-
- /**
- * Test terms in a single and multiple hierarchy.
- */
- function testTaxonomyTermHierarchy() {
- // Create two taxonomy terms.
- $term1 = $this->createTerm($this->vocabulary);
- $term2 = $this->createTerm($this->vocabulary);
-
- // Check that hierarchy is flat.
- $vocabulary = taxonomy_vocabulary_load($this->vocabulary->vid);
- $this->assertEqual(0, $vocabulary->hierarchy, 'Vocabulary is flat.');
-
- // Edit $term2, setting $term1 as parent.
- $edit = array();
- $edit['parent[]'] = array($term1->tid);
- $this->drupalPost('taxonomy/term/' . $term2->tid . '/edit', $edit, t('Save'));
-
- // Check the hierarchy.
- $children = taxonomy_get_children($term1->tid);
- $parents = taxonomy_get_parents($term2->tid);
- $this->assertTrue(isset($children[$term2->tid]), 'Child found correctly.');
- $this->assertTrue(isset($parents[$term1->tid]), 'Parent found correctly.');
-
- // Load and save a term, confirming that parents are still set.
- $term = taxonomy_term_load($term2->tid);
- taxonomy_term_save($term);
- $parents = taxonomy_get_parents($term2->tid);
- $this->assertTrue(isset($parents[$term1->tid]), 'Parent found correctly.');
-
- // Create a third term and save this as a parent of term2.
- $term3 = $this->createTerm($this->vocabulary);
- $term2->parent = array($term1->tid, $term3->tid);
- taxonomy_term_save($term2);
- $parents = taxonomy_get_parents($term2->tid);
- $this->assertTrue(isset($parents[$term1->tid]) && isset($parents[$term3->tid]), 'Both parents found successfully.');
- }
-
- /**
- * Test that hook_node_$op implementations work correctly.
- *
- * Save & edit a node and assert that taxonomy terms are saved/loaded properly.
- */
- function testTaxonomyNode() {
- // Create two taxonomy terms.
- $term1 = $this->createTerm($this->vocabulary);
- $term2 = $this->createTerm($this->vocabulary);
-
- // Post an article.
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $this->randomName();
- $edit["body[$langcode][0][value]"] = $this->randomName();
- $edit[$this->instance['field_name'] . '[' . $langcode . '][]'] = $term1->tid;
- $this->drupalPost('node/add/article', $edit, t('Save'));
-
- // Check that the term is displayed when the node is viewed.
- $node = $this->drupalGetNodeByTitle($edit["title"]);
- $this->drupalGet('node/' . $node->nid);
- $this->assertText($term1->name, 'Term is displayed when viewing the node.');
-
- // Edit the node with a different term.
- $edit[$this->instance['field_name'] . '[' . $langcode . '][]'] = $term2->tid;
- $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
-
- $this->drupalGet('node/' . $node->nid);
- $this->assertText($term2->name, 'Term is displayed when viewing the node.');
-
- // Preview the node.
- $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Preview'));
- $this->assertNoUniqueText($term2->name, 'Term is displayed when previewing the node.');
- $this->drupalPost(NULL, NULL, t('Preview'));
- $this->assertNoUniqueText($term2->name, 'Term is displayed when previewing the node again.');
- }
-
- /**
- * Test term creation with a free-tagging vocabulary from the node form.
- */
- function testNodeTermCreationAndDeletion() {
- // Enable tags in the vocabulary.
- $instance = $this->instance;
- $instance['widget'] = array('type' => 'taxonomy_autocomplete');
- $instance['bundle'] = 'page';
- field_create_instance($instance);
- $terms = array(
- 'term1' => $this->randomName(),
- 'term2' => $this->randomName() . ', ' . $this->randomName(),
- 'term3' => $this->randomName(),
- );
-
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $this->randomName();
- $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]"] = drupal_implode_tags($terms);
-
- // Preview and verify the terms appear but are not created.
- $this->drupalPost('node/add/page', $edit, t('Preview'));
- foreach ($terms as $term) {
- $this->assertText($term, 'The term appears on the node preview.');
- }
- $tree = taxonomy_get_tree($this->vocabulary->vid);
- $this->assertTrue(empty($tree), 'The terms are not created on preview.');
-
- // taxonomy.module does not maintain its static caches.
- drupal_static_reset();
-
- // Save, creating the terms.
- $this->drupalPost('node/add/page', $edit, t('Save'));
- $this->assertRaw(t('@type %title has been created.', array('@type' => t('Basic page'), '%title' => $edit["title"])), 'The node was created successfully.');
- foreach ($terms as $term) {
- $this->assertText($term, 'The term was saved and appears on the node page.');
- }
-
- // Get the created terms.
- $term_objects = array();
- foreach ($terms as $key => $term) {
- $term_objects[$key] = taxonomy_get_term_by_name($term);
- $term_objects[$key] = reset($term_objects[$key]);
- }
-
- // Delete term 1.
- $this->drupalPost('taxonomy/term/' . $term_objects['term1']->tid . '/edit', array(), t('Delete'));
- $this->drupalPost(NULL, NULL, t('Delete'));
- $term_names = array($term_objects['term2']->name, $term_objects['term3']->name);
-
- // Get the node.
- $node = $this->drupalGetNodeByTitle($edit["title"]);
- $this->drupalGet('node/' . $node->nid);
-
- foreach ($term_names as $term_name) {
- $this->assertText($term_name, format_string('The term %name appears on the node page after one term %deleted was deleted', array('%name' => $term_name, '%deleted' => $term_objects['term1']->name)));
- }
- $this->assertNoText($term_objects['term1']->name, format_string('The deleted term %name does not appear on the node page.', array('%name' => $term_objects['term1']->name)));
-
- // Test autocomplete on term 2, which contains a comma.
- // The term will be quoted, and the " will be encoded in unicode (\u0022).
- $input = substr($term_objects['term2']->name, 0, 3);
- $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input);
- $this->assertRaw('{"\u0022' . $term_objects['term2']->name . '\u0022":"' . $term_objects['term2']->name . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term2']->name)));
-
- // Test autocomplete on term 3 - it is alphanumeric only, so no extra
- // quoting.
- $input = substr($term_objects['term3']->name, 0, 3);
- $this->drupalGet('taxonomy/autocomplete/taxonomy_' . $this->vocabulary->machine_name . '/' . $input);
- $this->assertRaw('{"' . $term_objects['term3']->name . '":"' . $term_objects['term3']->name . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term3']->name)));
-
- // Test taxonomy autocomplete with a nonexistent field.
- $field_name = $this->randomName();
- $tag = $this->randomName();
- $message = t("Taxonomy field @field_name not found.", array('@field_name' => $field_name));
- $this->assertFalse(field_info_field($field_name), format_string('Field %field_name does not exist.', array('%field_name' => $field_name)));
- $this->drupalGet('taxonomy/autocomplete/' . $field_name . '/' . $tag);
- $this->assertRaw($message, 'Autocomplete returns correct error message when the taxonomy field does not exist.');
-
- // Test the autocomplete path without passing a field_name and terms.
- // This should not trigger a PHP notice.
- $field_name = '';
- $message = t("Taxonomy field @field_name not found.", array('@field_name' => $field_name));
- $this->drupalGet('taxonomy/autocomplete');
- $this->assertRaw($message, 'Autocomplete returns correct error message when no taxonomy field is given.');
- }
-
- /**
- * Tests term autocompletion edge cases with slashes in the names.
- */
- function testTermAutocompletion() {
- // Add a term with a slash in the name.
- $first_term = $this->createTerm($this->vocabulary);
- $first_term->name = '10/16/2011';
- taxonomy_term_save($first_term);
- // Add another term that differs after the slash character.
- $second_term = $this->createTerm($this->vocabulary);
- $second_term->name = '10/17/2011';
- taxonomy_term_save($second_term);
- // Add another term that has both a comma and a slash character.
- $third_term = $this->createTerm($this->vocabulary);
- $third_term->name = 'term with, a comma and / a slash';
- taxonomy_term_save($third_term);
-
- // Try to autocomplete a term name that matches both terms.
- // We should get both term in a json encoded string.
- $input = '10/';
- $path = 'taxonomy/autocomplete/taxonomy_';
- $path .= $this->vocabulary->machine_name . '/' . $input;
- // The result order is not guaranteed, so check each term separately.
- $url = url($path, array('absolute' => TRUE));
- $result = drupal_http_request($url);
- $data = drupal_json_decode($result->data);
- $this->assertEqual($data[$first_term->name], check_plain($first_term->name), 'Autocomplete returned the first matching term.');
- $this->assertEqual($data[$second_term->name], check_plain($second_term->name), 'Autocomplete returned the second matching term.');
-
- // Try to autocomplete a term name that matches first term.
- // We should only get the first term in a json encoded string.
- $input = '10/16';
- $url = 'taxonomy/autocomplete/taxonomy_';
- $url .= $this->vocabulary->machine_name . '/' . $input;
- $this->drupalGet($url);
- $target = array($first_term->name => check_plain($first_term->name));
- $this->assertRaw(drupal_json_encode($target), 'Autocomplete returns only the expected matching term.');
-
- // Try to autocomplete a term name with both a comma and a slash.
- $input = '"term with, comma and / a';
- $url = 'taxonomy/autocomplete/taxonomy_';
- $url .= $this->vocabulary->machine_name . '/' . $input;
- $this->drupalGet($url);
- $n = $third_term->name;
- // Term names containing commas or quotes must be wrapped in quotes.
- if (strpos($third_term->name, ',') !== FALSE || strpos($third_term->name, '"') !== FALSE) {
- $n = '"' . str_replace('"', '""', $third_term->name) . '"';
- }
- $target = array($n => check_plain($third_term->name));
- $this->assertRaw(drupal_json_encode($target), 'Autocomplete returns a term containing a comma and a slash.');
- }
-
- /**
- * Save, edit and delete a term using the user interface.
- */
- function testTermInterface() {
- $edit = array(
- 'name' => $this->randomName(12),
- 'description[value]' => $this->randomName(100),
- );
- // Explicitly set the parents field to 'root', to ensure that
- // taxonomy_form_term_submit() handles the invalid term ID correctly.
- $edit['parent[]'] = array(0);
-
- // Create the term to edit.
- $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add', $edit, t('Save'));
-
- $terms = taxonomy_get_term_by_name($edit['name']);
- $term = reset($terms);
- $this->assertNotNull($term, 'Term found in database.');
-
- // Submitting a term takes us to the add page; we need the List page.
- $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name);
-
- // Test edit link as accessed from Taxonomy administration pages.
- // Because Simpletest creates its own database when running tests, we know
- // the first edit link found on the listing page is to our term.
- $this->clickLink(t('edit'));
-
- $this->assertRaw($edit['name'], 'The randomly generated term name is present.');
- $this->assertText($edit['description[value]'], 'The randomly generated term description is present.');
-
- $edit = array(
- 'name' => $this->randomName(14),
- 'description[value]' => $this->randomName(102),
- );
-
- // Edit the term.
- $this->drupalPost('taxonomy/term/' . $term->tid . '/edit', $edit, t('Save'));
-
- // Check that the term is still present at admin UI after edit.
- $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name);
- $this->assertText($edit['name'], 'The randomly generated term name is present.');
- $this->assertLink(t('edit'));
-
- // View the term and check that it is correct.
- $this->drupalGet('taxonomy/term/' . $term->tid);
- $this->assertText($edit['name'], 'The randomly generated term name is present.');
- $this->assertText($edit['description[value]'], 'The randomly generated term description is present.');
-
- // Did this page request display a 'term-listing-heading'?
- $this->assertPattern('|class="taxonomy-term-description"|', 'Term page displayed the term description element.');
- // Check that it does NOT show a description when description is blank.
- $term->description = '';
- taxonomy_term_save($term);
- $this->drupalGet('taxonomy/term/' . $term->tid);
- $this->assertNoPattern('|class="taxonomy-term-description"|', 'Term page did not display the term description when description was blank.');
-
- // Check that the term feed page is working.
- $this->drupalGet('taxonomy/term/' . $term->tid . '/feed');
-
- // Check that the term edit page does not try to interpret additional path
- // components as arguments for taxonomy_form_term().
- $this->drupalGet('taxonomy/term/' . $term->tid . '/edit/' . $this->randomName());
-
- // Delete the term.
- $this->drupalPost('taxonomy/term/' . $term->tid . '/edit', array(), t('Delete'));
- $this->drupalPost(NULL, NULL, t('Delete'));
-
- // Assert that the term no longer exists.
- $this->drupalGet('taxonomy/term/' . $term->tid);
- $this->assertResponse(404, 'The taxonomy term page was not found.');
- }
-
- /**
- * Save, edit and delete a term using the user interface.
- */
- function testTermReorder() {
- $this->createTerm($this->vocabulary);
- $this->createTerm($this->vocabulary);
- $this->createTerm($this->vocabulary);
-
- // Fetch the created terms in the default alphabetical order, i.e. term1
- // precedes term2 alphabetically, and term2 precedes term3.
- drupal_static_reset('taxonomy_get_tree');
- drupal_static_reset('taxonomy_get_treeparent');
- drupal_static_reset('taxonomy_get_treeterms');
- list($term1, $term2, $term3) = taxonomy_get_tree($this->vocabulary->vid);
-
- $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name);
-
- // Each term has four hidden fields, "tid:1:0[tid]", "tid:1:0[parent]",
- // "tid:1:0[depth]", and "tid:1:0[weight]". Change the order to term2,
- // term3, term1 by setting weight property, make term3 a child of term2 by
- // setting the parent and depth properties, and update all hidden fields.
- $edit = array(
- 'tid:' . $term2->tid . ':0[tid]' => $term2->tid,
- 'tid:' . $term2->tid . ':0[parent]' => 0,
- 'tid:' . $term2->tid . ':0[depth]' => 0,
- 'tid:' . $term2->tid . ':0[weight]' => 0,
- 'tid:' . $term3->tid . ':0[tid]' => $term3->tid,
- 'tid:' . $term3->tid . ':0[parent]' => $term2->tid,
- 'tid:' . $term3->tid . ':0[depth]' => 1,
- 'tid:' . $term3->tid . ':0[weight]' => 1,
- 'tid:' . $term1->tid . ':0[tid]' => $term1->tid,
- 'tid:' . $term1->tid . ':0[parent]' => 0,
- 'tid:' . $term1->tid . ':0[depth]' => 0,
- 'tid:' . $term1->tid . ':0[weight]' => 2,
- );
- $this->drupalPost(NULL, $edit, t('Save'));
-
- drupal_static_reset('taxonomy_get_tree');
- drupal_static_reset('taxonomy_get_treeparent');
- drupal_static_reset('taxonomy_get_treeterms');
- $terms = taxonomy_get_tree($this->vocabulary->vid);
- $this->assertEqual($terms[0]->tid, $term2->tid, 'Term 2 was moved above term 1.');
- $this->assertEqual($terms[1]->parents, array($term2->tid), 'Term 3 was made a child of term 2.');
- $this->assertEqual($terms[2]->tid, $term1->tid, 'Term 1 was moved below term 2.');
-
- $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name, array(), t('Reset to alphabetical'));
- // Submit confirmation form.
- $this->drupalPost(NULL, array(), t('Reset to alphabetical'));
-
- drupal_static_reset('taxonomy_get_tree');
- drupal_static_reset('taxonomy_get_treeparent');
- drupal_static_reset('taxonomy_get_treeterms');
- $terms = taxonomy_get_tree($this->vocabulary->vid);
- $this->assertEqual($terms[0]->tid, $term1->tid, 'Term 1 was moved to back above term 2.');
- $this->assertEqual($terms[1]->tid, $term2->tid, 'Term 2 was moved to back below term 1.');
- $this->assertEqual($terms[2]->tid, $term3->tid, 'Term 3 is still below term 2.');
- $this->assertEqual($terms[2]->parents, array($term2->tid), '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, 'Term found in database.');
- $this->assertEqual($edit['name'], $term->name, 'Term name was successfully saved.');
- $this->assertEqual($edit['description[value]'], $term->description, 'Term description was successfully saved.');
- // Check that the parent tid is still there. The other parent () is
- // not added by taxonomy_get_parents().
- $parents = taxonomy_get_parents($term->tid);
- $parent = reset($parents);
- $this->assertEqual($edit['parent[]'][1], $parent->tid, 'Term parents were successfully saved.');
- }
-
- /**
- * Test taxonomy_get_term_by_name().
- */
- function testTaxonomyGetTermByName() {
- $term = $this->createTerm($this->vocabulary);
-
- // Load the term with the exact name.
- $terms = taxonomy_get_term_by_name($term->name);
- $this->assertTrue(isset($terms[$term->tid]), 'Term loaded using exact name.');
-
- // Load the term with space concatenated.
- $terms = taxonomy_get_term_by_name(' ' . $term->name . ' ');
- $this->assertTrue(isset($terms[$term->tid]), 'Term loaded with extra whitespace.');
-
- // Load the term with name uppercased.
- $terms = taxonomy_get_term_by_name(strtoupper($term->name));
- $this->assertTrue(isset($terms[$term->tid]), 'Term loaded with uppercased name.');
-
- // Load the term with name lowercased.
- $terms = taxonomy_get_term_by_name(strtolower($term->name));
- $this->assertTrue(isset($terms[$term->tid]), 'Term loaded with lowercased name.');
-
- // Try to load an invalid term name.
- $terms = taxonomy_get_term_by_name('Banana');
- $this->assertFalse($terms);
-
- // Try to load the term using a substring of the name.
- $terms = taxonomy_get_term_by_name(drupal_substr($term->name, 2));
- $this->assertFalse($terms);
-
- // Create a new term in a different vocabulary with the same name.
- $new_vocabulary = $this->createVocabulary();
- $new_term = new stdClass();
- $new_term->name = $term->name;
- $new_term->vid = $new_vocabulary->vid;
- taxonomy_term_save($new_term);
-
- // Load multiple terms with the same name.
- $terms = taxonomy_get_term_by_name($term->name);
- $this->assertEqual(count($terms), 2, 'Two terms loaded with the same name.');
-
- // Load single term when restricted to one vocabulary.
- $terms = taxonomy_get_term_by_name($term->name, $this->vocabulary->machine_name);
- $this->assertEqual(count($terms), 1, 'One term loaded when restricted by vocabulary.');
- $this->assertTrue(isset($terms[$term->tid]), 'Term loaded using exact name and vocabulary machine name.');
-
- // Create a new term with another name.
- $term2 = $this->createTerm($this->vocabulary);
-
- // Try to load a term by name that doesn't exist in this vocabulary but
- // exists in another vocabulary.
- $terms = taxonomy_get_term_by_name($term2->name, $new_vocabulary->machine_name);
- $this->assertFalse($terms, 'Invalid term name restricted by vocabulary machine name not loaded.');
-
- // Try to load terms filtering by a non-existing vocabulary.
- $terms = taxonomy_get_term_by_name($term2->name, 'non_existing_vocabulary');
- $this->assertEqual(count($terms), 0, 'No terms loaded when restricted by a non-existing vocabulary.');
- }
-
-}
-
-/**
- * Tests the rendering of term reference fields in RSS feeds.
- */
-class TaxonomyRSSTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy RSS Content.',
- 'description' => 'Ensure that data added as terms appears in RSS feeds if "RSS Category" format is selected.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy');
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types'));
- $this->drupalLogin($this->admin_user);
- $this->vocabulary = $this->createVocabulary();
-
- $field = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($field);
-
- $this->instance = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'bundle' => 'article',
- 'entity_type' => 'node',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance);
- }
-
- /**
- * Tests that terms added to nodes are displayed in core RSS feed.
- *
- * Create a node and assert that taxonomy terms appear in rss.xml.
- */
- function testTaxonomyRSS() {
- // Create two taxonomy terms.
- $term1 = $this->createTerm($this->vocabulary);
-
- // RSS display must be added manually.
- $this->drupalGet("admin/structure/types/manage/article/display");
- $edit = array(
- "view_modes_custom[rss]" => '1',
- );
- $this->drupalPost(NULL, $edit, t('Save'));
-
- // Change the format to 'RSS category'.
- $this->drupalGet("admin/structure/types/manage/article/display/rss");
- $edit = array(
- "fields[taxonomy_" . $this->vocabulary->machine_name . "][type]" => 'taxonomy_term_reference_rss_category',
- );
- $this->drupalPost(NULL, $edit, t('Save'));
-
- // Post an article.
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $this->randomName();
- $edit[$this->instance['field_name'] . '[' . $langcode . '][]'] = $term1->tid;
- $this->drupalPost('node/add/article', $edit, t('Save'));
-
- // Check that the term is displayed when the RSS feed is viewed.
- $this->drupalGet('rss.xml');
- $test_element = array(
- 'key' => 'category',
- 'value' => $term1->name,
- 'attributes' => array(
- 'domain' => url('taxonomy/term/' . $term1->tid, array('absolute' => TRUE)),
- ),
- );
- $this->assertRaw(format_xml_elements(array($test_element)), 'Term is displayed when viewing the rss feed.');
- }
-
-}
-
-/**
- * Tests the hook implementations that maintain the taxonomy index.
- */
-class TaxonomyTermIndexTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term index',
- 'description' => 'Tests the hook implementations that maintain the taxonomy index.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy');
-
- // Create an administrative user.
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
- $this->drupalLogin($this->admin_user);
-
- // Create a vocabulary and add two term reference fields to article nodes.
- $this->vocabulary = $this->createVocabulary();
-
- $this->field_name_1 = drupal_strtolower($this->randomName());
- $this->field_1 = array(
- 'field_name' => $this->field_name_1,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($this->field_1);
- $this->instance_1 = array(
- 'field_name' => $this->field_name_1,
- 'bundle' => 'article',
- 'entity_type' => 'node',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance_1);
-
- $this->field_name_2 = drupal_strtolower($this->randomName());
- $this->field_2 = array(
- 'field_name' => $this->field_name_2,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($this->field_2);
- $this->instance_2 = array(
- 'field_name' => $this->field_name_2,
- 'bundle' => 'article',
- 'entity_type' => 'node',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance_2);
- }
-
- /**
- * Tests that the taxonomy index is maintained properly.
- */
- function testTaxonomyIndex() {
- // Create terms in the vocabulary.
- $term_1 = $this->createTerm($this->vocabulary);
- $term_2 = $this->createTerm($this->vocabulary);
-
- // Post an article.
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $this->randomName();
- $edit["body[$langcode][0][value]"] = $this->randomName();
- $edit["{$this->field_name_1}[$langcode][]"] = $term_1->tid;
- $edit["{$this->field_name_2}[$langcode][]"] = $term_1->tid;
- $this->drupalPost('node/add/article', $edit, t('Save'));
-
- // Check that the term is indexed, and only once.
- $node = $this->drupalGetNodeByTitle($edit["title"]);
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 1 is indexed once.');
-
- // Update the article to change one term.
- $edit["{$this->field_name_1}[$langcode][]"] = $term_2->tid;
- $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
-
- // Check that both terms are indexed.
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 1 is indexed.');
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_2->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 2 is indexed.');
-
- // Update the article to change another term.
- $edit["{$this->field_name_2}[$langcode][]"] = $term_2->tid;
- $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
-
- // Check that only one term is indexed.
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(0, $index_count, 'Term 1 is not indexed.');
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_2->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 2 is indexed once.');
-
- // Redo the above tests without interface.
- $update_node = array(
- 'nid' => $node->nid,
- 'vid' => $node->vid,
- 'uid' => $node->uid,
- 'type' => $node->type,
- 'title' => $this->randomName(),
- );
-
- // Update the article with no term changed.
- $updated_node = (object) $update_node;
- node_save($updated_node);
-
- // Check that the index was not changed.
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(0, $index_count, 'Term 1 is not indexed.');
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_2->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 2 is indexed once.');
-
- // Update the article to change one term.
- $update_node[$this->field_name_1][$langcode] = array(array('tid' => $term_1->tid));
- $updated_node = (object) $update_node;
- node_save($updated_node);
-
- // Check that both terms are indexed.
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 1 is indexed.');
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_2->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 2 is indexed.');
-
- // Update the article to change another term.
- $update_node[$this->field_name_2][$langcode] = array(array('tid' => $term_1->tid));
- $updated_node = (object) $update_node;
- node_save($updated_node);
-
- // Check that only one term is indexed.
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_1->tid,
- ))->fetchField();
- $this->assertEqual(1, $index_count, 'Term 1 is indexed once.');
- $index_count = db_query('SELECT COUNT(*) FROM {taxonomy_index} WHERE nid = :nid AND tid = :tid', array(
- ':nid' => $node->nid,
- ':tid' => $term_2->tid,
- ))->fetchField();
- $this->assertEqual(0, $index_count, 'Term 2 is not indexed.');
- }
-
- /**
- * Tests that there is a link to the parent term on the child term page.
- */
- function testTaxonomyTermHierarchyBreadcrumbs() {
- // Create two taxonomy terms and set term2 as the parent of term1.
- $term1 = $this->createTerm($this->vocabulary);
- $term2 = $this->createTerm($this->vocabulary);
- $term1->parent = array($term2->tid);
- taxonomy_term_save($term1);
-
- // Verify that the page breadcrumbs include a link to the parent term.
- $this->drupalGet('taxonomy/term/' . $term1->tid);
- $this->assertRaw(l($term2->name, 'taxonomy/term/' . $term2->tid), 'Parent term link is displayed when viewing the node.');
- }
-
-}
-
-/**
- * Test the taxonomy_term_load_multiple() function.
- */
-class TaxonomyLoadMultipleTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term multiple loading',
- 'description' => 'Test the loading of multiple taxonomy terms at once',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy'));
- $this->drupalLogin($this->taxonomy_admin);
- }
-
- /**
- * Create a vocabulary and some taxonomy terms, ensuring they're loaded
- * correctly using taxonomy_term_load_multiple().
- */
- function testTaxonomyTermMultipleLoad() {
- // Create a vocabulary.
- $vocabulary = $this->createVocabulary();
-
- // Create five terms in the vocabulary.
- $i = 0;
- while ($i < 5) {
- $i++;
- $this->createTerm($vocabulary);
- }
- // Load the terms from the vocabulary.
- $terms = taxonomy_term_load_multiple(NULL, array('vid' => $vocabulary->vid));
- $count = count($terms);
- $this->assertEqual($count, 5, format_string('Correct number of terms were loaded. !count terms.', array('!count' => $count)));
-
- // Load the same terms again by tid.
- $terms2 = taxonomy_term_load_multiple(array_keys($terms));
- $this->assertEqual($count, count($terms2), 'Five terms were loaded by tid.');
- $this->assertEqual($terms, $terms2, 'Both arrays contain the same terms.');
-
- // Load the terms by tid, with a condition on vid.
- $terms3 = taxonomy_term_load_multiple(array_keys($terms2), array('vid' => $vocabulary->vid));
- $this->assertEqual($terms2, $terms3);
-
- // Remove one term from the array, then delete it.
- $deleted = array_shift($terms3);
- taxonomy_term_delete($deleted->tid);
- $deleted_term = taxonomy_term_load($deleted->tid);
- $this->assertFalse($deleted_term);
-
- // Load terms from the vocabulary by vid.
- $terms4 = taxonomy_term_load_multiple(NULL, array('vid' => $vocabulary->vid));
- $this->assertEqual(count($terms4), 4, 'Correct number of terms were loaded.');
- $this->assertFalse(isset($terms4[$deleted->tid]));
-
- // Create a single term and load it by name.
- $term = $this->createTerm($vocabulary);
- $loaded_terms = taxonomy_term_load_multiple(array(), array('name' => $term->name));
- $this->assertEqual(count($loaded_terms), 1, 'One term was loaded.');
- $loaded_term = reset($loaded_terms);
- $this->assertEqual($term->tid, $loaded_term->tid, 'Term loaded by name successfully.');
- }
-}
-
-/**
- * Tests for taxonomy hook invocation.
- */
-class TaxonomyHooksTestCase extends TaxonomyWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term hooks',
- 'description' => 'Hooks for taxonomy term load/save/delete.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('taxonomy', 'taxonomy_test');
- module_load_include('inc', 'taxonomy', 'taxonomy.pages');
- $taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy'));
- $this->drupalLogin($taxonomy_admin);
- }
-
- /**
- * Test that hooks are run correctly on creating, editing, viewing,
- * and deleting a term.
- *
- * @see taxonomy_test.module
- */
- function testTaxonomyTermHooks() {
- $vocabulary = $this->createVocabulary();
-
- // Create a term with one antonym.
- $edit = array(
- 'name' => $this->randomName(),
- 'antonym' => 'Long',
- );
- $this->drupalPost('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add', $edit, t('Save'));
- $terms = taxonomy_get_term_by_name($edit['name']);
- $term = reset($terms);
- $this->assertEqual($term->antonym, $edit['antonym'], 'Antonym was loaded into the term object.');
-
- // Update the term with a different antonym.
- $edit = array(
- 'name' => $this->randomName(),
- 'antonym' => 'Short',
- );
- $this->drupalPost('taxonomy/term/' . $term->tid . '/edit', $edit, t('Save'));
- taxonomy_terms_static_reset();
- $term = taxonomy_term_load($term->tid);
- $this->assertEqual($edit['antonym'], $term->antonym, 'Antonym was successfully edited.');
-
- // View the term and ensure that hook_taxonomy_term_view() and
- // hook_entity_view() are invoked.
- $term = taxonomy_term_load($term->tid);
- $term_build = taxonomy_term_page($term);
- $this->assertFalse(empty($term_build['term_heading']['term']['taxonomy_test_term_view_check']), 'hook_taxonomy_term_view() was invoked when viewing the term.');
- $this->assertFalse(empty($term_build['term_heading']['term']['taxonomy_test_entity_view_check']), 'hook_entity_view() was invoked when viewing the term.');
-
- // Delete the term.
- taxonomy_term_delete($term->tid);
- $antonym = db_query('SELECT tid FROM {taxonomy_term_antonym} WHERE tid = :tid', array(':tid' => $term->tid))->fetchField();
- $this->assertFalse($antonym, 'The antonym were deleted from the database.');
- }
-
-}
-
-/**
- * Tests for taxonomy term field and formatter.
- */
-class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
-
- protected $instance;
- protected $vocabulary;
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy term reference field',
- 'description' => 'Test the creation of term fields.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('field_test');
-
- $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer taxonomy'));
- $this->drupalLogin($web_user);
- $this->vocabulary = $this->createVocabulary();
-
- // Setup a field and instance.
- $this->field_name = drupal_strtolower($this->randomName());
- $this->field = array(
- 'field_name' => $this->field_name,
- 'type' => 'taxonomy_term_reference',
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => '0',
- ),
- ),
- )
- );
- field_create_field($this->field);
- $this->instance = array(
- 'field_name' => $this->field_name,
- 'entity_type' => 'test_entity',
- 'bundle' => 'test_bundle',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'full' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance);
- }
-
- /**
- * Test term field validation.
- */
- function testTaxonomyTermFieldValidation() {
- // Test valid and invalid values with field_attach_validate().
- $langcode = LANGUAGE_NONE;
- $entity = field_test_create_stub_entity();
- $term = $this->createTerm($this->vocabulary);
- $entity->{$this->field_name}[$langcode][0]['tid'] = $term->tid;
- try {
- field_attach_validate('test_entity', $entity);
- $this->pass('Correct term does not cause validation error.');
- }
- catch (FieldValidationException $e) {
- $this->fail('Correct term does not cause validation error.');
- }
-
- $entity = field_test_create_stub_entity();
- $bad_term = $this->createTerm($this->createVocabulary());
- $entity->{$this->field_name}[$langcode][0]['tid'] = $bad_term->tid;
- try {
- field_attach_validate('test_entity', $entity);
- $this->fail('Wrong term causes validation error.');
- }
- catch (FieldValidationException $e) {
- $this->pass('Wrong term causes validation error.');
- }
- }
-
- /**
- * Test widgets.
- */
- function testTaxonomyTermFieldWidgets() {
- // Create a term in the vocabulary.
- $term = $this->createTerm($this->vocabulary);
-
- // Display creation form.
- $langcode = LANGUAGE_NONE;
- $this->drupalGet('test-entity/add/test-bundle');
- $this->assertFieldByName("{$this->field_name}[$langcode]", '', 'Widget is displayed.');
-
- // Submit with some value.
- $edit = array(
- "{$this->field_name}[$langcode]" => array($term->tid),
- );
- $this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
- $id = $match[1];
- $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
-
- // Display the object.
- $entity = field_test_entity_test_load($id);
- $entities = array($id => $entity);
- field_attach_prepare_view('test_entity', $entities, 'full');
- $entity->content = field_attach_view('test_entity', $entity, 'full');
- $this->content = drupal_render($entity->content);
- $this->assertText($term->name, 'Term name is displayed.');
-
- // Delete the vocabulary and verify that the widget is gone.
- taxonomy_vocabulary_delete($this->vocabulary->vid);
- $this->drupalGet('test-entity/add/test-bundle');
- $this->assertNoFieldByName("{$this->field_name}[$langcode]", '', 'Widget is not displayed.');
- }
-
- /**
- * Tests that vocabulary machine name changes are mirrored in field definitions.
- */
- function testTaxonomyTermFieldChangeMachineName() {
- // Add several entries in the 'allowed_values' setting, to make sure that
- // they all get updated.
- $this->field['settings']['allowed_values'] = array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => '0',
- ),
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => '0',
- ),
- array(
- 'vocabulary' => 'foo',
- 'parent' => '0',
- ),
- );
- field_update_field($this->field);
- // Change the machine name.
- $old_name = $this->vocabulary->machine_name;
- $new_name = drupal_strtolower($this->randomName());
- $this->vocabulary->machine_name = $new_name;
- taxonomy_vocabulary_save($this->vocabulary);
-
- // Check that entity bundles are properly updated.
- $info = entity_get_info('taxonomy_term');
- $this->assertFalse(isset($info['bundles'][$old_name]), 'The old bundle name does not appear in entity_get_info().');
- $this->assertTrue(isset($info['bundles'][$new_name]), 'The new bundle name appears in entity_get_info().');
-
- // Check that the field instance is still attached to the vocabulary.
- $field = field_info_field($this->field_name);
- $allowed_values = $field['settings']['allowed_values'];
- $this->assertEqual($allowed_values[0]['vocabulary'], $new_name, 'Index 0: Machine name was updated correctly.');
- $this->assertEqual($allowed_values[1]['vocabulary'], $new_name, 'Index 1: Machine name was updated correctly.');
- $this->assertEqual($allowed_values[2]['vocabulary'], 'foo', 'Index 2: Machine name was left untouched.');
- }
-
-}
-
-/**
- * Tests a taxonomy term reference field that allows multiple vocabularies.
- */
-class TaxonomyTermFieldMultipleVocabularyTestCase extends TaxonomyWebTestCase {
-
- protected $instance;
- protected $vocabulary1;
- protected $vocabulary2;
-
- public static function getInfo() {
- return array(
- 'name' => 'Multiple vocabulary term reference field',
- 'description' => 'Tests term reference fields that allow multiple vocabularies.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp('field_test');
-
- $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer taxonomy'));
- $this->drupalLogin($web_user);
- $this->vocabulary1 = $this->createVocabulary();
- $this->vocabulary2 = $this->createVocabulary();
-
- // Set up a field and instance.
- $this->field_name = drupal_strtolower($this->randomName());
- $this->field = array(
- 'field_name' => $this->field_name,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary1->machine_name,
- 'parent' => '0',
- ),
- array(
- 'vocabulary' => $this->vocabulary2->machine_name,
- 'parent' => '0',
- ),
- ),
- )
- );
- field_create_field($this->field);
- $this->instance = array(
- 'field_name' => $this->field_name,
- 'entity_type' => 'test_entity',
- 'bundle' => 'test_bundle',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'full' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance);
- }
-
- /**
- * Tests term reference field and widget with multiple vocabularies.
- */
- function testTaxonomyTermFieldMultipleVocabularies() {
- // Create a term in each vocabulary.
- $term1 = $this->createTerm($this->vocabulary1);
- $term2 = $this->createTerm($this->vocabulary2);
-
- // Submit an entity with both terms.
- $langcode = LANGUAGE_NONE;
- $this->drupalGet('test-entity/add/test-bundle');
- $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is displayed.');
- $edit = array(
- "{$this->field_name}[$langcode][]" => array($term1->tid, $term2->tid),
- );
- $this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
- $id = $match[1];
- $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
-
- // Render the entity.
- $entity = field_test_entity_test_load($id);
- $entities = array($id => $entity);
- field_attach_prepare_view('test_entity', $entities, 'full');
- $entity->content = field_attach_view('test_entity', $entity, 'full');
- $this->content = drupal_render($entity->content);
- $this->assertText($term1->name, 'Term 1 name is displayed.');
- $this->assertText($term2->name, 'Term 2 name is displayed.');
-
- // Delete vocabulary 2.
- taxonomy_vocabulary_delete($this->vocabulary2->vid);
-
- // Re-render the content.
- $entity = field_test_entity_test_load($id);
- $entities = array($id => $entity);
- field_attach_prepare_view('test_entity', $entities, 'full');
- $entity->content = field_attach_view('test_entity', $entity, 'full');
- $this->plainTextContent = FALSE;
- $this->content = drupal_render($entity->content);
-
- // Term 1 should still be displayed; term 2 should not be.
- $this->assertText($term1->name, 'Term 1 name is displayed.');
- $this->assertNoText($term2->name, 'Term 2 name is not displayed.');
-
- // Verify that field and instance settings are correct.
- $field_info = field_info_field($this->field_name);
- $this->assertEqual(sizeof($field_info['settings']['allowed_values']), 1, 'Only one vocabulary is allowed for the field.');
-
- // The widget should still be displayed.
- $this->drupalGet('test-entity/add/test-bundle');
- $this->assertFieldByName("{$this->field_name}[$langcode][]", '', 'Widget is still displayed.');
-
- // Term 1 should still pass validation.
- $edit = array(
- "{$this->field_name}[$langcode][]" => array($term1->tid),
- );
- $this->drupalPost(NULL, $edit, t('Save'));
- }
-
-}
-
-/**
- * Test taxonomy token replacement in strings.
- */
-class TaxonomyTokenReplaceTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy token replacement',
- 'description' => 'Generates text using placeholders for dummy content to check taxonomy token replacement.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access'));
- $this->drupalLogin($this->admin_user);
- $this->vocabulary = $this->createVocabulary();
- $this->langcode = LANGUAGE_NONE;
-
- $field = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $this->vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($field);
-
- $this->instance = array(
- 'field_name' => 'taxonomy_' . $this->vocabulary->machine_name,
- 'bundle' => 'article',
- 'entity_type' => 'node',
- 'widget' => array(
- 'type' => 'options_select',
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- ),
- ),
- );
- field_create_instance($this->instance);
- }
-
- /**
- * Creates some terms and a node, then tests the tokens generated from them.
- */
- function testTaxonomyTokenReplacement() {
- global $language;
-
- // Create two taxonomy terms.
- $term1 = $this->createTerm($this->vocabulary);
- $term2 = $this->createTerm($this->vocabulary);
-
- // Edit $term2, setting $term1 as parent.
- $edit = array();
- $edit['name'] = 'Blinking Text ';
- $edit['parent[]'] = array($term1->tid);
- $this->drupalPost('taxonomy/term/' . $term2->tid . '/edit', $edit, t('Save'));
-
- // Create node with term2.
- $edit = array();
- $node = $this->drupalCreateNode(array('type' => 'article'));
- $edit[$this->instance['field_name'] . '[' . $this->langcode . '][]'] = $term2->tid;
- $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
-
- // Generate and test sanitized tokens for term1.
- $tests = array();
- $tests['[term:tid]'] = $term1->tid;
- $tests['[term:name]'] = check_plain($term1->name);
- $tests['[term:description]'] = check_markup($term1->description, $term1->format);
- $tests['[term:url]'] = url('taxonomy/term/' . $term1->tid, array('absolute' => TRUE));
- $tests['[term:node-count]'] = 0;
- $tests['[term:parent:name]'] = '[term:parent:name]';
- $tests['[term:vocabulary:name]'] = check_plain($this->vocabulary->name);
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('term' => $term1), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Sanitized taxonomy term token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test sanitized tokens for term2.
- $tests = array();
- $tests['[term:tid]'] = $term2->tid;
- $tests['[term:name]'] = check_plain($term2->name);
- $tests['[term:description]'] = check_markup($term2->description, $term2->format);
- $tests['[term:url]'] = url('taxonomy/term/' . $term2->tid, array('absolute' => TRUE));
- $tests['[term:node-count]'] = 1;
- $tests['[term:parent:name]'] = check_plain($term1->name);
- $tests['[term:parent:url]'] = url('taxonomy/term/' . $term1->tid, array('absolute' => TRUE));
- $tests['[term:parent:parent:name]'] = '[term:parent:parent:name]';
- $tests['[term:vocabulary:name]'] = check_plain($this->vocabulary->name);
-
- // Test to make sure that we generated something for each token.
- $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('term' => $term2), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Sanitized taxonomy term token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test unsanitized tokens.
- $tests['[term:name]'] = $term2->name;
- $tests['[term:description]'] = $term2->description;
- $tests['[term:parent:name]'] = $term1->name;
- $tests['[term:vocabulary:name]'] = $this->vocabulary->name;
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('term' => $term2), array('language' => $language, 'sanitize' => FALSE));
- $this->assertEqual($output, $expected, format_string('Unsanitized taxonomy term token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test sanitized tokens.
- $tests = array();
- $tests['[vocabulary:vid]'] = $this->vocabulary->vid;
- $tests['[vocabulary:name]'] = check_plain($this->vocabulary->name);
- $tests['[vocabulary:description]'] = filter_xss($this->vocabulary->description);
- $tests['[vocabulary:node-count]'] = 1;
- $tests['[vocabulary:term-count]'] = 2;
-
- // Test to make sure that we generated something for each token.
- $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('vocabulary' => $this->vocabulary), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Sanitized taxonomy vocabulary token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test unsanitized tokens.
- $tests['[vocabulary:name]'] = $this->vocabulary->name;
- $tests['[vocabulary:description]'] = $this->vocabulary->description;
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('vocabulary' => $this->vocabulary), array('language' => $language, 'sanitize' => FALSE));
- $this->assertEqual($output, $expected, format_string('Unsanitized taxonomy vocabulary token %token replaced.', array('%token' => $input)));
- }
- }
-
-}
-
-/**
- * Tests for verifying that taxonomy pages use the correct theme.
- */
-class TaxonomyThemeTestCase extends TaxonomyWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy theme switching',
- 'description' => 'Verifies that various taxonomy pages use the expected theme.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp();
-
- // Make sure we are using distinct default and administrative themes for
- // the duration of these tests.
- variable_set('theme_default', 'bartik');
- variable_set('admin_theme', 'seven');
-
- // Create and log in as a user who has permission to add and edit taxonomy
- // terms and view the administrative theme.
- $admin_user = $this->drupalCreateUser(array('administer taxonomy', 'view the administration theme'));
- $this->drupalLogin($admin_user);
- }
-
- /**
- * Test the theme used when adding, viewing and editing taxonomy terms.
- */
- function testTaxonomyTermThemes() {
- // Adding a term to a vocabulary is considered an administrative action and
- // should use the administrative theme.
- $vocabulary = $this->createVocabulary();
- $this->drupalGet('admin/structure/taxonomy/' . $vocabulary->machine_name . '/add');
- $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page for adding a taxonomy term.");
-
- // Viewing a taxonomy term should use the default theme.
- $term = $this->createTerm($vocabulary);
- $this->drupalGet('taxonomy/term/' . $term->tid);
- $this->assertRaw('bartik/css/style.css', "The default theme's CSS appears on the page for viewing a taxonomy term.");
-
- // Editing a taxonomy term should use the same theme as adding one.
- $this->drupalGet('taxonomy/term/' . $term->tid . '/edit');
- $this->assertRaw('seven/style.css', "The administrative theme's CSS appears on the page for editing a taxonomy term.");
- }
-
-}
-
-/**
- * Tests the functionality of EntityFieldQuery for taxonomy entities.
- */
-class TaxonomyEFQTestCase extends TaxonomyWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Taxonomy EntityFieldQuery',
- 'description' => 'Verifies operation of a taxonomy-based EntityFieldQuery.',
- 'group' => 'Taxonomy',
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy'));
- $this->drupalLogin($this->admin_user);
- $this->vocabulary = $this->createVocabulary();
- }
-
- /**
- * Tests that a basic taxonomy EntityFieldQuery works.
- */
- function testTaxonomyEFQ() {
- $terms = array();
- for ($i = 0; $i < 5; $i++) {
- $term = $this->createTerm($this->vocabulary);
- $terms[$term->tid] = $term;
- }
- $query = new EntityFieldQuery();
- $query->entityCondition('entity_type', 'taxonomy_term');
- $result = $query->execute();
- $result = $result['taxonomy_term'];
- asort($result);
- $this->assertEqual(array_keys($terms), array_keys($result), 'Taxonomy terms were retrieved by EntityFieldQuery.');
-
- // Create a second vocabulary and five more terms.
- $vocabulary2 = $this->createVocabulary();
- $terms2 = array();
- for ($i = 0; $i < 5; $i++) {
- $term = $this->createTerm($vocabulary2);
- $terms2[$term->tid] = $term;
- }
-
- $query = new EntityFieldQuery();
- $query->entityCondition('entity_type', 'taxonomy_term');
- $query->entityCondition('bundle', $vocabulary2->machine_name);
- $result = $query->execute();
- $result = $result['taxonomy_term'];
- asort($result);
- $this->assertEqual(array_keys($terms2), array_keys($result), format_string('Taxonomy terms from the %name vocabulary were retrieved by EntityFieldQuery.', array('%name' => $vocabulary2->name)));
- }
-
-}
diff --git a/modules/taxonomy/taxonomy.tokens.inc b/modules/taxonomy/taxonomy.tokens.inc
deleted file mode 100644
index f8ae4576..00000000
--- a/modules/taxonomy/taxonomy.tokens.inc
+++ /dev/null
@@ -1,189 +0,0 @@
- t("Taxonomy terms"),
- 'description' => t("Tokens related to taxonomy terms."),
- 'needs-data' => 'term',
- );
- $types['vocabulary'] = array(
- 'name' => t("Vocabularies"),
- 'description' => t("Tokens related to taxonomy vocabularies."),
- 'needs-data' => 'vocabulary',
- );
-
- // Taxonomy term related variables.
- $term['tid'] = array(
- 'name' => t("Term ID"),
- 'description' => t("The unique ID of the taxonomy term."),
- );
- $term['name'] = array(
- 'name' => t("Name"),
- 'description' => t("The name of the taxonomy term."),
- );
- $term['description'] = array(
- 'name' => t("Description"),
- 'description' => t("The optional description of the taxonomy term."),
- );
- $term['node-count'] = array(
- 'name' => t("Node count"),
- 'description' => t("The number of nodes tagged with the taxonomy term."),
- );
- $term['url'] = array(
- 'name' => t("URL"),
- 'description' => t("The URL of the taxonomy term."),
- );
-
- // Taxonomy vocabulary related variables.
- $vocabulary['vid'] = array(
- 'name' => t("Vocabulary ID"),
- 'description' => t("The unique ID of the taxonomy vocabulary."),
- );
- $vocabulary['name'] = array(
- 'name' => t("Name"),
- 'description' => t("The name of the taxonomy vocabulary."),
- );
- $vocabulary['description'] = array(
- 'name' => t("Description"),
- 'description' => t("The optional description of the taxonomy vocabulary."),
- );
- $vocabulary['node-count'] = array(
- 'name' => t("Node count"),
- 'description' => t("The number of nodes tagged with terms belonging to the taxonomy vocabulary."),
- );
- $vocabulary['term-count'] = array(
- 'name' => t("Term count"),
- 'description' => t("The number of terms belonging to the taxonomy vocabulary."),
- );
-
- // Chained tokens for taxonomies
- $term['vocabulary'] = array(
- 'name' => t("Vocabulary"),
- 'description' => t("The vocabulary the taxonomy term belongs to."),
- 'type' => 'vocabulary',
- );
- $term['parent'] = array(
- 'name' => t("Parent term"),
- 'description' => t("The parent term of the taxonomy term, if one exists."),
- 'type' => 'term',
- );
-
- return array(
- 'types' => $types,
- 'tokens' => array(
- 'term' => $term,
- 'vocabulary' => $vocabulary,
- ),
- );
-}
-
-/**
- * Implements hook_tokens().
- */
-function taxonomy_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
- $sanitize = !empty($options['sanitize']);
-
- if ($type == 'term' && !empty($data['term'])) {
- $term = $data['term'];
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'tid':
- $replacements[$original] = $term->tid;
- break;
-
- case 'name':
- $replacements[$original] = $sanitize ? check_plain($term->name) : $term->name;
- break;
-
- case 'description':
- $replacements[$original] = $sanitize ? check_markup($term->description, $term->format, '', TRUE) : $term->description;
- break;
-
- case 'url':
- $uri = entity_uri('taxonomy_term', $term);
- $replacements[$original] = url($uri['path'], array_merge($uri['options'], array('absolute' => TRUE)));
- break;
-
- case 'node-count':
- $query = db_select('taxonomy_index');
- $query->condition('tid', $term->tid);
- $query->addTag('term_node_count');
- $count = $query->countQuery()->execute()->fetchField();
- $replacements[$original] = $count;
- break;
-
- case 'vocabulary':
- $vocabulary = taxonomy_vocabulary_load($term->vid);
- $replacements[$original] = check_plain($vocabulary->name);
- break;
-
- case 'parent':
- if ($parents = taxonomy_get_parents($term->tid)) {
- $parent = array_pop($parents);
- $replacements[$original] = check_plain($parent->name);
- }
- break;
- }
- }
-
- if ($vocabulary_tokens = token_find_with_prefix($tokens, 'vocabulary')) {
- $vocabulary = taxonomy_vocabulary_load($term->vid);
- $replacements += token_generate('vocabulary', $vocabulary_tokens, array('vocabulary' => $vocabulary), $options);
- }
-
- if (($vocabulary_tokens = token_find_with_prefix($tokens, 'parent')) && $parents = taxonomy_get_parents($term->tid)) {
- $parent = array_pop($parents);
- $replacements += token_generate('term', $vocabulary_tokens, array('term' => $parent), $options);
- }
- }
-
- elseif ($type == 'vocabulary' && !empty($data['vocabulary'])) {
- $vocabulary = $data['vocabulary'];
-
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'vid':
- $replacements[$original] = $vocabulary->vid;
- break;
-
- case 'name':
- $replacements[$original] = $sanitize ? check_plain($vocabulary->name) : $vocabulary->name;
- break;
-
- case 'description':
- $replacements[$original] = $sanitize ? filter_xss($vocabulary->description) : $vocabulary->description;
- break;
-
- case 'term-count':
- $query = db_select('taxonomy_term_data');
- $query->condition('vid', $vocabulary->vid);
- $query->addTag('vocabulary_term_count');
- $count = $query->countQuery()->execute()->fetchField();
- $replacements[$original] = $count;
- break;
-
- case 'node-count':
- $query = db_select('taxonomy_index', 'ti');
- $query->addExpression('COUNT(DISTINCT ti.nid)');
- $query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
- $query->condition('td.vid', $vocabulary->vid);
- $query->addTag('vocabulary_node_count');
- $count = $query->execute()->fetchField();
- $replacements[$original] = $count;
- break;
- }
- }
- }
-
- return $replacements;
-}
diff --git a/modules/toolbar/toolbar-rtl.css b/modules/toolbar/toolbar-rtl.css
deleted file mode 100644
index acbc98f8..00000000
--- a/modules/toolbar/toolbar-rtl.css
+++ /dev/null
@@ -1,41 +0,0 @@
-
-#toolbar,
-#toolbar * {
- text-align: right;
-}
-#toolbar ul li {
- float: right;
-}
-#toolbar ul li a {
- display: inline-block;
- float: none;
- zoom: 1;
-}
-#toolbar div.toolbar-menu {
- padding: 5px 50px 5px 50px;
-}
-#toolbar-user {
- float: left;
-}
-#toolbar ul#toolbar-user li {
- float: none;
- display: inline;
-}
-#toolbar-menu {
- float: none;
-}
-#toolbar-home {
- float: right;
-}
-#toolbar ul li.home a {
- position: absolute;
- right: 10px;
-}
-#toolbar div.toolbar-menu a.toggle {
- left: 10px;
- right: auto;
-}
-* html #toolbar {
- left: 0;
- padding-left: 0;
-}
diff --git a/modules/toolbar/toolbar.css b/modules/toolbar/toolbar.css
deleted file mode 100644
index cbf3c14c..00000000
--- a/modules/toolbar/toolbar.css
+++ /dev/null
@@ -1,150 +0,0 @@
-
-body.toolbar {
- padding-top: 2.2em;
-}
-body.toolbar-drawer {
- padding-top: 5.3em;
-}
-
-/**
- * Aggressive resets so we can achieve a consistent look in hostile CSS
- * environments.
- */
-#toolbar,
-#toolbar * {
- border: 0;
- font-size: 100%;
- line-height: inherit;
- list-style: none;
- margin: 0;
- outline: 0;
- padding: 0;
- text-align: left; /* LTR */
- vertical-align: baseline;
-}
-
-/**
- * Base styles.
- *
- * We use a keyword for the toolbar font size to make it display consistently
- * across different themes, while still allowing browsers to resize the text.
- */
-#toolbar {
- background: #666;
- color: #ccc;
- font: normal small "Lucida Grande", Verdana, sans-serif;
- left: 0;
- margin: 0 -20px;
- padding: 0 20px;
- position: fixed;
- right: 0;
- top: 0;
- -moz-box-shadow: 0 3px 20px #000;
- -webkit-box-shadow: 0 3px 20px #000;
- box-shadow: 0 3px 20px #000;
- filter: progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10');
- -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(color=#000000, direction='180', strength='10')";
- z-index: 600;
-}
-#toolbar div.collapsed {
- display: none;
- visibility: hidden;
-}
-#toolbar a {
- color: #fff;
- font-size: .846em;
- text-decoration: none;
-}
-#toolbar ul li,
-#toolbar ul li a {
- float: left; /* LTR */
-}
-
-/**
- * Administration menu.
- */
-#toolbar div.toolbar-menu {
- background: #000;
- line-height: 20px;
- padding: 5px 50px 5px 10px; /* LTR */
- position: relative;
-}
-#toolbar-home a span {
- background: url(toolbar.png) no-repeat 0 -45px;
- display: block;
- height: 14px;
- margin: 3px 0px;
- text-indent: -9999px;
- vertical-align: text-bottom;
- width: 11px;
-}
-#toolbar-user {
- float: right; /* LTR */
-}
-#toolbar-menu {
- float: left; /* LTR */
-}
-#toolbar div.toolbar-menu a.toggle {
- background: url(toolbar.png) 0 -20px no-repeat;
- bottom: 0;
- cursor: pointer;
- height: 25px;
- overflow: hidden;
- position: absolute;
- right: 10px; /* LTR */
- text-indent: -9999px;
- width: 25px;
-}
-#toolbar div.toolbar-menu a.toggle:focus,
-#toolbar div.toolbar-menu a.toggle:hover {
- background-position: -50px -20px;
-}
-#toolbar div.toolbar-menu a.toggle-active {
- background-position: -25px -20px;
-}
-#toolbar div.toolbar-menu a.toggle-active.toggle:focus,
-#toolbar div.toolbar-menu a.toggle-active.toggle:hover {
- background-position: -75px -20px;
-}
-#toolbar div.toolbar-menu ul li a {
- padding: 0 10px;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- border-radius: 10px;
-}
-#toolbar div.toolbar-menu ul li a:focus,
-#toolbar div.toolbar-menu ul li a:hover,
-#toolbar div.toolbar-menu ul li a:active,
-#toolbar div.toolbar-menu ul li a.active:focus {
- background: #444;
-}
-#toolbar div.toolbar-menu ul li a.active:hover,
-#toolbar div.toolbar-menu ul li a.active:active,
-#toolbar div.toolbar-menu ul li a.active,
-#toolbar div.toolbar-menu ul li.active-trail a {
- background: url(toolbar.png) 0 0 repeat-x;
- text-shadow: #333 0 1px 0;
-}
-
-/**
- * Collapsed drawer of additional toolbar content.
- */
-#toolbar div.toolbar-drawer {
- position: relative;
- padding: 0 10px;
-}
-
-/**
- * IE 6 Fix.
- *
- * IE 6 shows elements with position:fixed as position:static so we replace
- * it with position:absolute; toolbar needs its z-index to stay above overlay.
- */
-* html #toolbar {
- left: -20px;
- margin: 0;
- padding-right: 0;
- position: absolute;
- right: 0;
- width: 100%;
-}
diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info
deleted file mode 100644
index c8d7d31a..00000000
--- a/modules/toolbar/toolbar.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = Toolbar
-description = Provides a toolbar that shows the top-level administration menu items and links from other modules.
-core = 7.x
-package = Core
-version = VERSION
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/toolbar/toolbar.js b/modules/toolbar/toolbar.js
deleted file mode 100644
index d50f2056..00000000
--- a/modules/toolbar/toolbar.js
+++ /dev/null
@@ -1,111 +0,0 @@
-(function ($) {
-
-Drupal.toolbar = Drupal.toolbar || {};
-
-/**
- * Attach toggling behavior and notify the overlay of the toolbar.
- */
-Drupal.behaviors.toolbar = {
- attach: function(context) {
-
- // Set the initial state of the toolbar.
- $('#toolbar', context).once('toolbar', Drupal.toolbar.init);
-
- // Toggling toolbar drawer.
- $('#toolbar a.toggle', context).once('toolbar-toggle').click(function(e) {
- Drupal.toolbar.toggle();
- // Allow resize event handlers to recalculate sizes/positions.
- $(window).triggerHandler('resize');
- return false;
- });
- }
-};
-
-/**
- * Retrieve last saved cookie settings and set up the initial toolbar state.
- */
-Drupal.toolbar.init = function() {
- // Retrieve the collapsed status from a stored cookie.
- var collapsed = $.cookie('Drupal.toolbar.collapsed');
-
- // Expand or collapse the toolbar based on the cookie value.
- if (collapsed == 1) {
- Drupal.toolbar.collapse();
- }
- else {
- Drupal.toolbar.expand();
- }
-};
-
-/**
- * Collapse the toolbar.
- */
-Drupal.toolbar.collapse = function() {
- var toggle_text = Drupal.t('Show shortcuts');
- $('#toolbar div.toolbar-drawer').addClass('collapsed');
- $('#toolbar a.toggle')
- .removeClass('toggle-active')
- .attr('title', toggle_text)
- .html(toggle_text);
- $('body').removeClass('toolbar-drawer').css('paddingTop', Drupal.toolbar.height());
- $.cookie(
- 'Drupal.toolbar.collapsed',
- 1,
- {
- path: Drupal.settings.basePath,
- // The cookie should "never" expire.
- expires: 36500
- }
- );
-};
-
-/**
- * Expand the toolbar.
- */
-Drupal.toolbar.expand = function() {
- var toggle_text = Drupal.t('Hide shortcuts');
- $('#toolbar div.toolbar-drawer').removeClass('collapsed');
- $('#toolbar a.toggle')
- .addClass('toggle-active')
- .attr('title', toggle_text)
- .html(toggle_text);
- $('body').addClass('toolbar-drawer').css('paddingTop', Drupal.toolbar.height());
- $.cookie(
- 'Drupal.toolbar.collapsed',
- 0,
- {
- path: Drupal.settings.basePath,
- // The cookie should "never" expire.
- expires: 36500
- }
- );
-};
-
-/**
- * Toggle the toolbar.
- */
-Drupal.toolbar.toggle = function() {
- if ($('#toolbar div.toolbar-drawer').hasClass('collapsed')) {
- Drupal.toolbar.expand();
- }
- else {
- Drupal.toolbar.collapse();
- }
-};
-
-Drupal.toolbar.height = function() {
- var $toolbar = $('#toolbar');
- var height = $toolbar.outerHeight();
- // In modern browsers (including IE9), when box-shadow is defined, use the
- // normal height.
- var cssBoxShadowValue = $toolbar.css('box-shadow');
- var boxShadow = (typeof cssBoxShadowValue !== 'undefined' && cssBoxShadowValue !== 'none');
- // In IE8 and below, we use the shadow filter to apply box-shadow styles to
- // the toolbar. It adds some extra height that we need to remove.
- if (!boxShadow && /DXImageTransform\.Microsoft\.Shadow/.test($toolbar.css('filter'))) {
- height -= $toolbar[0].filters.item("DXImageTransform.Microsoft.Shadow").strength;
- }
- return height;
-};
-
-})(jQuery);
diff --git a/modules/toolbar/toolbar.module b/modules/toolbar/toolbar.module
deleted file mode 100644
index 6d1b581d..00000000
--- a/modules/toolbar/toolbar.module
+++ /dev/null
@@ -1,363 +0,0 @@
-' . t('About') . '';
- $output .= '' . t('The Toolbar module displays links to top-level administration menu items and links from other modules at the top of the screen. For more information, see the online handbook entry for Toolbar module .', array('@toolbar' => 'http://drupal.org/documentation/modules/toolbar/')) . '
';
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Displaying administrative links') . ' ';
- $output .= '' . t('The Toolbar module displays a bar containing top-level administrative links across the top of the screen. Below that, the Toolbar module has a drawer section where it displays links provided by other modules, such as the core Shortcut module . The drawer can be hidden/shown by using the show/hide shortcuts link at the end of the toolbar.', array('@shortcuts-help' => url('admin/help/shortcut'))) . ' ';
- $output .= ' ';
- return $output;
- }
-}
-
-/**
- * Implements hook_permission().
- */
-function toolbar_permission() {
- return array(
- 'access toolbar' => array(
- 'title' => t('Use the administration toolbar'),
- ),
- );
-}
-
-/**
- * Implements hook_theme().
- */
-function toolbar_theme($existing, $type, $theme, $path) {
- $items['toolbar'] = array(
- 'render element' => 'toolbar',
- 'template' => 'toolbar',
- 'path' => drupal_get_path('module', 'toolbar'),
- );
- $items['toolbar_toggle'] = array(
- 'variables' => array(
- 'collapsed' => NULL,
- 'attributes' => array(),
- ),
- );
- return $items;
-}
-
-/**
- * Implements hook_menu().
- */
-function toolbar_menu() {
- $items['toolbar/toggle'] = array(
- 'title' => 'Toggle drawer visibility',
- 'type' => MENU_CALLBACK,
- 'page callback' => 'toolbar_toggle_page',
- 'access arguments' => array('access toolbar'),
- );
- return $items;
-}
-
-/**
- * Menu callback; toggles the visibility of the toolbar drawer.
- */
-function toolbar_toggle_page() {
- global $base_path;
- // Toggle the value in the cookie.
- setcookie('Drupal.toolbar.collapsed', !_toolbar_is_collapsed(), NULL, $base_path);
- // Redirect the user from where he used the toggle element.
- drupal_goto();
-}
-
-/**
- * Formats an element used to toggle the toolbar drawer's visibility.
- *
- * @param $variables
- * An associative array containing:
- * - collapsed: A boolean value representing the toolbar drawer's visibility.
- * - attributes: An associative array of HTML attributes.
- *
- * @return
- * An HTML string representing the element for toggling.
- *
- * @ingroup themable
- */
-function theme_toolbar_toggle($variables) {
- if ($variables['collapsed']) {
- $toggle_text = t('Show shortcuts');
- }
- else {
- $toggle_text = t('Hide shortcuts');
- $variables['attributes']['class'][] = 'toggle-active';
- }
- return l($toggle_text, 'toolbar/toggle', array('query' => drupal_get_destination(), 'attributes' => array('title' => $toggle_text) + $variables['attributes']));
-}
-
-/**
- * Determines the current state of the toolbar drawer's visibility.
- *
- * @return
- * TRUE when drawer is collapsed, FALSE when it is expanded.
- */
-function _toolbar_is_collapsed() {
- // PHP converts dots into underscores in cookie names to avoid problems with
- // its parser, so we use a converted cookie name.
- return isset($_COOKIE['Drupal_toolbar_collapsed']) ? $_COOKIE['Drupal_toolbar_collapsed'] : 0;
-}
-
-/**
- * Implements hook_page_build().
- *
- * Add admin toolbar to the page_top region automatically.
- */
-function toolbar_page_build(&$page) {
- $page['page_top']['toolbar'] = array(
- '#pre_render' => array('toolbar_pre_render'),
- '#access' => user_access('access toolbar'),
- 'toolbar_drawer' => array(),
- );
-}
-
-/**
- * Prerender function for the toolbar.
- *
- * Since building the toolbar takes some time, it is done just prior to
- * rendering to ensure that it is built only if it will be displayed.
- */
-function toolbar_pre_render($toolbar) {
- $toolbar = array_merge($toolbar, toolbar_view());
- return $toolbar;
-}
-
-/**
- * Implements hook_preprocess_html().
- *
- * Add some page classes, so global page theming can adjust to the toolbar.
- */
-function toolbar_preprocess_html(&$vars) {
- if (isset($vars['page']['page_top']['toolbar']) && user_access('access toolbar')) {
- $vars['classes_array'][] = 'toolbar';
- if (!_toolbar_is_collapsed()) {
- $vars['classes_array'][] = 'toolbar-drawer';
- }
- }
-}
-
-/**
- * Implements hook_preprocess_toolbar().
- *
- * Adding the 'overlay-displace-top' class to the toolbar pushes the overlay
- * down, so it appears below the toolbar.
- */
-function toolbar_preprocess_toolbar(&$variables) {
- $variables['classes_array'][] = "overlay-displace-top";
-}
-
-/**
- * Implements hook_system_info_alter().
- *
- * Indicate that the 'page_top' region (in which the toolbar will be displayed)
- * is an overlay supplemental region that should be refreshed whenever its
- * content is updated.
- *
- * This information is provided for any module that might need to use it, not
- * just the core Overlay module.
- */
-function toolbar_system_info_alter(&$info, $file, $type) {
- if ($type == 'theme') {
- $info['overlay_supplemental_regions'][] = 'page_top';
- }
-}
-
-/**
- * Builds the admin menu as a structured array ready for drupal_render().
- *
- * @return
- * Array of links and settings relating to the admin menu.
- */
-function toolbar_view() {
- global $user;
-
- $module_path = drupal_get_path('module', 'toolbar');
- $build = array(
- '#theme' => 'toolbar',
- '#attached'=> array(
- 'js' => array(
- $module_path . '/toolbar.js',
- array(
- 'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'),
- 'type' => 'setting'
- ),
- ),
- 'css' => array(
- $module_path . '/toolbar.css',
- ),
- 'library' => array(array('system', 'jquery.cookie')),
- ),
- );
-
- // Retrieve the admin menu from the database.
- $links = toolbar_menu_navigation_links(toolbar_get_menu_tree());
- $build['toolbar_menu'] = array(
- '#theme' => 'links__toolbar_menu',
- '#links' => $links,
- '#attributes' => array('id' => 'toolbar-menu'),
- '#heading' => array('text' => t('Administrative toolbar'), 'level' => 'h2', 'class' => 'element-invisible'),
- );
-
- // Add logout & user account links or login link.
- if ($user->uid) {
- $links = array(
- 'account' => array(
- 'title' => t('Hello @username ', array('@username' => format_username($user))),
- 'href' => 'user',
- 'html' => TRUE,
- 'attributes' => array('title' => t('User account')),
- ),
- 'logout' => array(
- 'title' => t('Log out'),
- 'href' => 'user/logout',
- ),
- );
- }
- else {
- $links = array(
- 'login' => array(
- 'title' => t('Log in'),
- 'href' => 'user',
- ),
- );
- }
- $build['toolbar_user'] = array(
- '#theme' => 'links__toolbar_user',
- '#links' => $links,
- '#attributes' => array('id' => 'toolbar-user'),
- );
-
- // Add a "home" link.
- $link = array(
- 'home' => array(
- 'title' => 'Home ',
- 'href' => '',
- 'html' => TRUE,
- 'attributes' => array('title' => t('Home')),
- ),
- );
- $build['toolbar_home'] = array(
- '#theme' => 'links',
- '#links' => $link,
- '#attributes' => array('id' => 'toolbar-home'),
- );
-
- // Add an anchor to be able to toggle the visibility of the drawer.
- $build['toolbar_toggle'] = array(
- '#theme' => 'toolbar_toggle',
- '#collapsed' => _toolbar_is_collapsed(),
- '#attributes' => array('class' => array('toggle')),
- );
-
- // Prepare the drawer links CSS classes.
- $toolbar_drawer_classes = array(
- 'toolbar-drawer',
- 'clearfix',
- );
- if(_toolbar_is_collapsed()) {
- $toolbar_drawer_classes[] = 'collapsed';
- }
- $build['toolbar_drawer_classes'] = implode(' ', $toolbar_drawer_classes);
-
- return $build;
-}
-
-/**
- * Gets only the top level items below the 'admin' path.
- *
- * @return
- * An array containing a menu tree of top level items below the 'admin' path.
- */
-function toolbar_get_menu_tree() {
- $tree = array();
- $admin_link = db_query('SELECT * FROM {menu_links} WHERE menu_name = :menu_name AND module = :module AND link_path = :path', array(':menu_name' => 'management', ':module' => 'system', ':path' => 'admin'))->fetchAssoc();
- if ($admin_link) {
- $tree = menu_build_tree('management', array(
- 'expanded' => array($admin_link['mlid']),
- 'min_depth' => $admin_link['depth'] + 1,
- 'max_depth' => $admin_link['depth'] + 1,
- ));
- }
-
- return $tree;
-}
-
-/**
- * Generates a links array from a menu tree array.
- *
- * Based on menu_navigation_links(). Adds path based IDs and icon placeholders
- * to the links.
- *
- * @return
- * An array of links as defined above.
- */
-function toolbar_menu_navigation_links($tree) {
- $links = array();
- foreach ($tree as $item) {
- if (!$item['link']['hidden'] && $item['link']['access']) {
- // Make sure we have a path specific ID in place, so we can attach icons
- // and behaviors to the items.
- $id = str_replace(array('/', '<', '>'), array('-', '', ''), $item['link']['href']);
-
- $link = $item['link']['localized_options'];
- $link['href'] = $item['link']['href'];
- // Add icon placeholder.
- $link['title'] = ' ' . check_plain($item['link']['title']);
- // Add admin link ID.
- $link['attributes'] = array('id' => 'toolbar-link-' . $id);
- if (!empty($item['link']['description'])) {
- $link['title'] .= ' (' . $item['link']['description'] . ') ';
- $link['attributes']['title'] = $item['link']['description'];
- }
- $link['html'] = TRUE;
-
- $class = ' path-' . $id;
- if (toolbar_in_active_trail($item['link']['href'])) {
- $class .= ' active-trail';
- }
- $links['menu-' . $item['link']['mlid'] . $class] = $link;
- }
- }
- return $links;
-}
-
-/**
- * Checks whether an item is in the active trail.
- *
- * Useful when using a menu generated by menu_tree_all_data() which does
- * not set the 'in_active_trail' flag on items.
- *
- * @return
- * TRUE when path is in the active trail, FALSE if not.
- *
- * @todo
- * Look at migrating to a menu system level function.
- */
-function toolbar_in_active_trail($path) {
- $active_paths = &drupal_static(__FUNCTION__);
-
- // Gather active paths.
- if (!isset($active_paths)) {
- $active_paths = array();
- $trail = menu_get_active_trail();
- foreach ($trail as $item) {
- if (!empty($item['href'])) {
- $active_paths[] = $item['href'];
- }
- }
- }
- return in_array($path, $active_paths);
-}
diff --git a/modules/toolbar/toolbar.png b/modules/toolbar/toolbar.png
deleted file mode 100644
index f2c7f355..00000000
Binary files a/modules/toolbar/toolbar.png and /dev/null differ
diff --git a/modules/toolbar/toolbar.tpl.php b/modules/toolbar/toolbar.tpl.php
deleted file mode 100644
index e8521299..00000000
--- a/modules/toolbar/toolbar.tpl.php
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
diff --git a/modules/tracker/tracker.css b/modules/tracker/tracker.css
deleted file mode 100644
index d3531c46..00000000
--- a/modules/tracker/tracker.css
+++ /dev/null
@@ -1,7 +0,0 @@
-
-.page-tracker td.replies {
- text-align: center;
-}
-.page-tracker table {
- width: 100%;
-}
diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info
deleted file mode 100644
index 6a84fc2f..00000000
--- a/modules/tracker/tracker.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = Tracker
-description = Enables tracking of recent content for users.
-dependencies[] = comment
-package = Core
-version = VERSION
-core = 7.x
-files[] = tracker.test
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/tracker/tracker.install b/modules/tracker/tracker.install
deleted file mode 100644
index 9967b9db..00000000
--- a/modules/tracker/tracker.install
+++ /dev/null
@@ -1,225 +0,0 @@
-fetchField();
- if ($max_nid != 0) {
- variable_set('tracker_index_nid', $max_nid);
- // To avoid timing out while attempting to do a complete indexing, we
- // simply call our cron job to remove stale records and begin the process.
- tracker_cron();
- }
-}
-
-/**
- * Implements hook_schema().
- */
-function tracker_schema() {
- $schema['tracker_node'] = array(
- 'description' => 'Tracks when nodes were last changed or commented on.',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'published' => array(
- 'description' => 'Boolean indicating whether the node is published.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'changed' => array(
- 'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- ),
- 'indexes' => array(
- 'tracker' => array('published', 'changed'),
- ),
- 'primary key' => array('nid'),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- ),
- );
-
- $schema['tracker_user'] = array(
- 'description' => 'Tracks when nodes were last changed or commented on, for each user that authored the node or one of its comments.',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'uid' => array(
- 'description' => 'The {users}.uid of the node author or commenter.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'published' => array(
- 'description' => 'Boolean indicating whether the node is published.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'changed' => array(
- 'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- ),
- 'indexes' => array(
- 'tracker' => array('uid', 'published', 'changed'),
- ),
- 'primary key' => array('nid', 'uid'),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- 'tracked_user' => array(
- 'table' => 'users',
- 'columns' => array('uid' => 'uid'),
- ),
- ),
- );
-
- return $schema;
-}
-
-/**
- * @addtogroup updates-6.x-to-7.x
- * @{
- */
-
-/**
- * Create new tracker_node and tracker_user tables.
- */
-function tracker_update_7000() {
- $schema['tracker_node'] = array(
- 'description' => 'Tracks when nodes were last changed or commented on',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'published' => array(
- 'description' => 'Boolean indicating whether the node is published.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'changed' => array(
- 'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- ),
- 'indexes' => array(
- 'tracker' => array('published', 'changed'),
- ),
- 'primary key' => array('nid'),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- ),
- );
-
- $schema['tracker_user'] = array(
- 'description' => 'Tracks when nodes were last changed or commented on, for each user that authored the node or one of its comments.',
- 'fields' => array(
- 'nid' => array(
- 'description' => 'The {node}.nid this record tracks.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'uid' => array(
- 'description' => 'The {users}.uid of the node author or commenter.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'published' => array(
- 'description' => 'Boolean indicating whether the node is published.',
- 'type' => 'int',
- 'not null' => FALSE,
- 'default' => 0,
- 'size' => 'tiny',
- ),
- 'changed' => array(
- 'description' => 'The Unix timestamp when the node was most recently saved or commented on.',
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ),
- ),
- 'indexes' => array(
- 'tracker' => array('uid', 'published', 'changed'),
- ),
- 'primary key' => array('nid', 'uid'),
- 'foreign keys' => array(
- 'tracked_node' => array(
- 'table' => 'node',
- 'columns' => array('nid' => 'nid'),
- ),
- 'tracked_user' => array(
- 'table' => 'users',
- 'columns' => array('uid' => 'uid'),
- ),
- ),
- );
-
- foreach ($schema as $name => $table) {
- db_create_table($name, $table);
- }
-
- $max_nid = db_query('SELECT MAX(nid) FROM {node}')->fetchField();
- if ($max_nid != 0) {
- variable_set('tracker_index_nid', $max_nid);
- }
-}
-
-/**
- * @} End of "addtogroup updates-6.x-to-7.x".
- */
diff --git a/modules/tracker/tracker.module b/modules/tracker/tracker.module
deleted file mode 100644
index 8694222d..00000000
--- a/modules/tracker/tracker.module
+++ /dev/null
@@ -1,380 +0,0 @@
-' . t('About') . '';
- $output .= '' . t('The Tracker module displays the most recently added and updated content on your site, and allows you to follow new content created by each user. This module has no configuration options. For more information, see the online handbook entry for Tracker module .', array('@tracker' => 'http://drupal.org/documentation/modules/tracker/')) . '
';
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Navigation') . ' ';
- $output .= '' . t('The Tracker module adds a new menu item to the Navigation menu, called Recent content . You can configure menu items via the Menus administration page .', array('@menus' => url('admin/structure/menu'))) . ' ';
- $output .= '' . t('Tracking new and updated site content') . ' ';
- $output .= '' . t("The Recent content page shows new and updated content in reverse chronological order, listing the content type, title, author's name, number of comments, and time of last update. Content is considered updated when changes occur in the text, or when new comments are added. The My recent content tab limits the list to the currently logged-in user.", array('@recent' => url('tracker'))) . ' ';
- $output .= '' . t('Tracking user-specific content') . ' ';
- $output .= '' . t("To follow a specific user's new and updated content, select the Track tab from the user's profile page.") . ' ';
- $output .= ' ';
- return $output;
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function tracker_menu() {
- $items['tracker'] = array(
- 'title' => 'Recent content',
- 'page callback' => 'tracker_page',
- 'access arguments' => array('access content'),
- 'weight' => 1,
- 'file' => 'tracker.pages.inc',
- );
- $items['tracker/all'] = array(
- 'title' => 'All recent content',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['tracker/%user_uid_optional'] = array(
- 'title' => 'My recent content',
- 'page callback' => 'tracker_page',
- 'access callback' => '_tracker_myrecent_access',
- 'access arguments' => array(1),
- 'page arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'tracker.pages.inc',
- );
-
- $items['user/%user/track'] = array(
- 'title' => 'Track',
- 'page callback' => 'tracker_page',
- 'page arguments' => array(1, TRUE),
- 'access callback' => '_tracker_user_access',
- 'access arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'tracker.pages.inc',
- );
- $items['user/%user/track/content'] = array(
- 'title' => 'Track content',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
-
- return $items;
-}
-
-/**
- * Implements hook_cron().
- *
- * Updates tracking information for any items still to be tracked. The variable
- * 'tracker_index_nid' is set to ((the last node ID that was indexed) - 1) and
- * used to select the nodes to be processed. If there are no remaining nodes to
- * process, 'tracker_index_nid' will be 0.
- */
-function tracker_cron() {
- $max_nid = variable_get('tracker_index_nid', 0);
- $batch_size = variable_get('tracker_batch_size', 1000);
- if ($max_nid > 0) {
- $last_nid = FALSE;
- $result = db_query_range('SELECT nid, uid, status FROM {node} WHERE nid <= :max_nid ORDER BY nid DESC', 0, $batch_size, array(':max_nid' => $max_nid), array('target' => 'slave'));
-
- $count = 0;
-
- foreach ($result as $row) {
- // Calculate the changed timestamp for this node.
- $changed = _tracker_calculate_changed($row->nid);
-
- // Remove existing data for this node.
- db_delete('tracker_node')
- ->condition('nid', $row->nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $row->nid)
- ->execute();
-
- // Insert the node-level data.
- db_insert('tracker_node')
- ->fields(array(
- 'nid' => $row->nid,
- 'published' => $row->status,
- 'changed' => $changed,
- ))
- ->execute();
-
- // Insert the user-level data for the node's author.
- db_insert('tracker_user')
- ->fields(array(
- 'nid' => $row->nid,
- 'published' => $row->status,
- 'changed' => $changed,
- 'uid' => $row->uid,
- ))
- ->execute();
-
- $query = db_select('comment', 'c', array('target' => 'slave'));
- // Force PostgreSQL to do an implicit cast by adding 0.
- $query->addExpression('0 + :changed', 'changed', array(':changed' => $changed));
- $query->addField('c', 'status', 'published');
- $query
- ->distinct()
- ->fields('c', array('uid', 'nid'))
- ->condition('c.nid', $row->nid)
- ->condition('c.uid', $row->uid, '<>')
- ->condition('c.status', COMMENT_PUBLISHED);
-
- // Insert the user-level data for the commenters (except if a commenter
- // is the node's author).
- db_insert('tracker_user')
- ->from($query)
- ->execute();
-
- // Note that we have indexed at least one node.
- $last_nid = $row->nid;
-
- $count++;
- }
-
- if ($last_nid !== FALSE) {
- // Prepare a starting point for the next run.
- variable_set('tracker_index_nid', $last_nid - 1);
-
- watchdog('tracker', 'Indexed %count content items for tracking.', array('%count' => $count));
- }
- else {
- // If all nodes have been indexed, set to zero to skip future cron runs.
- variable_set('tracker_index_nid', 0);
- }
- }
-}
-
-/**
- * Access callback for tracker/%user_uid_optional.
- */
-function _tracker_myrecent_access($account) {
- // This path is only allowed for authenticated users looking at their own content.
- return $account->uid && ($GLOBALS['user']->uid == $account->uid) && user_access('access content');
-}
-
-/**
- * Access callback for user/%user/track.
- */
-function _tracker_user_access($account) {
- return user_view_access($account) && user_access('access content');
-}
-
-/**
- * Implements hook_node_insert().
- *
- * Adds new tracking information for this node since it's new.
- */
-function tracker_node_insert($node, $arg = 0) {
- _tracker_add($node->nid, $node->uid, $node->changed);
-}
-
-/**
- * Implements hook_node_update().
- *
- * Adds tracking information for this node since it's been updated.
- */
-function tracker_node_update($node, $arg = 0) {
- _tracker_add($node->nid, $node->uid, $node->changed);
-}
-
-/**
- * Implements hook_node_delete().
- *
- * Deletes tracking information for a node.
- */
-function tracker_node_delete($node, $arg = 0) {
- db_delete('tracker_node')
- ->condition('nid', $node->nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $node->nid)
- ->execute();
-}
-
-/**
- * Implements hook_comment_update().
- *
- * Comment module doesn't call hook_comment_unpublish() when saving individual
- * comments so we need to check for those here.
- */
-function tracker_comment_update($comment) {
- // comment_save() calls hook_comment_publish() for all published comments
- // so we need to handle all other values here.
- if ($comment->status != COMMENT_PUBLISHED) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
- }
-}
-
-/**
- * Implements hook_comment_publish().
- *
- * This actually handles the insert and update of published nodes since
- * comment_save() calls hook_comment_publish() for all published comments.
- */
-function tracker_comment_publish($comment) {
- _tracker_add($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Implements hook_comment_unpublish().
- */
-function tracker_comment_unpublish($comment) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Implements hook_comment_delete().
- */
-function tracker_comment_delete($comment) {
- _tracker_remove($comment->nid, $comment->uid, $comment->changed);
-}
-
-/**
- * Updates indexing tables when a node is added, updated, or commented on.
- *
- * @param $nid
- * A node ID.
- * @param $uid
- * The node or comment author.
- * @param $changed
- * The node updated timestamp or comment timestamp.
- */
-function _tracker_add($nid, $uid, $changed) {
- $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
-
- // Adding a comment can only increase the changed timestamp, so our
- // calculation here is simple.
- $changed = max($node->changed, $changed);
-
- // Update the node-level data.
- db_merge('tracker_node')
- ->key(array('nid' => $nid))
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->execute();
-
- // Create or update the user-level data.
- db_merge('tracker_user')
- ->key(array(
- 'nid' => $nid,
- 'uid' => $uid,
- ))
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->execute();
-}
-
-/**
- * Determines the max timestamp between $node->changed and the last comment.
- *
- * @param $nid
- * A node ID.
- *
- * @return
- * The $node->changed timestamp, or most recent comment timestamp, whichever
- * is the greatest.
- */
-function _tracker_calculate_changed($nid) {
- $changed = db_query('SELECT changed FROM {node} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'slave'))->fetchField();
- $latest_comment = db_query_range('SELECT cid, changed FROM {comment} WHERE nid = :nid AND status = :status ORDER BY changed DESC', 0, 1, array(
- ':nid' => $nid,
- ':status' => COMMENT_PUBLISHED,
- ), array('target' => 'slave'))->fetchObject();
- if ($latest_comment && $latest_comment->changed > $changed) {
- $changed = $latest_comment->changed;
- }
- return $changed;
-}
-
-/**
- * Cleans up indexed data when nodes or comments are removed.
- *
- * @param $nid
- * The node ID.
- * @param $uid
- * The author of the node or comment.
- * @param $changed
- * The last changed timestamp of the node.
- */
-function _tracker_remove($nid, $uid = NULL, $changed = NULL) {
- $node = db_query('SELECT nid, status, uid, changed FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
-
- // The user only keeps his or her subscription if both of the following are true:
- // (1) The node exists.
- // (2) The user is either the node author or has commented on the node.
- $keep_subscription = FALSE;
-
- if ($node) {
- // Self-authorship is one reason to keep the user's subscription.
- $keep_subscription = ($node->uid == $uid);
-
- // Comments are a second reason to keep the user's subscription.
- if (!$keep_subscription) {
- // Check if the user has commented at least once on the given nid.
- $keep_subscription = db_query_range('SELECT COUNT(*) FROM {comment} WHERE nid = :nid AND uid = :uid AND status = :status', 0, 1, array(
- ':nid' => $nid,
- ':uid' => $uid,
- ':status' => COMMENT_PUBLISHED,
- ))->fetchField();
- }
-
- // If we haven't found a reason to keep the user's subscription, delete it.
- if (!$keep_subscription) {
- db_delete('tracker_user')
- ->condition('nid', $nid)
- ->condition('uid', $uid)
- ->execute();
- }
-
- // Now we need to update the (possibly) changed timestamps for other users
- // and the node itself.
- // We only need to do this if the removed item has a timestamp that equals
- // or exceeds the listed changed timestamp for the node.
- $tracker_node = db_query('SELECT nid, changed FROM {tracker_node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject();
- if ($tracker_node && $changed >= $tracker_node->changed) {
- // If we're here, the item being removed is *possibly* the item that
- // established the node's changed timestamp.
-
- // We just have to recalculate things from scratch.
- $changed = _tracker_calculate_changed($nid);
-
- // And then we push the out the new changed timestamp to our denormalized
- // tables.
- db_update('tracker_node')
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->condition('nid', $nid)
- ->execute();
- db_update('tracker_node')
- ->fields(array(
- 'changed' => $changed,
- 'published' => $node->status,
- ))
- ->condition('nid', $nid)
- ->execute();
- }
- }
- else {
- // If the node doesn't exist, remove everything.
- db_delete('tracker_node')
- ->condition('nid', $nid)
- ->execute();
- db_delete('tracker_user')
- ->condition('nid', $nid)
- ->execute();
- }
-}
diff --git a/modules/tracker/tracker.pages.inc b/modules/tracker/tracker.pages.inc
deleted file mode 100644
index baa99866..00000000
--- a/modules/tracker/tracker.pages.inc
+++ /dev/null
@@ -1,129 +0,0 @@
-extend('PagerDefault');
- $query->condition('t.uid', $account->uid);
-
- if ($set_title) {
- // When viewed from user/%user/track, display the name of the user
- // as page title -- the tab title remains Track so this needs to be done
- // here and not in the menu definition.
- drupal_set_title(format_username($account));
- }
- }
- else {
- $query = db_select('tracker_node', 't', array('target' => 'slave'))->extend('PagerDefault');
- }
-
- // This array acts as a placeholder for the data selected later
- // while keeping the correct order.
- $nodes = $query
- ->addTag('node_access')
- ->fields('t', array('nid', 'changed'))
- ->condition('t.published', 1)
- ->orderBy('t.changed', 'DESC')
- ->limit(25)
- ->execute()
- ->fetchAllAssoc('nid');
-
- $rows = array();
- if (!empty($nodes)) {
- // Now, get the data and put into the placeholder array.
- $result = db_query('SELECT n.nid, n.title, n.type, n.changed, n.uid, u.name, l.comment_count FROM {node} n INNER JOIN {node_comment_statistics} l ON n.nid = l.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.nid IN (:nids)', array(':nids' => array_keys($nodes)), array('target' => 'slave'));
- foreach ($result as $node) {
- $node->last_activity = $nodes[$node->nid]->changed;
- $nodes[$node->nid] = $node;
- }
-
- // Display the data.
- foreach ($nodes as $node) {
- // Determine the number of comments.
- $comments = 0;
- if ($node->comment_count) {
- $comments = $node->comment_count;
-
- if ($new = comment_num_new($node->nid)) {
- $comments .= ' ';
- $comments .= l(format_plural($new, '1 new', '@count new'), 'node/' . $node->nid, array('fragment' => 'new'));
- }
- }
-
- $row = array(
- 'type' => check_plain(node_type_get_name($node->type)),
- 'title' => array('data' => l($node->title, 'node/' . $node->nid) . ' ' . theme('mark', array('type' => node_mark($node->nid, $node->changed)))),
- 'author' => array('data' => theme('username', array('account' => $node))),
- 'replies' => array('class' => array('replies'), 'data' => $comments),
- 'last updated' => array('data' => t('!time ago', array('!time' => format_interval(REQUEST_TIME - $node->last_activity)))),
- );
-
- // Adds extra RDFa markup to the $row array if the RDF module is enabled.
- if (function_exists('rdf_mapping_load')) {
- // Each node is not loaded for performance reasons, as a result we need
- // to retrieve the RDF mapping for each node type.
- $mapping = rdf_mapping_load('node', $node->type);
- // Adds RDFa markup to the title of the node. Because the RDFa markup is
- // added to the td tag which might contain HTML code, we specify an
- // empty datatype to ensure the value of the title read by the RDFa
- // parsers is a plain literal.
- $row['title'] += rdf_rdfa_attributes($mapping['title']) + array('datatype' => '');
- // Annotates the td tag containing the author of the node.
- $row['author'] += rdf_rdfa_attributes($mapping['uid']);
- // Annotates the td tag containing the number of replies. We add the
- // content attribute to ensure that only the comment count is used as
- // the value for 'num_replies'. Otherwise, other text such as a link
- // to the number of new comments could be included in the 'num_replies'
- // value.
- $row['replies'] += rdf_rdfa_attributes($mapping['comment_count']);
- $row['replies'] += array('content' => $node->comment_count);
- // If the node has no comments, we assume the node itself was modified
- // and apply 'changed' in addition to 'last_activity'. If there are
- // comments present, we cannot infer whether the node itself was
- // modified or a comment was posted, so we use only 'last_activity'.
- $mapping_last_activity = rdf_rdfa_attributes($mapping['last_activity'], $node->last_activity);
- if ($node->comment_count == 0) {
- $mapping_changed = rdf_rdfa_attributes($mapping['changed'], $node->last_activity);
- $mapping_last_activity['property'] = array_merge($mapping_last_activity['property'], $mapping_changed['property']);
- }
- $row['last updated'] += $mapping_last_activity;
-
- // We need to add the about attribute on the tr tag to specify which
- // node the RDFa annotations above apply to. We move the content of
- // $row to a 'data' sub array so we can specify attributes for the row.
- $row = array('data' => $row);
- $row['about'] = url('node/' . $node->nid);
- }
- $rows[] = $row;
- }
- }
-
- $page['tracker'] = array(
- '#rows' => $rows,
- '#header' => array(t('Type'), t('Title'), t('Author'), t('Replies'), t('Last updated')),
- '#theme' => 'table',
- '#empty' => t('No content available.'),
- '#attached' => array(
- 'css' => array(drupal_get_path('module', 'tracker') . '/tracker.css' => array()),
- ),
- );
- $page['pager'] = array(
- '#theme' => 'pager',
- '#quantity' => 25,
- '#weight' => 10,
- );
- $page['#sorted'] = TRUE;
-
- return $page;
-}
diff --git a/modules/tracker/tracker.test b/modules/tracker/tracker.test
deleted file mode 100644
index 66ebb848..00000000
--- a/modules/tracker/tracker.test
+++ /dev/null
@@ -1,268 +0,0 @@
- 'Tracker',
- 'description' => 'Create and delete nodes and check for their display in the tracker listings.',
- 'group' => 'Tracker'
- );
- }
-
- function setUp() {
- parent::setUp('comment', 'tracker');
-
- $permissions = array('access comments', 'create page content', 'post comments', 'skip comment approval');
- $this->user = $this->drupalCreateUser($permissions);
- $this->other_user = $this->drupalCreateUser($permissions);
-
- // Make node preview optional.
- variable_set('comment_preview_page', 0);
- }
-
- /**
- * Tests for the presence of nodes on the global tracker listing.
- */
- function testTrackerAll() {
- $this->drupalLogin($this->user);
-
- $unpublished = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'status' => 0,
- ));
- $published = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'status' => 1,
- ));
-
- $this->drupalGet('tracker');
- $this->assertNoText($unpublished->title, 'Unpublished node do not show up in the tracker listing.');
- $this->assertText($published->title, 'Published node show up in the tracker listing.');
- $this->assertLink(t('My recent content'), 0, 'User tab shows up on the global tracker page.');
-
- // Delete a node and ensure it no longer appears on the tracker.
- node_delete($published->nid);
- $this->drupalGet('tracker');
- $this->assertNoText($published->title, 'Deleted node do not show up in the tracker listing.');
- }
-
- /**
- * Tests for the presence of nodes on a user's tracker listing.
- */
- function testTrackerUser() {
- $this->drupalLogin($this->user);
-
- $unpublished = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'uid' => $this->user->uid,
- 'status' => 0,
- ));
- $my_published = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'uid' => $this->user->uid,
- 'status' => 1,
- ));
- $other_published_no_comment = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'uid' => $this->other_user->uid,
- 'status' => 1,
- ));
- $other_published_my_comment = $this->drupalCreateNode(array(
- 'title' => $this->randomName(8),
- 'uid' => $this->other_user->uid,
- 'status' => 1,
- ));
- $comment = array(
- 'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
- );
- $this->drupalPost('comment/reply/' . $other_published_my_comment->nid, $comment, t('Save'));
-
- $this->drupalGet('user/' . $this->user->uid . '/track');
- $this->assertNoText($unpublished->title, "Unpublished nodes do not show up in the users's tracker listing.");
- $this->assertText($my_published->title, "Published nodes show up in the user's tracker listing.");
- $this->assertNoText($other_published_no_comment->title, "Other user's nodes do not show up in the user's tracker listing.");
- $this->assertText($other_published_my_comment->title, "Nodes that the user has commented on appear in the user's tracker listing.");
-
- // Verify that unpublished comments are removed from the tracker.
- $admin_user = $this->drupalCreateUser(array('administer comments', 'access user profiles'));
- $this->drupalLogin($admin_user);
- $this->drupalPost('comment/1/edit', array('status' => COMMENT_NOT_PUBLISHED), t('Save'));
- $this->drupalGet('user/' . $this->user->uid . '/track');
- $this->assertNoText($other_published_my_comment->title, 'Unpublished comments are not counted on the tracker listing.');
- }
-
- /**
- * Tests for the presence of the "new" flag for nodes.
- */
- function testTrackerNewNodes() {
- $this->drupalLogin($this->user);
-
- $edit = array(
- 'title' => $this->randomName(8),
- );
-
- $node = $this->drupalCreateNode($edit);
- $title = $edit['title'];
- $this->drupalGet('tracker');
- $this->assertPattern('/' . $title . '.*new/', 'New nodes are flagged as such in the tracker listing.');
-
- $this->drupalGet('node/' . $node->nid);
- $this->drupalGet('tracker');
- $this->assertNoPattern('/' . $title . '.*new/', 'Visited nodes are not flagged as new.');
-
- $this->drupalLogin($this->other_user);
- $this->drupalGet('tracker');
- $this->assertPattern('/' . $title . '.*new/', 'For another user, new nodes are flagged as such in the tracker listing.');
-
- $this->drupalGet('node/' . $node->nid);
- $this->drupalGet('tracker');
- $this->assertNoPattern('/' . $title . '.*new/', 'For another user, visited nodes are not flagged as new.');
- }
-
- /**
- * Tests for comment counters on the tracker listing.
- */
- function testTrackerNewComments() {
- $this->drupalLogin($this->user);
-
- $node = $this->drupalCreateNode(array(
- 'comment' => 2,
- 'title' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(8)))),
- ));
-
- // Add a comment to the page.
- $comment = array(
- 'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
- );
- // The new comment is automatically viewed by the current user.
- $this->drupalPost('comment/reply/' . $node->nid, $comment, t('Save'));
-
- $this->drupalLogin($this->other_user);
- $this->drupalGet('tracker');
- $this->assertText('1 new', 'New comments are counted on the tracker listing pages.');
- $this->drupalGet('node/' . $node->nid);
-
- // Add another comment as other_user.
- $comment = array(
- 'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
- );
- // If the comment is posted in the same second as the last one then Drupal
- // can't tell the difference, so we wait one second here.
- sleep(1);
- $this->drupalPost('comment/reply/' . $node->nid, $comment, t('Save'));
-
- $this->drupalLogin($this->user);
- $this->drupalGet('tracker');
- $this->assertText('1 new', 'New comments are counted on the tracker listing pages.');
- }
-
- /**
- * Tests that existing nodes are indexed by cron.
- */
- function testTrackerCronIndexing() {
- $this->drupalLogin($this->user);
-
- // Create 3 nodes.
- $edits = array();
- $nodes = array();
- for ($i = 1; $i <= 3; $i++) {
- $edits[$i] = array(
- 'comment' => 2,
- 'title' => $this->randomName(),
- );
- $nodes[$i] = $this->drupalCreateNode($edits[$i]);
- }
-
- // Add a comment to the last node as other user.
- $this->drupalLogin($this->other_user);
- $comment = array(
- 'subject' => $this->randomName(),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => $this->randomName(20),
- );
- $this->drupalPost('comment/reply/' . $nodes[3]->nid, $comment, t('Save'));
-
- // Start indexing backwards from node 3.
- variable_set('tracker_index_nid', 3);
-
- // Clear the current tracker tables and rebuild them.
- db_delete('tracker_node')
- ->execute();
- db_delete('tracker_user')
- ->execute();
- tracker_cron();
-
- $this->drupalLogin($this->user);
-
- // Fetch the user's tracker.
- $this->drupalGet('tracker/' . $this->user->uid);
-
- // Assert that all node titles are displayed.
- foreach ($nodes as $i => $node) {
- $this->assertText($node->title, format_string('Node @i is displayed on the tracker listing pages.', array('@i' => $i)));
- }
- $this->assertText('1 new', 'New comment is counted on the tracker listing pages.');
- $this->assertText('updated', 'Node is listed as updated');
-
- // Fetch the site-wide tracker.
- $this->drupalGet('tracker');
-
- // Assert that all node titles are displayed.
- foreach ($nodes as $i => $node) {
- $this->assertText($node->title, format_string('Node @i is displayed on the tracker listing pages.', array('@i' => $i)));
- }
- $this->assertText('1 new', 'New comment is counted on the tracker listing pages.');
- }
-
- /**
- * Tests that publish/unpublish works at admin/content/node.
- */
- function testTrackerAdminUnpublish() {
- $admin_user = $this->drupalCreateUser(array('access content overview', 'administer nodes', 'bypass node access'));
- $this->drupalLogin($admin_user);
-
- $node = $this->drupalCreateNode(array(
- 'comment' => 2,
- 'title' => $this->randomName(),
- ));
-
- // Assert that the node is displayed.
- $this->drupalGet('tracker');
- $this->assertText($node->title, 'Node is displayed on the tracker listing pages.');
-
- // Unpublish the node and ensure that it's no longer displayed.
- $edit = array(
- 'operation' => 'unpublish',
- 'nodes[' . $node->nid . ']' => $node->nid,
- );
- $this->drupalPost('admin/content', $edit, t('Update'));
-
- $this->drupalGet('tracker');
- $this->assertText(t('No content available.'), 'Node is displayed on the tracker listing pages.');
- }
-}
diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info
deleted file mode 100644
index 4d83254a..00000000
--- a/modules/translation/tests/translation_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "Content Translation Test"
-description = "Support module for the content translation tests."
-core = 7.x
-package = Testing
-version = VERSION
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/translation/tests/translation_test.module b/modules/translation/tests/translation_test.module
deleted file mode 100644
index e3bb4b5f..00000000
--- a/modules/translation/tests/translation_test.module
+++ /dev/null
@@ -1,13 +0,0 @@
-' . t('About') . '';
- $output .= '' . t('The Content translation module allows content to be translated into different languages. Working with the Locale module (which manages enabled languages and provides translation for the site interface), the Content translation module is key to creating and maintaining translated site content. For more information, see the online handbook entry for Content translation module .', array('@locale' => url('admin/help/locale'), '@translation' => 'http://drupal.org/documentation/modules/translation/')) . '
';
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Configuring content types for translation') . ' ';
- $output .= '' . t('To configure a particular content type for translation, visit the Content types page, and click the edit link for the content type. In the Publishing options section, select Enabled, with translation under Multilingual support .', array('@content-types' => url('admin/structure/types'))) . ' ';
- $output .= '' . t('Assigning a language to content') . ' ';
- $output .= '' . t('Use the Language drop down to select the appropriate language when creating or editing content.') . ' ';
- $output .= '' . t('Translating content') . ' ';
- $output .= '' . t('Users with the translate content permission can translate content, if the content type has been configured to allow translations. To translate content, select the Translation tab when viewing the content, select the language for which you wish to provide content, and then enter the content.') . ' ';
- $output .= '' . t('Maintaining translations') . ' ';
- $output .= '' . t('If editing content in one language requires that translated versions also be updated to reflect the change, use the Flag translations as outdated check box to mark the translations as outdated and in need of revision. Individual translations may also be marked for revision by selecting the This translation needs to be updated check box on the translation editing form.') . ' ';
- $output .= ' ';
- return $output;
- case 'node/%/translate':
- $output = '' . t('Translations of a piece of content are managed with translation sets. Each translation set has one source post and any number of translations in any of the enabled languages . All translations are tracked to be up to date or outdated based on whether the source post was modified significantly.', array('!languages' => url('admin/config/regional/language'))) . '
';
- return $output;
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function translation_menu() {
- $items = array();
- $items['node/%node/translate'] = array(
- 'title' => 'Translate',
- 'page callback' => 'translation_node_overview',
- 'page arguments' => array(1),
- 'access callback' => '_translation_tab_access',
- 'access arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 2,
- 'file' => 'translation.pages.inc',
- );
- return $items;
-}
-
-/**
- * Access callback: Checks that the user has permission to 'translate content'.
- *
- * Only displays the translation tab for nodes that are not language-neutral
- * of types that have translation enabled.
- *
- * @param $node
- * A node object.
- *
- * @return
- * TRUE if the translation tab should be displayed, FALSE otherwise.
- *
- * @see translation_menu()
- */
-function _translation_tab_access($node) {
- if (entity_language('node', $node) != LANGUAGE_NONE && translation_supported_type($node->type) && node_access('view', $node)) {
- return user_access('translate content');
- }
- return FALSE;
-}
-
-/**
- * Implements hook_admin_paths().
- */
-function translation_admin_paths() {
- if (variable_get('node_admin_theme')) {
- $paths = array(
- 'node/*/translate' => TRUE,
- );
- return $paths;
- }
-}
-
-/**
- * Implements hook_permission().
- */
-function translation_permission() {
- return array(
- 'translate content' => array(
- 'title' => t('Translate content'),
- ),
- );
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for node_type_form().
- */
-function translation_form_node_type_form_alter(&$form, &$form_state) {
- // Add translation option to content type form.
- $form['workflow']['language_content_type']['#options'][TRANSLATION_ENABLED] = t('Enabled, with translation');
- // Description based on text from locale.module.
- $form['workflow']['language_content_type']['#description'] = t('Enable multilingual support for this content type. If enabled, a language selection field will be added to the editing form, allowing you to select from one of the enabled languages . You can also turn on translation for this content type, which lets you have content translated to any of the installed languages. If disabled, new posts are saved with the default language. Existing content will not be affected by changing this option.', array('!languages' => url('admin/config/regional/language')));
-}
-
-/**
- * Implements hook_form_BASE_FORM_ID_alter() for node_form().
- *
- * Alters language fields on node edit forms when a translation is about to be
- * created.
- *
- * @see node_form()
- */
-function translation_form_node_form_alter(&$form, &$form_state) {
- if (translation_supported_type($form['#node']->type)) {
- $node = $form['#node'];
- $languages = language_list('enabled');
- $disabled_languages = isset($languages[0]) ? $languages[0] : FALSE;
- $translator_widget = $disabled_languages && user_access('translate content');
- $groups = array(t('Disabled'), t('Enabled'));
- // Allow translators to enter content in disabled languages. Translators
- // might need to distinguish between enabled and disabled languages, hence
- // we divide them in two option groups.
- if ($translator_widget) {
- $options = array($groups[1] => array(LANGUAGE_NONE => t('Language neutral')));
- $language_list = locale_language_list('name', TRUE);
- foreach (array(1, 0) as $status) {
- $group = $groups[$status];
- foreach ($languages[$status] as $langcode => $language) {
- $options[$group][$langcode] = $language_list[$langcode];
- }
- }
- $form['language']['#options'] = $options;
- }
- if (!empty($node->translation_source)) {
- // We are creating a translation. Add values and lock language field.
- $form['translation_source'] = array('#type' => 'value', '#value' => $node->translation_source);
- $form['language']['#disabled'] = TRUE;
- }
- elseif (!empty($node->nid) && !empty($node->tnid)) {
- // Disable languages for existing translations, so it is not possible to switch this
- // node to some language which is already in the translation set. Also remove the
- // language neutral option.
- unset($form['language']['#options'][LANGUAGE_NONE]);
- foreach (translation_node_get_translations($node->tnid) as $langcode => $translation) {
- if ($translation->nid != $node->nid) {
- if ($translator_widget) {
- $group = $groups[(int)!isset($disabled_languages[$langcode])];
- unset($form['language']['#options'][$group][$langcode]);
- }
- else {
- unset($form['language']['#options'][$langcode]);
- }
- }
- }
- // Add translation values and workflow options.
- $form['tnid'] = array('#type' => 'value', '#value' => $node->tnid);
- $form['translation'] = array(
- '#type' => 'fieldset',
- '#title' => t('Translation settings'),
- '#access' => user_access('translate content'),
- '#collapsible' => TRUE,
- '#collapsed' => !$node->translate,
- '#tree' => TRUE,
- '#weight' => 30,
- );
- if ($node->tnid == $node->nid) {
- // This is the source node of the translation
- $form['translation']['retranslate'] = array(
- '#type' => 'checkbox',
- '#title' => t('Flag translations as outdated'),
- '#default_value' => 0,
- '#description' => t('If you made a significant change, which means translations should be updated, you can flag all translations of this post as outdated. This will not change any other property of those posts, like whether they are published or not.'),
- );
- $form['translation']['status'] = array('#type' => 'value', '#value' => 0);
- }
- else {
- $form['translation']['status'] = array(
- '#type' => 'checkbox',
- '#title' => t('This translation needs to be updated'),
- '#default_value' => $node->translate,
- '#description' => t('When this option is checked, this translation needs to be updated because the source post has changed. Uncheck when the translation is up to date again.'),
- );
- }
- }
- }
-}
-
-/**
- * Implements hook_node_view().
- *
- * Displays translation links with language names if this node is part of a
- * translation set. If no language provider is enabled, "fall back" to simple
- * links built through the result of translation_node_get_translations().
- */
-function translation_node_view($node, $view_mode) {
- // If the site has no translations or is not multilingual we have no content
- // translation links to display.
- if (isset($node->tnid) && drupal_multilingual() && $translations = translation_node_get_translations($node->tnid)) {
- $languages = language_list('enabled');
- $languages = $languages[1];
-
- // There might be a language provider enabled defining custom language
- // switch links which need to be taken into account while generating the
- // content translation links. As custom language switch links are available
- // only for configurable language types and interface language is the only
- // configurable language type in core, we use it as default. Contributed
- // modules can change this behavior by setting the system variable below.
- $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
- $custom_links = language_negotiation_get_switch_links($type, "node/$node->nid");
- $links = array();
-
- foreach ($translations as $langcode => $translation) {
- // Do not show links to the same node, to unpublished translations or to
- // translations in disabled languages.
- if ($translation->status && isset($languages[$langcode]) && $langcode != entity_language('node', $node)) {
- $language = $languages[$langcode];
- $key = "translation_$langcode";
-
- if (isset($custom_links->links[$langcode])) {
- $links[$key] = $custom_links->links[$langcode];
- }
- else {
- $links[$key] = array(
- 'href' => "node/{$translation->nid}",
- 'title' => $language->native,
- 'language' => $language,
- );
- }
-
- // Custom switch links are more generic than content translation links,
- // hence we override existing attributes with the ones below.
- $links[$key] += array('attributes' => array());
- $attributes = array(
- 'title' => $translation->title,
- 'class' => array('translation-link'),
- );
- $links[$key]['attributes'] = $attributes + $links[$key]['attributes'];
- }
- }
-
- $node->content['links']['translation'] = array(
- '#theme' => 'links__node__translation',
- '#links' => $links,
- '#attributes' => array('class' => array('links', 'inline')),
- );
- }
-}
-
-/**
- * Implements hook_node_prepare().
- */
-function translation_node_prepare($node) {
- // Only act if we are dealing with a content type supporting translations.
- if (translation_supported_type($node->type) &&
- // And it's a new node.
- empty($node->nid) &&
- // And the user has permission to translate content.
- user_access('translate content') &&
- // And the $_GET variables are set properly.
- isset($_GET['translation']) &&
- isset($_GET['target']) &&
- is_numeric($_GET['translation'])) {
-
- $source_node = node_load($_GET['translation']);
- if (empty($source_node) || !node_access('view', $source_node)) {
- // Source node not found or no access to view. We should not check
- // for edit access, since the translator might not have permissions
- // to edit the source node but should still be able to translate.
- return;
- }
-
- $language_list = language_list();
- $langcode = $_GET['target'];
- if (!isset($language_list[$langcode]) || ($source_node->language == $langcode)) {
- // If not supported language, or same language as source node, break.
- return;
- }
-
- // Ensure we don't have an existing translation in this language.
- if (!empty($source_node->tnid)) {
- $translations = translation_node_get_translations($source_node->tnid);
- if (isset($translations[$langcode])) {
- drupal_set_message(t('A translation of %title in %language already exists, a new %type will be created instead of a translation.', array('%title' => $source_node->title, '%language' => $language_list[$langcode]->name, '%type' => $node->type)), 'error');
- return;
- }
- }
-
- // Populate fields based on source node.
- $node->language = $langcode;
- $node->translation_source = $source_node;
- $node->title = $source_node->title;
-
- // Add field translations and let other modules module add custom translated
- // fields.
- field_attach_prepare_translation('node', $node, $langcode, $source_node, $source_node->language);
- }
-}
-
-/**
- * Implements hook_node_insert().
- */
-function translation_node_insert($node) {
- // Only act if we are dealing with a content type supporting translations.
- if (translation_supported_type($node->type)) {
- if (!empty($node->translation_source)) {
- if ($node->translation_source->tnid) {
- // Add node to existing translation set.
- $tnid = $node->translation_source->tnid;
- }
- else {
- // Create new translation set, using nid from the source node.
- $tnid = $node->translation_source->nid;
- db_update('node')
- ->fields(array(
- 'tnid' => $tnid,
- 'translate' => 0,
- ))
- ->condition('nid', $node->translation_source->nid)
- ->execute();
- }
- db_update('node')
- ->fields(array(
- 'tnid' => $tnid,
- 'translate' => 0,
- ))
- ->condition('nid', $node->nid)
- ->execute();
- // Save tnid to avoid loss in case of resave.
- $node->tnid = $tnid;
- }
- }
-}
-
-/**
- * Implements hook_node_update().
- */
-function translation_node_update($node) {
- // Only act if we are dealing with a content type supporting translations.
- if (translation_supported_type($node->type)) {
- $langcode = entity_language('node', $node);
- if (isset($node->translation) && $node->translation && !empty($langcode) && $node->tnid) {
- // Update translation information.
- db_update('node')
- ->fields(array(
- 'tnid' => $node->tnid,
- 'translate' => $node->translation['status'],
- ))
- ->condition('nid', $node->nid)
- ->execute();
- if (!empty($node->translation['retranslate'])) {
- // This is the source node, asking to mark all translations outdated.
- db_update('node')
- ->fields(array('translate' => 1))
- ->condition('nid', $node->nid, '<>')
- ->condition('tnid', $node->tnid)
- ->execute();
- }
- }
- }
-}
-
-/**
- * Implements hook_node_validate().
- *
- * Ensures that duplicate translations can't be created for the same source.
- */
-function translation_node_validate($node, $form) {
- // Only act on translatable nodes with a tnid or translation_source.
- if (translation_supported_type($node->type) && (!empty($node->tnid) || !empty($form['#node']->translation_source->nid))) {
- $tnid = !empty($node->tnid) ? $node->tnid : $form['#node']->translation_source->nid;
- $translations = translation_node_get_translations($tnid);
- $langcode = entity_language('node', $node);
- if (isset($translations[$langcode]) && $translations[$langcode]->nid != $node->nid ) {
- form_set_error('language', t('There is already a translation in this language.'));
- }
- }
-}
-
-/**
- * Implements hook_node_delete().
- */
-function translation_node_delete($node) {
- // Only act if we are dealing with a content type supporting translations.
- if (translation_supported_type($node->type)) {
- translation_remove_from_set($node);
- }
-}
-
-/**
- * Removes a node from its translation set and updates accordingly.
- *
- * @param $node
- * A node object.
- */
-function translation_remove_from_set($node) {
- if (isset($node->tnid)) {
- $query = db_update('node')
- ->fields(array(
- 'tnid' => 0,
- 'translate' => 0,
- ));
- if (db_query('SELECT COUNT(*) FROM {node} WHERE tnid = :tnid', array(':tnid' => $node->tnid))->fetchField() == 1) {
- // There is only one node left in the set: remove the set altogether.
- $query
- ->condition('tnid', $node->tnid)
- ->execute();
- }
- else {
- $query
- ->condition('nid', $node->nid)
- ->execute();
-
- // If the node being removed was the source of the translation set,
- // we pick a new source - preferably one that is up to date.
- if ($node->tnid == $node->nid) {
- $new_tnid = db_query('SELECT nid FROM {node} WHERE tnid = :tnid ORDER BY translate ASC, nid ASC', array(':tnid' => $node->tnid))->fetchField();
- db_update('node')
- ->fields(array('tnid' => $new_tnid))
- ->condition('tnid', $node->tnid)
- ->execute();
- }
- }
- }
-}
-
-/**
- * Gets all nodes in a given translation set.
- *
- * @param $tnid
- * The translation source nid of the translation set, the identifier of the
- * node used to derive all translations in the set.
- *
- * @return
- * Array of partial node objects (nid, title, language) representing all
- * nodes in the translation set, in effect all translations of node $tnid,
- * including node $tnid itself. Because these are partial nodes, you need to
- * node_load() the full node, if you need more properties. The array is
- * indexed by language code.
- */
-function translation_node_get_translations($tnid) {
- if (is_numeric($tnid) && $tnid) {
- $translations = &drupal_static(__FUNCTION__, array());
-
- if (!isset($translations[$tnid])) {
- $translations[$tnid] = array();
- $result = db_select('node', 'n')
- ->fields('n', array('nid', 'type', 'uid', 'status', 'title', 'language'))
- ->condition('n.tnid', $tnid)
- ->addTag('node_access')
- ->execute();
-
- foreach ($result as $node) {
- $langcode = entity_language('node', $node);
- $translations[$tnid][$langcode] = $node;
- }
- }
- return $translations[$tnid];
- }
-}
-
-/**
- * Returns whether the given content type has support for translations.
- *
- * @return
- * TRUE if translation is supported, and FALSE if not.
- */
-function translation_supported_type($type) {
- return variable_get('language_content_type_' . $type, 0) == TRANSLATION_ENABLED;
-}
-
-/**
- * Returns the paths of all translations of a node, based on its Drupal path.
- *
- * @param $path
- * A Drupal path, for example node/432.
- *
- * @return
- * An array of paths of translations of the node accessible to the current
- * user, keyed with language codes.
- */
-function translation_path_get_translations($path) {
- $paths = array();
- // Check for a node related path, and for its translations.
- if ((preg_match("!^node/(\d+)(/.+|)$!", $path, $matches)) && ($node = node_load((int) $matches[1])) && !empty($node->tnid)) {
- foreach (translation_node_get_translations($node->tnid) as $language => $translation_node) {
- $paths[$language] = 'node/' . $translation_node->nid . $matches[2];
- }
- }
- return $paths;
-}
-
-/**
- * Implements hook_language_switch_links_alter().
- *
- * Replaces links with pointers to translated versions of the content.
- */
-function translation_language_switch_links_alter(array &$links, $type, $path) {
- $language_type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
-
- if ($type == $language_type && preg_match("!^node/(\d+)(/.+|)!", $path, $matches)) {
- $node = node_load((int) $matches[1]);
-
- if (empty($node->tnid)) {
- // If the node cannot be found nothing needs to be done. If it does not
- // have translations it might be a language neutral node, in which case we
- // must leave the language switch links unaltered. This is true also for
- // nodes not having translation support enabled.
- if (empty($node) || entity_language('node', $node) == LANGUAGE_NONE || !translation_supported_type($node->type)) {
- return;
- }
- $langcode = entity_language('node', $node);
- $translations = array($langcode => $node);
- }
- else {
- $translations = translation_node_get_translations($node->tnid);
- }
-
- foreach ($links as $langcode => $link) {
- if (isset($translations[$langcode]) && $translations[$langcode]->status) {
- // Translation in a different node.
- $links[$langcode]['href'] = 'node/' . $translations[$langcode]->nid . $matches[2];
- }
- else {
- // No translation in this language, or no permission to view.
- unset($links[$langcode]['href']);
- $links[$langcode]['attributes']['class'][] = 'locale-untranslated';
- }
- }
- }
-}
diff --git a/modules/translation/translation.pages.inc b/modules/translation/translation.pages.inc
deleted file mode 100644
index 110fea60..00000000
--- a/modules/translation/translation.pages.inc
+++ /dev/null
@@ -1,82 +0,0 @@
-tnid) {
- // Already part of a set, grab that set.
- $tnid = $node->tnid;
- $translations = translation_node_get_translations($node->tnid);
- }
- else {
- // We have no translation source nid, this could be a new set, emulate that.
- $tnid = $node->nid;
- $translations = array(entity_language('node', $node) => $node);
- }
-
- $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
- $header = array(t('Language'), t('Title'), t('Status'), t('Operations'));
-
- foreach (language_list() as $langcode => $language) {
- $options = array();
- $language_name = $language->name;
- if (isset($translations[$langcode])) {
- // Existing translation in the translation set: display status.
- // We load the full node to check whether the user can edit it.
- $translation_node = node_load($translations[$langcode]->nid);
- $path = 'node/' . $translation_node->nid;
- $links = language_negotiation_get_switch_links($type, $path);
- $title = empty($links->links[$langcode]['href']) ? l($translation_node->title, $path) : l($translation_node->title, $links->links[$langcode]['href'], $links->links[$langcode]);
- if (node_access('update', $translation_node)) {
- $text = t('edit');
- $path = 'node/' . $translation_node->nid . '/edit';
- $links = language_negotiation_get_switch_links($type, $path);
- $options[] = empty($links->links[$langcode]['href']) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]);
- }
- $status = $translation_node->status ? t('Published') : t('Not published');
- $status .= $translation_node->translate ? ' - ' . t('outdated') . ' ' : '';
- if ($translation_node->nid == $tnid) {
- $language_name = t('@language_name (source)', array('@language_name' => $language_name));
- }
- }
- else {
- // No such translation in the set yet: help user to create it.
- $title = t('n/a');
- if (node_access('create', $node)) {
- $text = t('add translation');
- $path = 'node/add/' . str_replace('_', '-', $node->type);
- $links = language_negotiation_get_switch_links($type, $path);
- $query = array('query' => array('translation' => $node->nid, 'target' => $langcode));
- $options[] = empty($links->links[$langcode]['href']) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query));
- }
- $status = t('Not translated');
- }
- $rows[] = array($language_name, $title, $status, implode(" | ", $options));
- }
-
- drupal_set_title(t('Translations of %title', array('%title' => $node->title)), PASS_THROUGH);
-
- $build['translation_node_overview'] = array(
- '#theme' => 'table',
- '#header' => $header,
- '#rows' => $rows,
- );
-
- return $build;
-}
diff --git a/modules/translation/translation.test b/modules/translation/translation.test
deleted file mode 100644
index 4d272f3e..00000000
--- a/modules/translation/translation.test
+++ /dev/null
@@ -1,492 +0,0 @@
- 'Translation functionality',
- 'description' => 'Create a basic page with translation, modify the page outdating translation, and update translation.',
- 'group' => 'Translation'
- );
- }
-
- function setUp() {
- parent::setUp('locale', 'translation', 'translation_test');
-
- // Setup users.
- $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate content'));
- $this->translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content'));
-
- $this->drupalLogin($this->admin_user);
-
- // Add languages.
- $this->addLanguage('en');
- $this->addLanguage('es');
- $this->addLanguage('it');
-
- // Disable Italian to test the translation behavior with disabled languages.
- $edit = array('enabled[it]' => FALSE);
- $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
-
- // Set "Basic page" content type to use multilingual support with
- // translation.
- $this->drupalGet('admin/structure/types/manage/page');
- $edit = array();
- $edit['language_content_type'] = 2;
- $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')), 'Basic page content type has been updated.');
-
- // Enable the language switcher block.
- $language_type = LANGUAGE_TYPE_INTERFACE;
- $edit = array("blocks[locale_$language_type][region]" => 'sidebar_first');
- $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-
- // Enable URL language detection and selection to make the language switcher
- // block appear.
- $edit = array('language[enabled][locale-url]' => TRUE);
- $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
- $this->assertRaw(t('Language negotiation configuration saved.'), 'URL language detection enabled.');
- $this->resetCaches();
-
- $this->drupalLogin($this->translator);
- }
-
- /**
- * Creates, modifies, and updates a basic page with a translation.
- */
- function testContentTranslation() {
- // Create Basic page in English.
- $node_title = $this->randomName();
- $node_body = $this->randomName();
- $node = $this->createPage($node_title, $node_body, 'en');
-
- // Unpublish the original node to check that this has no impact on the
- // translation overview page, publish it again afterwards.
- $this->drupalLogin($this->admin_user);
- $this->drupalPost('node/' . $node->nid . '/edit', array('status' => FALSE), t('Save'));
- $this->drupalGet('node/' . $node->nid . '/translate');
- $this->drupalPost('node/' . $node->nid . '/edit', array('status' => NODE_PUBLISHED), t('Save'));
- $this->drupalLogin($this->translator);
-
- // Check that the "add translation" link uses a localized path.
- $languages = language_list();
- $this->drupalGet('node/' . $node->nid . '/translate');
- $this->assertLinkByHref($languages['es']->prefix . '/node/add/' . str_replace('_', '-', $node->type), 0, format_string('The "add translation" link for %language points to the localized path of the target language.', array('%language' => $languages['es']->name)));
-
- // Submit translation in Spanish.
- $node_translation_title = $this->randomName();
- $node_translation_body = $this->randomName();
- $node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es');
-
- // Check that the "edit translation" and "view node" links use localized
- // paths.
- $this->drupalGet('node/' . $node->nid . '/translate');
- $this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid . '/edit', 0, format_string('The "edit" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
- $this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid, 0, format_string('The "view" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
-
- // Attempt to submit a duplicate translation by visiting the node/add page
- // with identical query string.
- $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => 'es')));
- $this->assertRaw(t('A translation of %title in %language already exists', array('%title' => $node_title, '%language' => $languages['es']->name)), 'Message regarding attempted duplicate translation is displayed.');
-
- // Attempt a resubmission of the form - this emulates using the back button
- // to return to the page then resubmitting the form without a refresh.
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $this->randomName();
- $edit["body[$langcode][0][value]"] = $this->randomName();
- $this->drupalPost('node/add/page', $edit, t('Save'), array('query' => array('translation' => $node->nid, 'language' => 'es')));
- $duplicate = $this->drupalGetNodeByTitle($edit["title"]);
- $this->assertEqual($duplicate->tnid, 0, 'The node does not have a tnid.');
-
- // Update original and mark translation as outdated.
- $node_body = $this->randomName();
- $node->body[LANGUAGE_NONE][0]['value'] = $node_body;
- $edit = array();
- $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)), 'Original node updated.');
-
- // Check to make sure that interface shows translation as outdated.
- $this->drupalGet('node/' . $node->nid . '/translate');
- $this->assertRaw('' . t('outdated') . ' ', 'Translation marked as outdated.');
-
- // Update translation and mark as updated.
- $edit = array();
- $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)), 'Translated node updated.');
-
- // Confirm that disabled languages are an option for translators when
- // creating nodes.
- $this->drupalGet('node/add/page');
- $this->assertFieldByXPath('//select[@name="language"]//option', 'it', 'Italian (disabled) is available in language selection.');
- $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
- $this->assertRaw($translation_it->body[LANGUAGE_NONE][0]['value'], 'Content created in Italian (disabled).');
-
- // Confirm that language neutral is an option for translators when there are
- // disabled languages.
- $this->drupalGet('node/add/page');
- $this->assertFieldByXPath('//select[@name="language"]//option', LANGUAGE_NONE, 'Language neutral is available in language selection with disabled languages.');
- $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NONE);
- $this->assertRaw($node2->body[LANGUAGE_NONE][0]['value'], 'Language neutral content created with disabled languages available.');
-
- // Leave just one language enabled and check that the translation overview
- // page is still accessible.
- $this->drupalLogin($this->admin_user);
- $edit = array('enabled[es]' => FALSE);
- $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
- $this->drupalLogin($this->translator);
- $this->drupalGet('node/' . $node->nid . '/translate');
- $this->assertRaw(t('Translations of %title', array('%title' => $node->title)), 'Translation overview page available with only one language enabled.');
- }
-
- /**
- * Checks that the language switch links behave properly.
- */
- function testLanguageSwitchLinks() {
- // Create a Basic page in English and its translations in Spanish and
- // Italian.
- $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
- $translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
- $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
-
- // Check that language switch links are correctly shown only for enabled
- // languages.
- $this->assertLanguageSwitchLinks($node, $translation_es);
- $this->assertLanguageSwitchLinks($translation_es, $node);
- $this->assertLanguageSwitchLinks($node, $translation_it, FALSE);
-
- // Check that links to the displayed translation appear only in the language
- // switcher block.
- $this->assertLanguageSwitchLinks($node, $node, FALSE, 'node');
- $this->assertLanguageSwitchLinks($node, $node, TRUE, 'block-locale');
-
- // Unpublish the Spanish translation to check that the related language
- // switch link is not shown.
- $this->drupalLogin($this->admin_user);
- $edit = array('status' => FALSE);
- $this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
- $this->drupalLogin($this->translator);
- $this->assertLanguageSwitchLinks($node, $translation_es, FALSE);
-
- // Check that content translation links are shown even when no language
- // negotiation is configured.
- $this->drupalLogin($this->admin_user);
- $edit = array('language[enabled][locale-url]' => FALSE);
- $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
- $this->resetCaches();
- $edit = array('status' => TRUE);
- $this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
- $this->drupalLogin($this->translator);
- $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, 'node');
- }
-
- /**
- * Tests that the language switcher block alterations work as intended.
- */
- function testLanguageSwitcherBlockIntegration() {
- // Enable Italian to have three items in the language switcher block.
- $this->drupalLogin($this->admin_user);
- $edit = array('enabled[it]' => TRUE);
- $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
- $this->drupalLogin($this->translator);
-
- // Create a Basic page in English.
- $type = 'block-locale';
- $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
- $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $this->emptyNode('es'), TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
-
- // Create the Spanish translation.
- $translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
- $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
-
- // Create the Italian translation.
- $translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
- $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $translation_it, TRUE, $type);
-
- // Create a language neutral node and check that the language switcher is
- // left untouched.
- $node2 = $this->createPage($this->randomName(), $this->randomName(), LANGUAGE_NONE);
- $node2_en = (object) array('nid' => $node2->nid, 'language' => 'en');
- $node2_es = (object) array('nid' => $node2->nid, 'language' => 'es');
- $node2_it = (object) array('nid' => $node2->nid, 'language' => 'it');
- $this->assertLanguageSwitchLinks($node2_en, $node2_en, TRUE, $type);
- $this->assertLanguageSwitchLinks($node2_en, $node2_es, TRUE, $type);
- $this->assertLanguageSwitchLinks($node2_en, $node2_it, TRUE, $type);
-
- // Disable translation support to check that the language switcher is left
- // untouched only for new nodes.
- $this->drupalLogin($this->admin_user);
- $edit = array('language_content_type' => 0);
- $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
- $this->drupalLogin($this->translator);
-
- // Existing translations trigger alterations even if translation support is
- // disabled.
- $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $translation_it, TRUE, $type);
-
- // Check that new nodes with a language assigned do not trigger language
- // switcher alterations when translation support is disabled.
- $node = $this->createPage($this->randomName(), $this->randomName());
- $node_es = (object) array('nid' => $node->nid, 'language' => 'es');
- $node_it = (object) array('nid' => $node->nid, 'language' => 'it');
- $this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $node_es, TRUE, $type);
- $this->assertLanguageSwitchLinks($node, $node_it, TRUE, $type);
- }
-
- /**
- * Resets static caches to make the test code match the client-side behavior.
- */
- function resetCaches() {
- drupal_static_reset('locale_url_outbound_alter');
- }
-
- /**
- * Returns an empty node data structure.
- *
- * @param $langcode
- * The language code.
- *
- * @return
- * An empty node data structure.
- */
- function emptyNode($langcode) {
- return (object) array('nid' => NULL, 'language' => $langcode);
- }
-
- /**
- * Installs the specified language, or enables it if it is already installed.
- *
- * @param $language_code
- * The language code to check.
- */
- function addLanguage($language_code) {
- // Check to make sure that language has not already been installed.
- $this->drupalGet('admin/config/regional/language');
-
- if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
- // Doesn't have language installed so add it.
- $edit = array();
- $edit['langcode'] = $language_code;
- $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
- // Make sure we are not using a stale list.
- drupal_static_reset('language_list');
- $languages = language_list('language');
- $this->assertTrue(array_key_exists($language_code, $languages), 'Language was installed successfully.');
-
- if (array_key_exists($language_code, $languages)) {
- $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the help screen .', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), 'Language has been created.');
- }
- }
- elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
- // It's installed and enabled. No need to do anything.
- $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
- }
- else {
- // It's installed but not enabled. Enable it.
- $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
- $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
- $this->assertRaw(t('Configuration saved.'), 'Language successfully enabled.');
- }
- }
-
- /**
- * Creates a "Basic page" in the specified language.
- *
- * @param $title
- * The title of a basic page in the specified language.
- * @param $body
- * The body of a basic page in the specified language.
- * @param $language
- * (optional) Language code.
- *
- * @return
- * A node object.
- */
- function createPage($title, $body, $language = NULL) {
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = $title;
- $edit["body[$langcode][0][value]"] = $body;
- if (!empty($language)) {
- $edit['language'] = $language;
- }
- $this->drupalPost('node/add/page', $edit, t('Save'));
- $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');
-
- // Check to make sure the node was created.
- $node = $this->drupalGetNodeByTitle($title);
- $this->assertTrue($node, 'Node found in database.');
-
- return $node;
- }
-
- /**
- * Creates a translation for a basic page in the specified language.
- *
- * @param $node
- * The basic page to create the translation for.
- * @param $title
- * The title of a basic page in the specified language.
- * @param $body
- * The body of a basic page in the specified language.
- * @param $language
- * Language code.
- *
- * @return
- * Translation object.
- */
- function createTranslation($node, $title, $body, $language) {
- $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
-
- $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[LANGUAGE_NONE][0]['value'], "Original body value correctly populated.");
-
- $edit = array();
- $edit["title"] = $title;
- $edit[$body_key] = $body;
- $this->drupalPost(NULL, $edit, t('Save'));
- $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Translation created.');
-
- // Check to make sure that translation was successful.
- $translation = $this->drupalGetNodeByTitle($title);
- $this->assertTrue($translation, 'Node found in database.');
- $this->assertTrue($translation->tnid == $node->nid, 'Translation set id correctly stored.');
-
- return $translation;
- }
-
- /**
- * Asserts an element identified by the given XPath has the given content.
- *
- * @param $xpath
- * The XPath used to find the element.
- * @param array $arguments
- * An array of arguments with keys in the form ':name' matching the
- * placeholders in the query. The values may be either strings or numeric
- * values.
- * @param $value
- * The text content of the matched element to assert.
- * @param $message
- * The message to display.
- * @param $group
- * The group this message belongs to.
- *
- * @return
- * TRUE on pass, FALSE on fail.
- */
- function assertContentByXPath($xpath, array $arguments = array(), $value = NULL, $message = '', $group = 'Other') {
- $found = $this->findContentByXPath($xpath, $arguments, $value);
- return $this->assertTrue($found, $message, $group);
- }
-
- /**
- * Tests whether the specified language switch links are found.
- *
- * @param $node
- * The node to display.
- * @param $translation
- * The translation whose link has to be checked.
- * @param $find
- * TRUE if the link must be present in the node page.
- * @param $types
- * The page areas to be checked.
- *
- * @return
- * TRUE if the language switch links are found, FALSE if not.
- */
- function assertLanguageSwitchLinks($node, $translation, $find = TRUE, $types = NULL) {
- if (empty($types)) {
- $types = array('node', 'block-locale');
- }
- elseif (is_string($types)) {
- $types = array($types);
- }
-
- $result = TRUE;
- $languages = language_list();
- $page_language = $languages[entity_language('node', $node)];
- $translation_language = $languages[$translation->language];
- $url = url("node/$translation->nid", array('language' => $translation_language));
-
- $this->drupalGet("node/$node->nid", array('language' => $page_language));
-
- foreach ($types as $type) {
- $args = array('%translation_language' => $translation_language->native, '%page_language' => $page_language->native, '%type' => $type);
- if ($find) {
- $message = format_string('[%page_language] Language switch item found for %translation_language language in the %type page area.', $args);
- }
- else {
- $message = format_string('[%page_language] Language switch item not found for %translation_language language in the %type page area.', $args);
- }
-
- if (!empty($translation->nid)) {
- $xpath = '//div[contains(@class, :type)]//a[@href=:url]';
- }
- else {
- $xpath = '//div[contains(@class, :type)]//span[contains(@class, "locale-untranslated")]';
- }
-
- $found = $this->findContentByXPath($xpath, array(':type' => $type, ':url' => $url), $translation_language->native);
- $result = $this->assertTrue($found == $find, $message) && $result;
- }
-
- return $result;
- }
-
- /**
- * Searches for elements matching the given xpath and value.
- *
- * @param $xpath
- * The XPath used to find the element.
- * @param array $arguments
- * An array of arguments with keys in the form ':name' matching the
- * placeholders in the query. The values may be either strings or numeric
- * values.
- * @param $value
- * The text content of the matched element to assert.
- *
- * @return
- * TRUE if found, otherwise FALSE.
- */
- function findContentByXPath($xpath, array $arguments = array(), $value = NULL) {
- $elements = $this->xpath($xpath, $arguments);
-
- $found = TRUE;
- if ($value && $elements) {
- $found = FALSE;
- foreach ($elements as $element) {
- if ((string) $element == $value) {
- $found = TRUE;
- break;
- }
- }
- }
-
- return $elements && $found;
- }
-}
diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info
deleted file mode 100644
index 56561377..00000000
--- a/modules/trigger/tests/trigger_test.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = "Trigger Test"
-description = "Support module for Trigger tests."
-package = Testing
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/trigger/tests/trigger_test.module b/modules/trigger/tests/trigger_test.module
deleted file mode 100644
index 72fe3528..00000000
--- a/modules/trigger/tests/trigger_test.module
+++ /dev/null
@@ -1,136 +0,0 @@
- array(
- 'type' => 'system',
- 'label' => t('Cron test action'),
- 'configurable' => FALSE,
- 'triggers' => array('cron'),
- ),
- 'trigger_test_system_cron_conf_action' => array(
- 'type' => 'system',
- 'label' => t('Cron test configurable action'),
- 'configurable' => TRUE,
- 'triggers' => array('cron'),
- ),
- 'trigger_test_generic_action' => array(
- 'type' => 'system',
- 'label' => t('Generic test action'),
- 'configurable' => FALSE,
- 'triggers' => array(
- 'taxonomy_term_insert',
- 'taxonomy_term_update',
- 'taxonomy_delete',
- 'comment_insert',
- 'comment_update',
- 'comment_delete',
- 'user_insert',
- 'user_update',
- 'user_delete',
- 'user_login',
- 'user_logout',
- 'user_view',
- ),
- ),
- 'trigger_test_generic_any_action' => array(
- 'type' => 'system',
- 'label' => t('Generic test action for any trigger'),
- 'configurable' => FALSE,
- 'triggers' => array('any'),
- ),
- );
-}
-
-/**
- * Implements hook_trigger_info().
- */
-function trigger_test_trigger_info() {
- // Register triggers that this module provides. The first is an additional
- // node trigger and the second is our own, which should create a new tab
- // on the trigger assignment page. The last tests long trigger names.
- return array(
- 'node' => array(
- 'node_triggertest' => array(
- 'label' => t('A test trigger is fired'),
- ),
- ),
- 'trigger_test' => array(
- 'trigger_test_triggertest' => array(
- 'label' => t('Another test trigger is fired'),
- ),
- 'trigger_test_we_sweat_it_out_in_the_streets_of_a_runaway_american_dream' => array(
- 'label' => t('A test trigger with a name over 64 characters'),
- ),
- ),
- );
-}
-
-/**
- * Action fired during the "cron run" trigger test.
- */
-function trigger_test_system_cron_action() {
- // Indicate successful execution by setting a persistent variable.
- variable_set('trigger_test_system_cron_action', TRUE);
-}
-
-/**
- * Implement a configurable Drupal action.
- */
-function trigger_test_system_cron_conf_action($object, $context) {
- // Indicate successful execution by incrementing a persistent variable.
- $value = variable_get('trigger_test_system_cron_conf_action', 0) + 1;
- variable_set('trigger_test_system_cron_conf_action', $value);
-}
-
-/**
- * Form for configurable test action.
- */
-function trigger_test_system_cron_conf_action_form($context) {
- if (!isset($context['subject'])) {
- $context['subject'] = '';
- }
- $form['subject'] = array(
- '#type' => 'textfield',
- '#default_value' => $context['subject'],
- );
- return $form;
-}
-
-/**
- * Form submission handler for configurable test action.
- */
-function trigger_test_system_cron_conf_action_submit($form, $form_state) {
- $form_values = $form_state['values'];
- // Process the HTML form to store configuration. The keyed array that
- // we return will be serialized to the database.
- $params = array(
- 'subject' => $form_values['subject'],
- );
- return $params;
-}
-
-/**
- * Action fired during the "taxonomy", "comment", and "user" trigger tests.
- */
-function trigger_test_generic_action($context) {
- // Indicate successful execution by setting a persistent variable.
- variable_set('trigger_test_generic_action', TRUE);
-}
-
-/**
- * Action fired during the additional trigger tests.
- */
-function trigger_test_generic_any_action($context) {
- // Indicate successful execution by setting a persistent variable.
- variable_set('trigger_test_generic_any_action', variable_get('trigger_test_generic_any_action', 0) + 1);
-}
diff --git a/modules/trigger/trigger.admin.inc b/modules/trigger/trigger.admin.inc
deleted file mode 100644
index 5b607c85..00000000
--- a/modules/trigger/trigger.admin.inc
+++ /dev/null
@@ -1,319 +0,0 @@
- $hooks) {
- if ($module == $module_to_display) {
- foreach ($hooks as $hook => $description) {
- $form_id = 'trigger_' . $hook . '_assign_form';
- $build[$form_id] = drupal_get_form($form_id, $module, $hook, $description['label']);
- }
- }
- }
- return $build;
-}
-
-/**
- * Form constructor for confirmation page for removal of an assigned action.
- *
- * @param $module
- * The tab of triggers the user will be directed to after successful
- * removal of the action, or if the confirmation form is cancelled.
- * @param $hook
- * The name of the trigger hook, e.g., 'node_insert'.
- * @param $aid
- * The action ID.
- *
- * @see trigger_unassign_submit()
- * @ingroup forms
- */
-function trigger_unassign($form, $form_state, $module, $hook = NULL, $aid = NULL) {
- if (!isset($hook, $aid)) {
- drupal_goto('admin/structure/trigger');
- }
-
- $form['hook'] = array(
- '#type' => 'value',
- '#value' => $hook,
- );
- $form['module'] = array(
- '#type' => 'value',
- '#value' => $module,
- );
- $form['aid'] = array(
- '#type' => 'value',
- '#value' => $aid,
- );
-
- $action = actions_function_lookup($aid);
- $actions = actions_get_all_actions();
-
- $destination = 'admin/structure/trigger/' . $module;
-
- return confirm_form($form,
- t('Are you sure you want to unassign the action %title?', array('%title' => $actions[$action]['label'])),
- $destination,
- t('You can assign it again later if you wish.'),
- t('Unassign'), t('Cancel')
- );
-}
-
-/**
- * Form submission handler for trigger_unassign().
- */
-function trigger_unassign_submit($form, &$form_state) {
- if ($form_state['values']['confirm'] == 1) {
- $aid = actions_function_lookup($form_state['values']['aid']);
- db_delete('trigger_assignments')
- ->condition('hook', $form_state['values']['hook'])
- ->condition('aid', $aid)
- ->execute();
- drupal_static_reset('trigger_get_assigned_actions');
- $actions = actions_get_all_actions();
- watchdog('actions', 'Action %action has been unassigned.', array('%action' => $actions[$aid]['label']));
- drupal_set_message(t('Action %action has been unassigned.', array('%action' => $actions[$aid]['label'])));
- $form_state['redirect'] = 'admin/structure/trigger/' . $form_state['values']['module'];
- }
- else {
- drupal_goto('admin/structure/trigger');
- }
-}
-
-/**
- * Returns the form for assigning an action to a trigger.
- *
- * @param $module
- * The name of the trigger group, e.g., 'node'.
- * @param $hook
- * The name of the trigger hook, e.g., 'node_insert'.
- * @param $label
- * A plain English description of what this trigger does.
- *
- * @see trigger_assign_form_validate()
- * @see trigger_assign_form_submit()
- * @ingroup forms
- */
-function trigger_assign_form($form, $form_state, $module, $hook, $label) {
- $form['module'] = array(
- '#type' => 'hidden',
- '#value' => $module,
- );
- $form['hook'] = array(
- '#type' => 'hidden',
- '#value' => $hook,
- );
- // All of these forms use the same validate and submit functions.
- $form['#validate'][] = 'trigger_assign_form_validate';
- $form['#submit'][] = 'trigger_assign_form_submit';
-
- $options = array();
- $functions = array();
- // Restrict the options list to actions that declare support for this hook.
- foreach (actions_list() as $func => $metadata) {
- if (isset($metadata['triggers']) && array_intersect(array($hook, 'any'), $metadata['triggers'])) {
- $functions[] = $func;
- }
- }
- foreach (actions_actions_map(actions_get_all_actions()) as $aid => $action) {
- if (in_array($action['callback'], $functions)) {
- $options[$action['type']][$aid] = $action['label'];
- }
- }
-
- $form[$hook] = array(
- '#type' => 'fieldset',
- // !description is correct, since these labels are passed through t() in
- // hook_trigger_info().
- '#title' => t('Trigger: !description', array('!description' => $label)),
- '#theme' => 'trigger_display',
- );
-
- // Retrieve actions that are already assigned to this hook combination.
- $actions = trigger_get_assigned_actions($hook);
- $form[$hook]['assigned']['#type'] = 'value';
- $form[$hook]['assigned']['#value'] = array();
- foreach ($actions as $aid => $info) {
- // If action is defined unassign it, otherwise offer to delete all orphaned
- // actions.
- $hash = drupal_hash_base64($aid, TRUE);
- if (actions_function_lookup($hash)) {
- $form[$hook]['assigned']['#value'][$aid] = array(
- 'label' => $info['label'],
- 'link' => l(t('unassign'), "admin/structure/trigger/unassign/$module/$hook/$hash"),
- );
- }
- else {
- // Link to system_actions_remove_orphans() to do the clean up.
- $form[$hook]['assigned']['#value'][$aid] = array(
- 'label' => $info['label'],
- 'link' => l(t('Remove orphaned actions'), "admin/config/system/actions/orphan"),
- );
- }
- }
-
- $form[$hook]['parent'] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('container-inline')),
- );
- // List possible actions that may be assigned.
- if (count($options) != 0) {
- $form[$hook]['parent']['aid'] = array(
- '#type' => 'select',
- '#title' => t('List of trigger actions when !description', array('!description' => $label)),
- '#title_display' => 'invisible',
- '#options' => $options,
- '#empty_option' => t('Choose an action'),
- );
- $form[$hook]['parent']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Assign')
- );
- }
- else {
- $form[$hook]['none'] = array(
- '#markup' => t('No actions available for this trigger. Add action .', array('@link' => url('admin/config/system/actions/manage')))
- );
- }
- return $form;
-}
-
-/**
- * Form validation handler for trigger_assign_form().
- *
- * Makes sure that the user is not re-assigning an action to an event.
- *
- * @see trigger_assign_form_submit()
- */
-function trigger_assign_form_validate($form, $form_state) {
- $form_values = $form_state['values'];
- if (!empty($form_values['aid'])) {
- $aid = actions_function_lookup($form_values['aid']);
- $aid_exists = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND aid = :aid", array(
- ':hook' => $form_values['hook'],
- ':aid' => $aid,
- ))->fetchField();
- if ($aid_exists) {
- form_set_error($form_values['hook'], t('The action you chose is already assigned to that trigger.'));
- }
- }
-}
-
-/**
- * Form submission handler for trigger_assign_form().
- *
- * @see trigger_assign_form_validate()
- */
-function trigger_assign_form_submit($form, &$form_state) {
- if (!empty($form_state['values']['aid'])) {
- $aid = actions_function_lookup($form_state['values']['aid']);
- $weight = db_query("SELECT MAX(weight) FROM {trigger_assignments} WHERE hook = :hook", array(':hook' => $form_state['values']['hook']))->fetchField();
-
- // Insert the new action.
- db_insert('trigger_assignments')
- ->fields(array(
- 'hook' => $form_state['values']['hook'],
- 'aid' => $aid,
- 'weight' => $weight + 1,
- ))
- ->execute();
-
- // If we are not configuring an action for a "presave" hook and this action
- // changes an object property, then we need to save the object, so the
- // property change will persist.
- $actions = actions_list();
- if (strpos($form_state['values']['hook'], 'presave') === FALSE && isset($actions[$aid]['behavior']) && in_array('changes_property', $actions[$aid]['behavior'])) {
- // Determine the corresponding save action name for this action.
- $save_action = strtok($aid, '_') . '_save_action';
- // If no corresponding save action exists, we need to bail out.
- if (!isset($actions[$save_action])) {
- throw new Exception(t('Missing/undefined save action (%save_aid) for %aid action.', array('%save_aid' => $aid, '%aid' => $aid)));
- }
- // Delete previous save action if it exists, and re-add it using a higher
- // weight.
- $save_action_assigned = db_query("SELECT aid FROM {trigger_assignments} WHERE hook = :hook AND aid = :aid", array(':hook' => $form_state['values']['hook'], ':aid' => $save_action))->fetchField();
-
- if ($save_action_assigned) {
- db_delete('trigger_assignments')
- ->condition('hook', $form_state['values']['hook'])
- ->condition('aid', $save_action)
- ->execute();
- }
- db_insert('trigger_assignments')
- ->fields(array(
- 'hook' => $form_state['values']['hook'],
- 'aid' => $save_action,
- 'weight' => $weight + 2,
- ))
- ->execute();
-
- // If no save action existed before, inform the user about it.
- if (!$save_action_assigned) {
- drupal_set_message(t('The %label action has been appended, which is required to save the property change.', array('%label' => $actions[$save_action]['label'])));
- }
- // Otherwise, just inform about the new weight.
- else {
- drupal_set_message(t('The %label action was moved to save the property change.', array('%label' => $actions[$save_action]['label'])));
- }
- }
- }
- drupal_static_reset('trigger_get_assigned_actions');
-}
-
-/**
- * Returns HTML for the form showing actions assigned to a trigger.
- *
- * @param $variables
- * An associative array containing:
- * - element: The fieldset including all assigned actions.
- *
- * @ingroup themeable
- */
-function theme_trigger_display($variables) {
- $element = $variables['element'];
-
- $header = array();
- $rows = array();
- if (isset($element['assigned']) && count($element['assigned']['#value'])) {
- $header = array(array('data' => t('Name')), array('data' => t('Operation')));
- $rows = array();
- foreach ($element['assigned']['#value'] as $aid => $info) {
- $rows[] = array(
- check_plain($info['label']),
- $info['link']
- );
- }
- }
-
- if (count($rows)) {
- $output = theme('table', array('header' => $header, 'rows' => $rows)) . drupal_render_children($element);
- }
- else {
- $output = drupal_render_children($element);
- }
- return $output;
-}
diff --git a/modules/trigger/trigger.api.php b/modules/trigger/trigger.api.php
deleted file mode 100644
index 839c1d48..00000000
--- a/modules/trigger/trigger.api.php
+++ /dev/null
@@ -1,78 +0,0 @@
- array(
- 'node_presave' => array(
- 'label' => t('When either saving new content or updating existing content'),
- ),
- 'node_insert' => array(
- 'label' => t('After saving new content'),
- ),
- 'node_update' => array(
- 'label' => t('After saving updated content'),
- ),
- 'node_delete' => array(
- 'label' => t('After deleting content'),
- ),
- 'node_view' => array(
- 'label' => t('When content is viewed by an authenticated user'),
- ),
- ),
- );
-}
-
-/**
- * Alter triggers declared by hook_trigger_info().
- *
- * @param $triggers
- * Array of trigger information returned by hook_trigger_info()
- * implementations. Modify this array in place. See hook_trigger_info()
- * for information on what this might contain.
- */
-function hook_trigger_info_alter(&$triggers) {
- $triggers['node']['node_insert']['label'] = t('When content is saved');
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info
deleted file mode 100644
index aa7c18c5..00000000
--- a/modules/trigger/trigger.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = Trigger
-description = Enables actions to be fired on certain system events, such as when new content is created.
-package = Core
-version = VERSION
-core = 7.x
-files[] = trigger.test
-configure = admin/structure/trigger
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/trigger/trigger.install b/modules/trigger/trigger.install
deleted file mode 100644
index 779cd2aa..00000000
--- a/modules/trigger/trigger.install
+++ /dev/null
@@ -1,116 +0,0 @@
- 'Maps trigger to hook and operation assignments from trigger.module.',
- 'fields' => array(
- 'hook' => array(
- 'type' => 'varchar',
- 'length' => 78,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Primary Key: The name of the internal Drupal hook; for example, node_insert.',
- ),
- 'aid' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "Primary Key: Action's {actions}.aid.",
- ),
- 'weight' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of the trigger assignment in relation to other triggers.',
- ),
- ),
- 'primary key' => array('hook', 'aid'),
- 'foreign keys' => array(
- 'action' => array(
- 'table' => 'actions',
- 'columns' => array('aid' => 'aid'),
- ),
- ),
- );
- return $schema;
-}
-
-/**
- * Implements hook_install().
- */
-function trigger_install() {
- // Do initial synchronization of actions in code and the database.
- actions_synchronize();
-}
-
-/**
- * Alter the "hook" field and drop the "op field" of {trigger_assignments}.
- *
- * Increase the length of the "hook" field to 78 characters and adds operation
- * names to the hook names, and drops the "op" field.
- */
-function trigger_update_7000() {
- db_drop_primary_key('trigger_assignments');
- db_change_field('trigger_assignments', 'hook', 'hook', array('type' => 'varchar', 'length' => 78, 'not null' => TRUE, 'default' => '', 'description' => 'Primary Key: The name of the internal Drupal hook; for example, node_insert.'));
-
- $result = db_query("SELECT hook, op, aid FROM {trigger_assignments} WHERE op <> ''");
-
- foreach ($result as $record) {
- db_update('trigger_assignments')
- ->fields(array('hook' => $record->hook . '_' . $record->op))
- ->condition('hook', $record->hook)
- ->condition('op', $record->op)
- ->condition('aid', $record->aid)
- ->execute();
- }
- db_drop_field('trigger_assignments', 'op');
-
- db_add_primary_key('trigger_assignments', array('hook', 'aid'));
-}
-
-/**
- * @addtogroup updates-7.x-extra
- * @{
- */
-
-/**
- * Increase the length of the "hook" field to 78 characters.
- *
- * This is a separate function for those who ran an older version of
- * trigger_update_7000() that did not do this.
- */
-function trigger_update_7001() {
- db_drop_primary_key('trigger_assignments');
- db_change_field('trigger_assignments', 'hook', 'hook', array('type' => 'varchar', 'length' => 78, 'not null' => TRUE, 'default' => '', 'description' => 'Primary Key: The name of the internal Drupal hook; for example, node_insert.', ), array('primary key' => array('hook', 'aid')));
-}
-
-/**
- * Renames nodeapi to node.
- */
-function trigger_update_7002() {
- $result = db_query("SELECT hook, aid FROM {trigger_assignments}");
-
- foreach($result as $record) {
- $new_hook = str_replace('nodeapi', 'node', $record->hook);
- db_update('trigger_assignments')
- ->fields(array('hook' => $new_hook))
- ->condition('hook', $record->hook)
- ->condition('aid', $record->aid)
- ->execute();
- }
-}
-
-/**
- * @} End of "addtogroup updates-7.x-extra".
- */
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
deleted file mode 100644
index aeb1211c..00000000
--- a/modules/trigger/trigger.module
+++ /dev/null
@@ -1,671 +0,0 @@
-' . t('Triggers are events on your site, such as new content being added or a user logging in. The Trigger module associates these triggers with actions (functional tasks), such as unpublishing content containing certain keywords or e-mailing an administrator. The Actions settings page contains a list of existing actions and provides the ability to create and configure advanced actions (actions requiring configuration, such as an e-mail address or a list of banned words).', array('@url' => url('admin/config/system/actions'))) . '';
-
- $module = $matches[1];
- $trigger_info = _trigger_tab_information();
- if (!empty($trigger_info[$module])) {
- $explanation .= '' . t('There is a tab on this page for each module that defines triggers. On this tab you can assign actions to run when triggers from the @module-name module happen.', array('@module-help' => url('admin/help/' . $module), '@module-name' => $trigger_info[$module])) . '
';
- }
-
- return $explanation;
- }
-
- if ($path == 'admin/help#trigger') {
- $output = '';
- $output .= '' . t('About') . ' ';
- $output .= '' . t('The Trigger module provides the ability to cause actions to run when certain triggers take place on your site. Triggers are events, such as new content being added to your site or a user logging in, and actions are tasks, such as unpublishing content or e-mailing an administrator. For more information, see the online handbook entry for Trigger module .', array('@trigger' => 'http://drupal.org/documentation/modules/trigger/')) . '
';
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Configuring triggers and actions') . ' ';
- $output .= '' . t('The combination of actions and triggers can perform many useful tasks, such as e-mailing an administrator if a user account is deleted, or automatically unpublishing comments that contain certain words. To set up a trigger/action combination, first visit the Actions configuration page , where you can either verify that the action you want is already listed, or create a new advanced action. You will need to set up an advanced action if there are configuration options in your trigger/action combination, such as specifying an e-mail address or a list of banned words. After configuring or verifying your action, visit the Triggers configuration page and choose the appropriate tab (Comment, Taxonomy, etc.), where you can assign the action to run when the trigger event occurs.', array('@triggers-page' => url('admin/structure/trigger'), '@actions-page' => url('admin/config/system/actions'))) . ' ';
- $output .= ' ';
- return $output;
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function trigger_menu() {
- $items['admin/structure/trigger'] = array(
- 'title' => 'Triggers',
- 'description' => 'Configure when to execute actions.',
- 'page callback' => 'trigger_assign',
- 'access arguments' => array('administer actions'),
- 'file' => 'trigger.admin.inc',
- );
-
- $trigger_info = _trigger_tab_information();
- foreach ($trigger_info as $module => $module_name) {
- $items["admin/structure/trigger/$module"] = array(
- 'title' => $module_name,
- 'page callback' => 'trigger_assign',
- 'page arguments' => array($module),
- 'access arguments' => array('administer actions'),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'trigger.admin.inc',
- );
- }
-
- $items['admin/structure/trigger/unassign'] = array(
- 'title' => 'Unassign',
- 'description' => 'Unassign an action from a trigger.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('trigger_unassign'),
- // Only accessible if there are any actions that can be unassigned.
- 'access callback' => 'trigger_menu_unassign_access',
- // Only output in the breadcrumb, not in menu trees.
- 'type' => MENU_VISIBLE_IN_BREADCRUMB,
- 'file' => 'trigger.admin.inc',
- );
-
- return $items;
-}
-
-/**
- * Access callback: Determines if triggers can be unassigned.
- *
- * @return bool
- * TRUE if there are triggers that the user can unassign, FALSE otherwise.
- *
- * @see trigger_menu()
- */
-function trigger_menu_unassign_access() {
- if (!user_access('administer actions')) {
- return FALSE;
- }
- $count = db_select('trigger_assignments')
- ->countQuery()
- ->execute()
- ->fetchField();
- return $count > 0;
-}
-
-/**
- * Implements hook_trigger_info().
- *
- * Defines all the triggers that this module implements triggers for.
- */
-function trigger_trigger_info() {
- return array(
- 'node' => array(
- 'node_presave' => array(
- 'label' => t('When either saving new content or updating existing content'),
- ),
- 'node_insert' => array(
- 'label' => t('After saving new content'),
- ),
- 'node_update' => array(
- 'label' => t('After saving updated content'),
- ),
- 'node_delete' => array(
- 'label' => t('After deleting content'),
- ),
- 'node_view' => array(
- 'label' => t('When content is viewed by an authenticated user'),
- ),
- ),
- 'comment' => array(
- 'comment_presave' => array(
- 'label' => t('When either saving a new comment or updating an existing comment'),
- ),
- 'comment_insert' => array(
- 'label' => t('After saving a new comment'),
- ),
- 'comment_update' => array(
- 'label' => t('After saving an updated comment'),
- ),
- 'comment_delete' => array(
- 'label' => t('After deleting a comment'),
- ),
- 'comment_view' => array(
- 'label' => t('When a comment is being viewed by an authenticated user'),
- ),
- ),
- 'taxonomy' => array(
- 'taxonomy_term_insert' => array(
- 'label' => t('After saving a new term to the database'),
- ),
- 'taxonomy_term_update' => array(
- 'label' => t('After saving an updated term to the database'),
- ),
- 'taxonomy_term_delete' => array(
- 'label' => t('After deleting a term'),
- ),
- ),
- 'system' => array(
- 'cron' => array(
- 'label' => t('When cron runs'),
- ),
- ),
- 'user' => array(
- 'user_insert' => array(
- 'label' => t('After creating a new user account'),
- ),
- 'user_update' => array(
- 'label' => t('After updating a user account'),
- ),
- 'user_delete' => array(
- 'label' => t('After a user has been deleted'),
- ),
- 'user_login' => array(
- 'label' => t('After a user has logged in'),
- ),
- 'user_logout' => array(
- 'label' => t('After a user has logged out'),
- ),
- 'user_view' => array(
- 'label' => t("When a user's profile is being viewed"),
- ),
- ),
- );
- }
-
-/**
- * Gets the action IDs of actions to be executed for a hook.
- *
- * @param $hook
- * The name of the hook being fired.
- *
- * @return
- * An array whose keys are action IDs that the user has associated with
- * this trigger, and whose values are arrays containing the action type and
- * label.
- */
-function trigger_get_assigned_actions($hook) {
- $actions = &drupal_static(__FUNCTION__, array());
- if (!isset($actions[$hook])) {
- $actions[$hook] = db_query("SELECT ta.aid, a.type, a.label FROM {trigger_assignments} ta LEFT JOIN {actions} a ON ta.aid = a.aid WHERE ta.hook = :hook ORDER BY ta.weight", array(
- ':hook' => $hook,
- ))->fetchAllAssoc('aid', PDO::FETCH_ASSOC);
- }
- return $actions[$hook];
-}
-
-/**
- * Implements hook_theme().
- */
-function trigger_theme() {
- return array(
- 'trigger_display' => array(
- 'render element' => 'element',
- 'file' => 'trigger.admin.inc',
- ),
- );
-}
-
-/**
- * Implements hook_forms().
- *
- * We re-use code by using the same assignment form definition for each hook.
- */
-function trigger_forms() {
- $trigger_info = _trigger_get_all_info();
- $forms = array();
- foreach ($trigger_info as $module => $hooks) {
- foreach ($hooks as $hook => $description) {
- $forms['trigger_' . $hook . '_assign_form'] = array('callback' => 'trigger_assign_form');
- }
- }
-
- return $forms;
-}
-
-/**
- * Loads associated objects for node triggers.
- *
- * When an action is called in a context that does not match its type, the
- * object that the action expects must be retrieved. For example, when an action
- * that works on users is called during a node hook implementation, the user
- * object is not available since the node hook call doesn't pass it. So here we
- * load the object the action expects.
- *
- * @param $type
- * The type of action that is about to be called.
- * @param $node
- * The node that was passed via the node hook.
- *
- * @return
- * The object expected by the action that is about to be called.
- */
-function _trigger_normalize_node_context($type, $node) {
- // Note that comment-type actions are not supported in node contexts,
- // because we wouldn't know which comment to choose.
- switch ($type) {
- // An action that works on users is being called in a node context.
- // Load the user object of the node's author.
- case 'user':
- return user_load($node->uid);
- }
-}
-
-/**
- * Calls action functions for node triggers.
- *
- * @param $node
- * Node object.
- * @param $hook
- * Hook to trigger.
- * @param $a3
- * Additional argument to action function.
- * @param $a4
- * Additional argument to action function.
- */
-function _trigger_node($node, $hook, $a3 = NULL, $a4 = NULL) {
- // Keep objects for reuse so that changes actions make to objects can persist.
- static $objects;
- // Prevent recursion by tracking which operations have already been called.
- static $recursion;
-
- $aids = trigger_get_assigned_actions($hook);
- if (!$aids) {
- return;
- }
-
- if (isset($recursion[$hook])) {
- return;
- }
- $recursion[$hook] = TRUE;
-
- $context = array(
- 'group' => 'node',
- 'hook' => $hook,
- );
-
- // We need to get the expected object if the action's type is not 'node'.
- // We keep the object in $objects so we can reuse it if we have multiple actions
- // that make changes to an object.
- foreach ($aids as $aid => $info) {
- $type = $info['type'];
- if ($type != 'node') {
- if (!isset($objects[$type])) {
- $objects[$type] = _trigger_normalize_node_context($type, $node);
- }
- // Since we know about the node, we pass that info along to the action.
- $context['node'] = $node;
- $result = actions_do($aid, $objects[$type], $context, $a3, $a4);
- }
- else {
- actions_do($aid, $node, $context, $a3, $a4);
- }
- }
-
- unset($recursion[$hook]);
-}
-
-/**
- * Implements hook_node_view().
- */
-function trigger_node_view($node, $view_mode) {
- _trigger_node($node, 'node_view', $view_mode);
-}
-
-/**
- * Implements hook_node_update().
- */
-function trigger_node_update($node) {
- _trigger_node($node, 'node_update');
-}
-
-/**
- * Implements hook_node_presave().
- */
-function trigger_node_presave($node) {
- _trigger_node($node, 'node_presave');
-}
-
-/**
- * Implements hook_node_insert().
- */
-function trigger_node_insert($node) {
- _trigger_node($node, 'node_insert');
-}
-
-/**
- * Implements hook_node_delete().
- */
-function trigger_node_delete($node) {
- _trigger_node($node, 'node_delete');
-}
-
-/**
- * Loads associated objects for comment triggers.
- *
- * When an action is called in a context that does not match its type, the
- * object that the action expects must be retrieved. For example, when an action
- * that works on nodes is called during the comment hook, the node object is not
- * available since the comment hook doesn't pass it. So here we load the object
- * the action expects.
- *
- * @param $type
- * The type of action that is about to be called.
- * @param $comment
- * The comment that was passed via the comment hook.
- *
- * @return
- * The object expected by the action that is about to be called.
- */
-function _trigger_normalize_comment_context($type, $comment) {
- switch ($type) {
- // An action that works with nodes is being called in a comment context.
- case 'node':
- return node_load(is_array($comment) ? $comment['nid'] : $comment->nid);
-
- // An action that works on users is being called in a comment context.
- case 'user':
- return user_load(is_array($comment) ? $comment['uid'] : $comment->uid);
- }
-}
-
-/**
- * Implements hook_comment_presave().
- */
-function trigger_comment_presave($comment) {
- _trigger_comment($comment, 'comment_presave');
-}
-
-/**
- * Implements hook_comment_insert().
- */
-function trigger_comment_insert($comment) {
- _trigger_comment($comment, 'comment_insert');
-}
-
-/**
- * Implements hook_comment_update().
- */
-function trigger_comment_update($comment) {
- _trigger_comment($comment, 'comment_update');
-}
-
-/**
- * Implements hook_comment_delete().
- */
-function trigger_comment_delete($comment) {
- _trigger_comment($comment, 'comment_delete');
-}
-
-/**
- * Implements hook_comment_view().
- */
-function trigger_comment_view($comment) {
- _trigger_comment($comment, 'comment_view');
-}
-
-/**
- * Calls action functions for comment triggers.
- *
- * @param $a1
- * Comment object or array of form values.
- * @param $hook
- * Hook to trigger.
- */
-function _trigger_comment($a1, $hook) {
- // Keep objects for reuse so that changes actions make to objects can persist.
- static $objects;
- $aids = trigger_get_assigned_actions($hook);
- $context = array(
- 'group' => 'comment',
- 'hook' => $hook,
- );
- // We need to get the expected object if the action's type is not 'comment'.
- // We keep the object in $objects so we can reuse it if we have multiple
- // actions that make changes to an object.
- foreach ($aids as $aid => $info) {
- $type = $info['type'];
- if ($type != 'comment') {
- if (!isset($objects[$type])) {
- $objects[$type] = _trigger_normalize_comment_context($type, $a1);
- }
- // Since we know about the comment, we pass it along to the action
- // in case it wants to peek at it.
- $context['comment'] = (object) $a1;
- actions_do($aid, $objects[$type], $context);
- }
- else {
- actions_do($aid, $a1, $context);
- }
- }
-}
-
-/**
- * Implements hook_cron().
- */
-function trigger_cron() {
- $aids = trigger_get_assigned_actions('cron');
- $context = array(
- 'group' => 'cron',
- 'hook' => 'cron',
- );
- // Cron does not act on any specific object.
- $object = NULL;
- actions_do(array_keys($aids), $object, $context);
-}
-
-/**
- * Loads associated objects for user triggers.
- *
- * When an action is called in a context that does not match its type, the
- * object that the action expects must be retrieved. For example, when an action
- * that works on nodes is called during the user hook, the node object is not
- * available since the user hook doesn't pass it. So here we load the object the
- * action expects.
- *
- * @param $type
- * The type of action that is about to be called.
- * @param $account
- * The account object that was passed via the user hook.
- *
- * @return
- * The object expected by the action that is about to be called.
- */
-function _trigger_normalize_user_context($type, $account) {
- // Note that comment-type actions are not supported in user contexts,
- // because we wouldn't know which comment to choose.
- switch ($type) {
- // An action that works with nodes is being called in a user context.
- // If a single node is being viewed, return the node.
- case 'node':
- // If we are viewing an individual node, return the node.
- if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == NULL) {
- return node_load(array('nid' => arg(1)));
- }
- break;
- }
-}
-
-/**
- * Implements hook_user_login().
- */
-function trigger_user_login(&$edit, $account, $category) {
- _trigger_user('user_login', $edit, $account, $category);
-}
-
-/**
- * Implements hook_user_logout().
- */
-function trigger_user_logout($account) {
- $edit = array();
- _trigger_user('user_logout', $edit, $account);
-}
-
-/**
- * Implements hook_user_insert().
- */
-function trigger_user_insert(&$edit, $account, $category) {
- _trigger_user('user_insert', $edit, $account, $category);
-}
-
-/**
- * Implements hook_user_update().
- */
-function trigger_user_update(&$edit, $account, $category) {
- _trigger_user('user_update', $edit, $account, $category);
-}
-
-/**
- * Implements hook_user_cancel().
- */
-function trigger_user_cancel($edit, $account, $method) {
- switch ($method) {
- case 'user_cancel_reassign':
- _trigger_user('user_delete', $edit, $account, $method);
- break;
- }
-}
-
-/**
- * Implements hook_user_delete().
- */
-function trigger_user_delete($account) {
- $edit = array();
- _trigger_user('user_delete', $edit, $account, NULL);
-}
-
-/**
- * Implements hook_user_view().
- */
-function trigger_user_view($account) {
- $edit = NULL;
- _trigger_user('user_view', $edit, $account, NULL);
-}
-
-/**
- * Calls action functions for user triggers.
- *
- * @param $hook
- * The hook that called this function.
- * @param $edit
- * Edit variable passed in to the hook or empty array if not needed.
- * @param $account
- * Account variable passed in to the hook.
- * @param $method
- * Method variable passed in to the hook or NULL if not needed.
- */
-function _trigger_user($hook, &$edit, $account, $category = NULL) {
- // Keep objects for reuse so that changes actions make to objects can persist.
- static $objects;
- $aids = trigger_get_assigned_actions($hook);
- $context = array(
- 'group' => 'user',
- 'hook' => $hook,
- 'form_values' => &$edit,
- );
- foreach ($aids as $aid => $info) {
- $type = $info['type'];
- if ($type != 'user') {
- if (!isset($objects[$type])) {
- $objects[$type] = _trigger_normalize_user_context($type, $account);
- }
- $context['user'] = $account;
- actions_do($aid, $objects[$type], $context);
- }
- else {
- actions_do($aid, $account, $context, $category);
- }
- }
-}
-
-/**
- * Calls action functions for taxonomy triggers.
- *
- * @param $hook
- * Hook to trigger actions for taxonomy_term_insert(),
- * taxonomy_term_update(), and taxonomy_term_delete().
- * @param $array
- * Item on which operation is being performed, either a term or
- * form values.
- */
-function _trigger_taxonomy($hook, $array) {
- $aids = trigger_get_assigned_actions($hook);
- $context = array(
- 'group' => 'taxonomy',
- 'hook' => $hook
- );
- actions_do(array_keys($aids), (object) $array, $context);
-}
-
-/**
- * Implements hook_taxonomy_term_insert().
- */
-function trigger_taxonomy_term_insert($term) {
- _trigger_taxonomy('taxonomy_term_insert', (array) $term);
-}
-
-/**
- * Implements hook_taxonomy_term_update().
- */
-function trigger_taxonomy_term_update($term) {
- _trigger_taxonomy('taxonomy_term_update', (array) $term);
-}
-
-/**
- * Implements hook_taxonomy_term_delete().
- */
-function trigger_taxonomy_term_delete($term) {
- _trigger_taxonomy('taxonomy_term_delete', (array) $term);
-}
-
-/**
- * Implements hook_actions_delete().
- *
- * Removes all trigger entries for the given action, when an action is deleted.
- */
-function trigger_actions_delete($aid) {
- db_delete('trigger_assignments')
- ->condition('aid', $aid)
- ->execute();
- drupal_static_reset('trigger_get_assigned_actions');
-}
-
-/**
- * Retrieves and caches information from hook_trigger_info() implementations.
- *
- * @return
- * Array of all triggers.
- */
-function _trigger_get_all_info() {
- $triggers = &drupal_static(__FUNCTION__);
-
- if (!isset($triggers)) {
- $triggers = module_invoke_all('trigger_info');
- drupal_alter('trigger_info', $triggers);
- }
-
- return $triggers;
-}
-
-/**
- * Gathers information about tabs on the triggers administration screen.
- *
- * @return
- * Array of modules that have triggers, with the keys being the
- * machine-readable name of the module, and the values being the
- * human-readable name of the module.
- */
-function _trigger_tab_information() {
- // Gather information about all triggers and modules.
- $trigger_info = _trigger_get_all_info();
- $modules = system_get_info('module');
- $modules = array_intersect_key($modules, $trigger_info);
-
- $return_info = array();
- foreach ($modules as $name => $info) {
- $return_info[$name] = $info['name'];
- }
-
- return $return_info;
-}
diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test
deleted file mode 100644
index 9e5f1142..00000000
--- a/modules/trigger/trigger.test
+++ /dev/null
@@ -1,771 +0,0 @@
-drupalPost("admin/config/system/actions/configure/$hash", $edit, t('Save'));
- $this->assertText(t('The action has been successfully saved.'));
-
- // Now we have to find out the action ID of what we created.
- return db_query('SELECT aid FROM {actions} WHERE callback = :callback AND label = :label', array(':callback' => $action, ':label' => $edit['actions_label']))->fetchField();
- }
-
-}
-
-/**
- * Provides tests for node triggers.
- */
-class TriggerContentTestCase extends TriggerWebTestCase {
- var $_cleanup_roles = array();
- var $_cleanup_users = array();
-
- public static function getInfo() {
- return array(
- 'name' => 'Trigger content (node) actions',
- 'description' => 'Perform various tests with content actions.',
- 'group' => 'Trigger',
- );
- }
-
- function setUp() {
- parent::setUp('trigger', 'trigger_test');
- }
-
- /**
- * Tests several content-oriented trigger issues.
- *
- * These are in one function to assure they happen in the right order.
- */
- function testActionsContent() {
- global $user;
- $content_actions = array('node_publish_action', 'node_unpublish_action', 'node_make_sticky_action', 'node_make_unsticky_action', 'node_promote_action', 'node_unpromote_action');
-
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $web_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer nodes'));
- foreach ($content_actions as $action) {
- $hash = drupal_hash_base64($action);
- $info = $this->actionInfo($action);
-
- // Assign an action to a trigger, then pull the trigger, and make sure
- // the actions fire.
- $this->drupalLogin($test_user);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-presave-assign-form');
- // Create an unpublished node.
- $this->drupalLogin($web_user);
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = '!SimpleTest test node! ' . $this->randomName(10);
- $edit["body[$langcode][0][value]"] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
- $edit[$info['property']] = !$info['expected'];
- $this->drupalPost('node/add/page', $edit, t('Save'));
- // Make sure the text we want appears.
- $this->assertRaw(t('!post %title has been created.', array('!post' => 'Basic page', '%title' => $edit["title"])), 'Make sure the Basic page has actually been created');
- // Action should have been fired.
- $loaded_node = $this->drupalGetNodeByTitle($edit["title"]);
- $this->assertTrue($loaded_node->$info['property'] == $info['expected'], format_string('Make sure the @action action fired.', array('@action' => $info['name'])));
- // Leave action assigned for next test
-
- // There should be an error when the action is assigned to the trigger
- // twice.
- $this->drupalLogin($test_user);
- // This action already assigned in this test.
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-presave-assign-form');
- $this->assertRaw(t('The action you chose is already assigned to that trigger.'), 'Check to make sure an error occurs when assigning an action to a trigger twice.');
-
- // The action should be able to be unassigned from a trigger.
- $this->drupalPost('admin/structure/trigger/unassign/node/node_presave/' . $hash, array(), t('Unassign'));
- $this->assertRaw(t('Action %action has been unassigned.', array('%action' => ucfirst($info['name']))), format_string('Check to make sure the @action action can be unassigned from the trigger.', array('@action' => $info['name'])));
- $assigned = db_query("SELECT COUNT(*) FROM {trigger_assignments} WHERE aid IN (:keys)", array(':keys' => $content_actions))->fetchField();
- $this->assertFalse($assigned, 'Check to make sure unassign worked properly at the database level.');
- }
- }
-
- /**
- * Tests multiple node actions.
- *
- * Verifies that node actions are fired for each node individually, if acting
- * on multiple nodes.
- */
- function testActionContentMultiple() {
- // Assign an action to the node save/update trigger.
- $test_user = $this->drupalCreateUser(array('administer actions', 'administer nodes', 'create page content', 'access administration pages', 'access content overview'));
- $this->drupalLogin($test_user);
- $nodes = array();
-
- for ($index = 0; $index < 3; $index++) {
- $nodes[] = $this->drupalCreateNode(array('type' => 'page'));
- }
-
- $action_id = 'trigger_test_generic_any_action';
- $hash = drupal_hash_base64($action_id);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-update-assign-form');
-
- $edit = array(
- 'operation' => 'unpublish',
- 'nodes[' . $nodes[0]->nid . ']' => TRUE,
- 'nodes[' . $nodes[1]->nid . ']' => TRUE,
- );
- $this->drupalPost('admin/content', $edit, t('Update'));
- $count = variable_get('trigger_test_generic_any_action', 0);
- $this->assertTrue($count == 2, format_string('Action was triggered 2 times. Actual: %count', array('%count' => $count)));
- }
-
- /**
- * Returns some info about each of the content actions.
- *
- * This is helper function for testActionsContent().
- *
- * @param $action
- * The name of the action to return info about.
- *
- * @return
- * An associative array of info about the action.
- */
- function actionInfo($action) {
- $info = array(
- 'node_publish_action' => array(
- 'property' => 'status',
- 'expected' => 1,
- 'name' => t('publish content'),
- ),
- 'node_unpublish_action' => array(
- 'property' => 'status',
- 'expected' => 0,
- 'name' => t('unpublish content'),
- ),
- 'node_make_sticky_action' => array(
- 'property' => 'sticky',
- 'expected' => 1,
- 'name' => t('make content sticky'),
- ),
- 'node_make_unsticky_action' => array(
- 'property' => 'sticky',
- 'expected' => 0,
- 'name' => t('make content unsticky'),
- ),
- 'node_promote_action' => array(
- 'property' => 'promote',
- 'expected' => 1,
- 'name' => t('promote content to front page'),
- ),
- 'node_unpromote_action' => array(
- 'property' => 'promote',
- 'expected' => 0,
- 'name' => t('remove content from front page'),
- ),
- );
- return $info[$action];
- }
-}
-
-/**
- * Tests cron trigger.
- */
-class TriggerCronTestCase extends TriggerWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Trigger cron (system) actions',
- 'description' => 'Perform various tests with cron trigger.',
- 'group' => 'Trigger',
- );
- }
-
- function setUp() {
- parent::setUp('trigger', 'trigger_test');
- }
-
- /**
- * Tests assigning multiple actions to the cron trigger.
- *
- * This test ensures that both simple and multiple complex actions
- * succeed properly. This is done in the cron trigger test because
- * cron allows passing multiple actions in at once.
- */
- function testActionsCron() {
- // Create an administrative user.
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($test_user);
-
- // Assign a non-configurable action to the cron run trigger.
- $edit = array('aid' => drupal_hash_base64('trigger_test_system_cron_action'));
- $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
-
- // Assign a configurable action to the cron trigger.
- $action_label = $this->randomName();
- $edit = array(
- 'actions_label' => $action_label,
- 'subject' => $action_label,
- );
- $aid = $this->configureAdvancedAction('trigger_test_system_cron_conf_action', $edit);
- // $aid is likely 3 but if we add more uses for the sequences table in
- // core it might break, so it is easier to get the value from the database.
- $edit = array('aid' => drupal_hash_base64($aid));
- $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
-
- // Add a second configurable action to the cron trigger.
- $action_label = $this->randomName();
- $edit = array(
- 'actions_label' => $action_label,
- 'subject' => $action_label,
- );
- $aid = $this->configureAdvancedAction('trigger_test_system_cron_conf_action', $edit);
- $edit = array('aid' => drupal_hash_base64($aid));
- $this->drupalPost('admin/structure/trigger/system', $edit, t('Assign'), array(), array(), 'trigger-cron-assign-form');
-
- // Force a cron run.
- $this->cronRun();
-
- // Make sure the non-configurable action has fired.
- $action_run = variable_get('trigger_test_system_cron_action', FALSE);
- $this->assertTrue($action_run, 'Check that the cron run triggered the test action.');
-
- // Make sure that both configurable actions have fired.
- $action_run = variable_get('trigger_test_system_cron_conf_action', 0) == 2;
- $this->assertTrue($action_run, 'Check that the cron run triggered both complex actions.');
- }
-}
-
-/**
- * Provides a base class with trigger assignments and test comparisons.
- */
-class TriggerActionTestCase extends TriggerWebTestCase {
-
- function setUp() {
- parent::setUp('trigger');
- }
-
- /**
- * Creates a message with tokens.
- *
- * @param $trigger
- *
- * @return
- * A message with embedded tokens.
- */
- function generateMessageWithTokens($trigger) {
- // Note that subject is limited to 254 characters in action configuration.
- $message = t('Action was triggered by trigger @trigger user:name=[user:name] user:uid=[user:uid] user:mail=[user:mail] user:url=[user:url] user:edit-url=[user:edit-url] user:created=[user:created]',
- array('@trigger' => $trigger));
- return trim($message);
- }
-
- /**
- * Generates a comparison message to match the pre-token-replaced message.
- *
- * @param $trigger
- * Trigger, like 'user_login'.
- * @param $account
- * Associated user account.
- *
- * @return
- * The token-replaced equivalent message. This does not use token
- * functionality.
- *
- * @see generateMessageWithTokens()
- */
- function generateTokenExpandedComparison($trigger, $account) {
- // Note that user:last-login was omitted because it changes and can't
- // be properly verified.
- $message = t('Action was triggered by trigger @trigger user:name=@username user:uid=@uid user:mail=@mail user:url=@user_url user:edit-url=@user_edit_url user:created=@user_created',
- array(
- '@trigger' => $trigger,
- '@username' => $account->name,
- '@uid' => !empty($account->uid) ? $account->uid : t('not yet assigned'),
- '@mail' => $account->mail,
- '@user_url' => !empty($account->uid) ? url("user/$account->uid", array('absolute' => TRUE)) : t('not yet assigned'),
- '@user_edit_url' => !empty($account->uid) ? url("user/$account->uid/edit", array('absolute' => TRUE)) : t('not yet assigned'),
- '@user_created' => isset($account->created) ? format_date($account->created, 'medium') : t('not yet created'),
- )
- );
- return trim($message);
- }
-
-
- /**
- * Assigns a simple (non-configurable) action to a trigger.
- *
- * @param $trigger
- * The trigger to assign to, like 'user_login'.
- * @param $action
- * The simple action to be assigned, like 'comment_insert'.
- */
- function assignSimpleAction($trigger, $action) {
- $form_name = "trigger_{$trigger}_assign_form";
- $form_html_id = strtr($form_name, '_', '-');
- $edit = array('aid' => drupal_hash_base64($action));
- $trigger_type = preg_replace('/_.*/', '', $trigger);
- $this->drupalPost("admin/structure/trigger/$trigger_type", $edit, t('Assign'), array(), array(), $form_html_id);
- $actions = trigger_get_assigned_actions($trigger);
- $this->assertTrue(!empty($actions[$action]), format_string('Simple action @action assigned to trigger @trigger', array('@action' => $action, '@trigger' => $trigger)));
- }
-
- /**
- * Assigns a system message action to the passed-in trigger.
- *
- * @param $trigger
- * For example, 'user_login'
- */
- function assignSystemMessageAction($trigger) {
- $form_name = "trigger_{$trigger}_assign_form";
- $form_html_id = strtr($form_name, '_', '-');
- // Assign a configurable action 'System message' to the passed trigger.
- $action_edit = array(
- 'actions_label' => $trigger . "_system_message_action_" . $this->randomName(16),
- 'message' => $this->generateMessageWithTokens($trigger),
- );
-
- // Configure an advanced action that we can assign.
- $aid = $this->configureAdvancedAction('system_message_action', $action_edit);
-
- $edit = array('aid' => drupal_hash_base64($aid));
- $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), $form_html_id);
- drupal_static_reset('trigger_get_asssigned_actions');
- }
-
-
- /**
- * Assigns a system_send_email_action to the passed-in trigger.
- *
- * @param $trigger
- * For example, 'user_login'
- */
- function assignSystemEmailAction($trigger) {
- $form_name = "trigger_{$trigger}_assign_form";
- $form_html_id = strtr($form_name, '_', '-');
-
- $message = $this->generateMessageWithTokens($trigger);
- // Assign a configurable action 'System message' to the passed trigger.
- $action_edit = array(
- // 'actions_label' => $trigger . "_system_send_message_action_" . $this->randomName(16),
- 'actions_label' => $trigger . "_system_send_email_action",
- 'recipient' => '[user:mail]',
- 'subject' => $message,
- 'message' => $message,
- );
-
- // Configure an advanced action that we can assign.
- $aid = $this->configureAdvancedAction('system_send_email_action', $action_edit);
-
- $edit = array('aid' => drupal_hash_base64($aid));
- $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), $form_html_id);
- drupal_static_reset('trigger_get_assigned_actions');
- }
-
- /**
- * Asserts correct token replacement in both system message and email.
- *
- * @param $trigger
- * A trigger like 'user_login'.
- * @param $account
- * The user account which triggered the action.
- * @param $email_depth
- * Number of emails to scan, starting with most recent.
- */
- function assertSystemMessageAndEmailTokenReplacement($trigger, $account, $email_depth = 1) {
- $this->assertSystemMessageTokenReplacement($trigger, $account);
- $this->assertSystemEmailTokenReplacement($trigger, $account, $email_depth);
- }
-
- /**
- * Asserts correct token replacement for the given trigger and account.
- *
- * @param $trigger
- * A trigger like 'user_login'.
- * @param $account
- * The user account which triggered the action.
- */
- function assertSystemMessageTokenReplacement($trigger, $account) {
- $expected = $this->generateTokenExpandedComparison($trigger, $account);
- $this->assertText($expected,
- format_string('Expected system message to contain token-replaced text "@expected" found in configured system message action', array('@expected' => $expected )) );
- }
-
-
- /**
- * Asserts correct token replacement for the given trigger and account.
- *
- * @param $trigger
- * A trigger like 'user_login'.
- * @param $account
- * The user account which triggered the action.
- * @param $email_depth
- * Number of emails to scan, starting with most recent.
- */
- function assertSystemEmailTokenReplacement($trigger, $account, $email_depth = 1) {
- $this->verboseEmail($email_depth);
- $expected = $this->generateTokenExpandedComparison($trigger, $account);
- $this->assertMailString('subject', $expected, $email_depth);
- $this->assertMailString('body', $expected, $email_depth);
- $this->assertMail('to', $account->mail, 'Mail sent to correct destination');
- }
-}
-
-/**
- * Tests token substitution in trigger actions.
- *
- * This tests nearly every permutation of user triggers with system actions
- * and checks the token replacement.
- */
-class TriggerUserTokenTestCase extends TriggerActionTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Test user triggers',
- 'description' => 'Test user triggers and system actions with token replacement.',
- 'group' => 'Trigger',
- );
- }
-
-
- /**
- * Tests a variety of token replacements in actions.
- */
- function testUserTriggerTokenReplacement() {
- $test_user = $this->drupalCreateUser(array('administer actions', 'administer users', 'change own username', 'access user profiles'));
- $this->drupalLogin($test_user);
-
- $triggers = array('user_login', 'user_insert', 'user_update', 'user_delete', 'user_logout', 'user_view');
- foreach ($triggers as $trigger) {
- $this->assignSystemMessageAction($trigger);
- $this->assignSystemEmailAction($trigger);
- }
-
- $this->drupalLogout();
- $this->assertSystemEmailTokenReplacement('user_logout', $test_user);
-
- $this->drupalLogin($test_user);
- $this->assertSystemMessageAndEmailTokenReplacement('user_login', $test_user, 2);
- $this->assertSystemMessageAndEmailTokenReplacement('user_view', $test_user, 2);
-
- $this->drupalPost("user/{$test_user->uid}/edit", array('name' => $test_user->name . '_changed'), t('Save'));
- $test_user->name .= '_changed'; // Since we just changed it.
- $this->assertSystemMessageAndEmailTokenReplacement('user_update', $test_user, 2);
-
- $this->drupalGet('user');
- $this->assertSystemMessageAndEmailTokenReplacement('user_view', $test_user);
-
- $new_user = $this->drupalCreateUser(array('administer actions', 'administer users', 'cancel account', 'access administration pages'));
- $this->assertSystemEmailTokenReplacement('user_insert', $new_user);
-
- $this->drupalLogin($new_user);
- $user_to_delete = $this->drupalCreateUser(array('access content'));
- variable_set('user_cancel_method', 'user_cancel_delete');
-
- $this->drupalPost("user/{$user_to_delete->uid}/cancel", array(), t('Cancel account'));
- $this->assertSystemMessageAndEmailTokenReplacement('user_delete', $user_to_delete);
- }
-
-
-}
-
-/**
- * Tests token substitution in trigger actions.
- *
- * This tests nearly every permutation of user triggers with system actions
- * and checks the token replacement.
- */
-class TriggerUserActionTestCase extends TriggerActionTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Test user actions',
- 'description' => 'Test user actions.',
- 'group' => 'Trigger',
- );
- }
-
- /**
- * Tests user action assignment and execution.
- */
- function testUserActionAssignmentExecution() {
- $test_user = $this->drupalCreateUser(array('administer actions', 'create article content', 'access comments', 'administer comments', 'skip comment approval', 'edit own comments'));
- $this->drupalLogin($test_user);
-
- $triggers = array('comment_presave', 'comment_insert', 'comment_update');
- // system_block_ip_action is difficult to test without ruining the test.
- $actions = array('user_block_user_action');
- foreach ($triggers as $trigger) {
- foreach ($actions as $action) {
- $this->assignSimpleAction($trigger, $action);
- }
- }
-
- $node = $this->drupalCreateNode(array('type' => 'article'));
- $this->drupalPost("node/{$node->nid}", array('comment_body[und][0][value]' => t("my comment"), 'subject' => t("my comment subject")), t('Save'));
- // Posting a comment should have blocked this user.
- $account = user_load($test_user->uid, TRUE);
- $this->assertTrue($account->status == 0, 'Account is blocked');
- $comment_author_uid = $account->uid;
- // Now rehabilitate the comment author so it can be be blocked again when
- // the comment is updated.
- user_save($account, array('status' => TRUE));
-
- $test_user = $this->drupalCreateUser(array('administer actions', 'create article content', 'access comments', 'administer comments', 'skip comment approval', 'edit own comments'));
- $this->drupalLogin($test_user);
-
- // Our original comment will have been comment 1.
- $this->drupalPost("comment/1/edit", array('comment_body[und][0][value]' => t("my comment, updated"), 'subject' => t("my comment subject")), t('Save'));
- $comment_author_account = user_load($comment_author_uid, TRUE);
- $this->assertTrue($comment_author_account->status == 0, format_string('Comment author account (uid=@uid) is blocked after update to comment', array('@uid' => $comment_author_uid)));
-
- // Verify that the comment was updated.
- $test_user = $this->drupalCreateUser(array('administer actions', 'create article content', 'access comments', 'administer comments', 'skip comment approval', 'edit own comments'));
- $this->drupalLogin($test_user);
-
- $this->drupalGet("node/$node->nid");
- $this->assertText(t("my comment, updated"));
- $this->verboseEmail();
- }
-}
-
-/**
- * Tests other triggers.
- */
-class TriggerOtherTestCase extends TriggerWebTestCase {
- var $_cleanup_roles = array();
- var $_cleanup_users = array();
-
- public static function getInfo() {
- return array(
- 'name' => 'Trigger other actions',
- 'description' => 'Test triggering of user, comment, taxonomy actions.',
- 'group' => 'Trigger',
- );
- }
-
- function setUp() {
- parent::setUp('trigger', 'trigger_test', 'contact');
- }
-
- /**
- * Tests triggering on user create and user login.
- */
- function testActionsUser() {
- // Assign an action to the create user trigger.
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($test_user);
- $action_id = 'trigger_test_generic_action';
- $hash = drupal_hash_base64($action_id);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-insert-assign-form');
-
- // Set action variable to FALSE.
- variable_set($action_id, FALSE);
-
- // Create an unblocked user
- $web_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($web_user);
- $name = $this->randomName();
- $pass = user_password();
- $edit = array();
- $edit['name'] = $name;
- $edit['mail'] = $name . '@example.com';
- $edit['pass[pass1]'] = $pass;
- $edit['pass[pass2]'] = $pass;
- $edit['status'] = 1;
- $this->drupalPost('admin/people/create', $edit, t('Create new account'));
-
- // Verify that the action variable has been set.
- $this->assertTrue(variable_get($action_id, FALSE), 'Check that creating a user triggered the test action.');
-
- // Reset the action variable.
- variable_set($action_id, FALSE);
-
- $this->drupalLogin($test_user);
- // Assign a configurable action 'System message' to the user_login trigger.
- $action_edit = array(
- 'actions_label' => $this->randomName(16),
- 'message' => t("You have logged in:") . $this->randomName(16),
- );
-
- // Configure an advanced action that we can assign.
- $aid = $this->configureAdvancedAction('system_message_action', $action_edit);
- $edit = array('aid' => drupal_hash_base64($aid));
- $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-login-assign-form');
-
- // Verify that the action has been assigned to the correct hook.
- $actions = trigger_get_assigned_actions('user_login');
- $this->assertEqual(1, count($actions), 'One Action assigned to the hook');
- $this->assertEqual($actions[$aid]['label'], $action_edit['actions_label'], 'Correct action label found.');
-
- // User should get the configured message at login.
- $contact_user = $this->drupalCreateUser(array('access site-wide contact form'));;
- $this->drupalLogin($contact_user);
- $this->assertText($action_edit['message']);
- }
-
- /**
- * Tests triggering on comment save.
- */
- function testActionsComment() {
- // Assign an action to the comment save trigger.
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($test_user);
- $action_id = 'trigger_test_generic_action';
- $hash = drupal_hash_base64($action_id);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/comment', $edit, t('Assign'), array(), array(), 'trigger-comment-insert-assign-form');
-
- // Set action variable to FALSE.
- variable_set($action_id, FALSE);
-
- // Create a node and add a comment to it.
- $web_user = $this->drupalCreateUser(array('create article content', 'access content', 'skip comment approval', 'post comments'));
- $this->drupalLogin($web_user);
- $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
- $edit = array();
- $edit['subject'] = $this->randomName(10);
- $edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName(10) . ' ' . $this->randomName(10);
- $this->drupalGet('comment/reply/' . $node->nid);
- $this->drupalPost(NULL, $edit, t('Save'));
-
- // Verify that the action variable has been set.
- $this->assertTrue(variable_get($action_id, FALSE), 'Check that creating a comment triggered the action.');
- }
-
- /**
- * Tests triggering on taxonomy new term.
- */
- function testActionsTaxonomy() {
- // Assign an action to the taxonomy term save trigger.
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($test_user);
- $action_id = 'trigger_test_generic_action';
- $hash = drupal_hash_base64($action_id);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/taxonomy', $edit, t('Assign'), array(), array(), 'trigger-taxonomy-term-insert-assign-form');
-
- // Set action variable to FALSE.
- variable_set($action_id, FALSE);
-
- // Create a taxonomy vocabulary and add a term to it.
-
- // Create a vocabulary.
- $vocabulary = new stdClass();
- $vocabulary->name = $this->randomName();
- $vocabulary->description = $this->randomName();
- $vocabulary->machine_name = drupal_strtolower($this->randomName());
- $vocabulary->help = '';
- $vocabulary->nodes = array('article' => 'article');
- $vocabulary->weight = mt_rand(0, 10);
- taxonomy_vocabulary_save($vocabulary);
-
- $term = new stdClass();
- $term->name = $this->randomName();
- $term->vid = $vocabulary->vid;
- taxonomy_term_save($term);
-
- // Verify that the action variable has been set.
- $this->assertTrue(variable_get($action_id, FALSE), 'Check that creating a taxonomy term triggered the action.');
- }
-
-}
-
-/**
- * Tests that orphaned actions are properly handled.
- */
-class TriggerOrphanedActionsTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Trigger orphaned actions',
- 'description' => 'Test triggering an action that has since been removed.',
- 'group' => 'Trigger',
- );
- }
-
- function setUp() {
- parent::setUp('trigger', 'trigger_test');
- }
-
- /**
- * Tests logic around orphaned actions.
- */
- function testActionsOrphaned() {
- $action = 'trigger_test_generic_any_action';
- $hash = drupal_hash_base64($action);
-
- // Assign an action from a disable-able module to a trigger, then pull the
- // trigger, and make sure the actions fire.
- $test_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($test_user);
- $edit = array('aid' => $hash);
- $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-presave-assign-form');
-
- // Create an unpublished node.
- $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content', 'access content', 'administer nodes'));
- $this->drupalLogin($web_user);
- $edit = array();
- $langcode = LANGUAGE_NONE;
- $edit["title"] = '!SimpleTest test node! ' . $this->randomName(10);
- $edit["body[$langcode][0][value]"] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
- $this->drupalPost('node/add/page', $edit, t('Save'));
- $this->assertRaw(t('!post %title has been created.', array('!post' => 'Basic page', '%title' => $edit["title"])), 'Make sure the Basic page has actually been created');
-
- // Action should have been fired.
- $this->assertTrue(variable_get('trigger_test_generic_any_action', FALSE), 'Trigger test action successfully fired.');
-
- // Disable the module that provides the action and make sure the trigger
- // doesn't white screen.
- module_disable(array('trigger_test'));
- $loaded_node = $this->drupalGetNodeByTitle($edit["title"]);
- $edit["body[$langcode][0][value]"] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
- $this->drupalPost("node/$loaded_node->nid/edit", $edit, t('Save'));
-
- // If the node body was updated successfully we have dealt with the
- // unavailable action.
- $this->assertRaw(t('!post %title has been updated.', array('!post' => 'Basic page', '%title' => $edit["title"])), 'Make sure the Basic page can be updated with the missing trigger function.');
- }
-}
-
-/**
- * Tests the unassigning of triggers.
- */
-class TriggerUnassignTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'Trigger unassigning',
- 'description' => 'Tests the unassigning of triggers.',
- 'group' => 'Trigger',
- );
- }
-
- function setUp() {
- parent::setUp('trigger', 'trigger_test');
- $web_user = $this->drupalCreateUser(array('administer actions'));
- $this->drupalLogin($web_user);
- }
-
- /**
- * Tests an attempt to unassign triggers when none are assigned.
- */
- function testUnassignAccessDenied() {
- $this->drupalGet('admin/structure/trigger/unassign');
- $this->assertResponse(403, 'If there are no actions available, return access denied.');
- }
-
-}
diff --git a/modules/update/tests/aaa_update_test.1_0.xml b/modules/update/tests/aaa_update_test.1_0.xml
deleted file mode 100644
index a168453f..00000000
--- a/modules/update/tests/aaa_update_test.1_0.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-AAA Update test
-aaa_update_test
-Drupal
-7.x
-1
-1
-1
-published
- http://example.com/project/aaa_update_test
-
- Projects Modules
-
-
-
- aaa_update_test 7.x-1.0
- 7.x-1.0
- DRUPAL-7--1-0
- 1
- 0
- published
- http://example.com/aaa_update_test-7-x-1-0-release
- http://example.com/aaa_update_test-7.x-1.0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info
deleted file mode 100644
index 8af9839d..00000000
--- a/modules/update/tests/aaa_update_test.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = AAA Update test
-description = Support module for update module testing.
-package = Testing
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/aaa_update_test.module b/modules/update/tests/aaa_update_test.module
deleted file mode 100644
index 4d67b8e4..00000000
--- a/modules/update/tests/aaa_update_test.module
+++ /dev/null
@@ -1,6 +0,0 @@
-
-No release history was found for the requested project (aaa_update_test).
diff --git a/modules/update/tests/aaa_update_test.tar.gz b/modules/update/tests/aaa_update_test.tar.gz
deleted file mode 100644
index 22c97191..00000000
Binary files a/modules/update/tests/aaa_update_test.tar.gz and /dev/null differ
diff --git a/modules/update/tests/bbb_update_test.1_0.xml b/modules/update/tests/bbb_update_test.1_0.xml
deleted file mode 100644
index bfdf196f..00000000
--- a/modules/update/tests/bbb_update_test.1_0.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-BBB Update test
-bbb_update_test
-Drupal
-7.x
-1
-1
-1
-published
- http://example.com/project/bbb_update_test
-
- Projects Modules
-
-
-
- bbb_update_test 7.x-1.0
- 7.x-1.0
- DRUPAL-7--1-0
- 1
- 0
- published
- http://example.com/bbb_update_test-7-x-1-0-release
- http://example.com/bbb_update_test-7.x-1.0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info
deleted file mode 100644
index 928cfbcf..00000000
--- a/modules/update/tests/bbb_update_test.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = BBB Update test
-description = Support module for update module testing.
-package = Testing
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/bbb_update_test.module b/modules/update/tests/bbb_update_test.module
deleted file mode 100644
index 4d67b8e4..00000000
--- a/modules/update/tests/bbb_update_test.module
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-CCC Update test
-ccc_update_test
-Drupal
-7.x
-1
-1
-1
-published
- http://example.com/project/ccc_update_test
-
- Projects Modules
-
-
-
- ccc_update_test 7.x-1.0
- 7.x-1.0
- DRUPAL-7--1-0
- 1
- 0
- published
- http://example.com/ccc_update_test-7-x-1-0-release
- http://example.com/ccc_update_test-7.x-1.0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info
deleted file mode 100644
index 7b4a97ab..00000000
--- a/modules/update/tests/ccc_update_test.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = CCC Update test
-description = Support module for update module testing.
-package = Testing
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/ccc_update_test.module b/modules/update/tests/ccc_update_test.module
deleted file mode 100644
index 4d67b8e4..00000000
--- a/modules/update/tests/ccc_update_test.module
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-Drupal
-drupal
-Drupal
-7.x
-7
-7
-7
-published
- http://example.com/project/drupal
-
- Projects Drupal project
-
-
-
- Drupal 7.0
- 7.0
- DRUPAL-7-0
- 7
- 0
- published
- http://example.com/drupal-7-0-release
- http://example.com/drupal-7-0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/drupal.1.xml b/modules/update/tests/drupal.1.xml
deleted file mode 100644
index de4cfd00..00000000
--- a/modules/update/tests/drupal.1.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-Drupal
-drupal
-Drupal
-7.x
-7
-7
-7
-published
- http://example.com/project/drupal
-
- Projects Drupal project
-
-
-
- Drupal 7.1
- 7.1
- DRUPAL-7-1
- 7
- 1
- published
- http://example.com/drupal-7-1-release
- http://example.com/drupal-7-1.tar.gz
- 1250424581
- b966255555d9c9b86d480ca08cfaa98e
- 2147483648
-
- Release type New features
- Release type Bug fixes
-
-
-
- Drupal 7.0
- 7.0
- DRUPAL-7-0
- 7
- 0
- published
- http://example.com/drupal-7-0-release
- http://example.com/drupal-7-0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/drupal.2-sec.xml b/modules/update/tests/drupal.2-sec.xml
deleted file mode 100644
index 1e68c8d5..00000000
--- a/modules/update/tests/drupal.2-sec.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-Drupal
-drupal
-Drupal
-7.x
-7
-7
-7
-published
- http://example.com/project/drupal
-
- Projects Drupal project
-
-
-
- Drupal 7.2
- 7.2
- DRUPAL-7-2
- 7
- 2
- published
- http://example.com/drupal-7-2-release
- http://example.com/drupal-7-2.tar.gz
- 1250424641
- b966255555d9c9b86d480ca08cfaa98e
- 4294967296
-
- Release type New features
- Release type Bug fixes
- Release type Security update
-
-
-
- Drupal 7.1
- 7.1
- DRUPAL-7-1
- 7
- 1
- published
- http://example.com/drupal-7-1-release
- http://example.com/drupal-7-1.tar.gz
- 1250424581
- b966255555d9c9b86d480ca08cfaa98e
- 2147483648
-
- Release type New features
- Release type Bug fixes
-
-
-
- Drupal 7.0
- 7.0
- DRUPAL-7-0
- 7
- 0
- published
- http://example.com/drupal-7-0-release
- http://example.com/drupal-7-0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/drupal.dev.xml b/modules/update/tests/drupal.dev.xml
deleted file mode 100644
index 49dcc3f5..00000000
--- a/modules/update/tests/drupal.dev.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-Drupal
-drupal
-Drupal
-7.x
-7
-7
-7
-published
- http://example.com/project/drupal
-
- Projects Drupal project
-
-
-
- Drupal 7.0
- 7.0
- DRUPAL-7-0
- 7
- 0
- published
- http://example.com/drupal-7-0-release
- http://example.com/drupal-7-0.tar.gz
- 1250424521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
- Drupal 7.x-dev
- 7.x-dev
- DRUPAL-7
- 7
- dev
- published
- http://example.com/drupal-7-x-dev-release
- http://example.com/drupal-7.x-dev.tar.gz
- 1250424581
- b966255555d9c9b86d480ca08cfaa98e
- 2147483648
-
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
deleted file mode 100644
index 3d506d78..00000000
--- a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info
+++ /dev/null
@@ -1,10 +0,0 @@
-name = Update test base theme
-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 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
deleted file mode 100644
index 40c2e447..00000000
--- a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = Update test subtheme
-description = Test theme which uses update_test_basetheme as the base theme.
-core = 7.x
-base theme = update_test_basetheme
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info
deleted file mode 100644
index 3964e7fa..00000000
--- a/modules/update/tests/update_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = Update test
-description = Support module for update module testing.
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/tests/update_test.module b/modules/update/tests/update_test.module
deleted file mode 100644
index 6fe4bdde..00000000
--- a/modules/update/tests/update_test.module
+++ /dev/null
@@ -1,191 +0,0 @@
- t('Update test'),
- 'page callback' => 'update_test_mock_page',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
- $items['503-error'] = array(
- 'title' => t('503 Service unavailable'),
- 'page callback' => 'update_callback_service_unavailable',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
-
- return $items;
-}
-
-/**
- * Implements hook_system_info_alter().
- *
- * Checks the 'update_test_system_info' variable and sees if we need to alter
- * the system info for the given $file based on the setting. The setting is
- * expected to be a nested associative array. If the key '#all' is defined, its
- * subarray will include .info keys and values for all modules and themes on the
- * system. Otherwise, the settings array is keyed by the module or theme short
- * name ($file->name) and the subarrays contain settings just for that module or
- * theme.
- */
-function update_test_system_info_alter(&$info, $file) {
- $setting = variable_get('update_test_system_info', array());
- foreach (array('#all', $file->name) as $id) {
- if (!empty($setting[$id])) {
- foreach ($setting[$id] as $key => $value) {
- $info[$key] = $value;
- }
- }
- }
-}
-
-/**
- * Implements hook_update_status_alter().
- *
- * Checks the 'update_test_update_status' variable and sees if we need to alter
- * the update status for the given project based on the setting. The setting is
- * expected to be a nested associative array. If the key '#all' is defined, its
- * subarray will include .info keys and values for all modules and themes on the
- * system. Otherwise, the settings array is keyed by the module or theme short
- * name and the subarrays contain settings just for that module or theme.
- */
-function update_test_update_status_alter(&$projects) {
- $setting = variable_get('update_test_update_status', array());
- if (!empty($setting)) {
- foreach ($projects as $project_name => &$project) {
- foreach (array('#all', $project_name) as $id) {
- if (!empty($setting[$id])) {
- foreach ($setting[$id] as $key => $value) {
- $project[$key] = $value;
- }
- }
- }
- }
- }
-}
-
-/**
- * Page callback: Prints mock XML for the Update Manager module.
- *
- * The specific XML file to print depends on two things: the project we're
- * trying to fetch data for, and the desired "availability scenario" for that
- * project which we're trying to test. Before attempting to fetch this data (by
- * checking for updates on the available updates report), callers need to define
- * the 'update_test_xml_map' variable as an array, keyed by project name,
- * indicating which availability scenario to use for that project.
- *
- * @param $project_name
- * The project short name the update manager is trying to fetch data for (the
- * fetch URLs are of the form: [base_url]/[project_name]/[core_version]).
- *
- * @see update_test_menu()
- */
-function update_test_mock_page($project_name) {
- $xml_map = variable_get('update_test_xml_map', FALSE);
- if (isset($xml_map[$project_name])) {
- $availability_scenario = $xml_map[$project_name];
- }
- elseif (isset($xml_map['#all'])) {
- $availability_scenario = $xml_map['#all'];
- }
- else {
- // The test didn't specify (for example, the webroot has other modules and
- // themes installed but they're disabled by the version of the site
- // running the test. So, we default to a file we know won't exist, so at
- // least we'll get an empty page from readfile instead of a bunch of
- // Drupal page output.
- $availability_scenario = '#broken#';
- }
-
- $path = drupal_get_path('module', 'update_test');
- readfile("$path/$project_name.$availability_scenario.xml");
-}
-
-/**
- * Implements hook_archiver_info().
- */
-function update_test_archiver_info() {
- return array(
- 'update_test_archiver' => array(
- // This is bogus, we only care about the extensions for now.
- 'class' => 'ArchiverUpdateTest',
- 'extensions' => array('update-test-extension'),
- ),
- );
-}
-
-/**
- * Implements hook_filetransfer_info().
- */
-function update_test_filetransfer_info() {
- // Define a mock file transfer method, to ensure that there will always be
- // at least one method available in the user interface (regardless of the
- // environment in which the update manager tests are run).
- return array(
- 'system_test' => array(
- 'title' => t('Update Test FileTransfer'),
- // This should be in an .inc file, but for testing purposes, it is OK to
- // leave it in the main module file.
- 'file' => 'update_test.module',
- 'class' => 'UpdateTestFileTransfer',
- 'weight' => -20,
- ),
- );
-}
-
-/**
- * Mocks a FileTransfer object to test the settings form functionality.
- */
-class UpdateTestFileTransfer {
-
- /**
- * Returns an UpdateTestFileTransfer object.
- *
- * @return
- * A new UpdateTestFileTransfer object.
- */
- public static function factory() {
- return new UpdateTestFileTransfer;
- }
-
- /**
- * Returns a settings form with a text field to input a username.
- */
- public function getSettingsForm() {
- $form = array();
- $form['udpate_test_username'] = array(
- '#type' => 'textfield',
- '#title' => t('Update Test Username'),
- );
- return $form;
- }
-}
-
-/**
- * Page callback: Displays an Error 503 (Service unavailable) page.
- *
- * @see update_test_menu()
- */
-function update_callback_service_unavailable() {
- drupal_add_http_header('Status', '503 Service unavailable');
- print "503 Service Temporarily Unavailable";
-}
diff --git a/modules/update/tests/update_test_basetheme.1_1-sec.xml b/modules/update/tests/update_test_basetheme.1_1-sec.xml
deleted file mode 100644
index 5c11c031..00000000
--- a/modules/update/tests/update_test_basetheme.1_1-sec.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-Update test base theme
-update_test_basetheme
-Drupal
-7.x
-1
-1
-1
-published
- http://example.com/project/update_test_basetheme
-
- Projects Themes
-
-
-
- update_test_basetheme 7.x-1.1
- 7.x-1.1
- DRUPAL-7--1-1
- 1
- 1
- published
- http://example.com/update_test_basetheme-7-x-1-1-release
- http://example.com/update_test_basetheme-7.x-1.1.tar.gz
- 1250624521
- b966255555d9c9b86d480ca08cfaa98e
- 1073763241
-
- Release type Security update
- Release type New features
- Release type Bug fixes
-
-
-
- update_test_basetheme 7.x-1.0
- 7.x-1.0
- DRUPAL-7--1-0
- 1
- 0
- published
- http://example.com/update_test_basetheme-7-x-1-0-release
- http://example.com/update_test_basetheme-7.x-1.0.tar.gz
- 1250524521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/tests/update_test_subtheme.1_0.xml b/modules/update/tests/update_test_subtheme.1_0.xml
deleted file mode 100644
index 5d04ec8b..00000000
--- a/modules/update/tests/update_test_subtheme.1_0.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-Update test subtheme
-update_test_subtheme
-Drupal
-7.x
-1
-1
-1
-published
- http://example.com/project/update_test_subtheme
-
- Projects Themes
-
-
-
- update_test_subtheme 7.x-1.0
- 7.x-1.0
- DRUPAL-7--1-0
- 1
- 0
- published
- http://example.com/update_test_subtheme-7-x-1-0-release
- http://example.com/update_test_subtheme-7.x-1.0.tar.gz
- 1250524521
- b966255555d9c9b86d480ca08cfaa98e
- 1073741824
-
- Release type New features
- Release type Bug fixes
-
-
-
-
diff --git a/modules/update/update-rtl.css b/modules/update/update-rtl.css
deleted file mode 100644
index f181c845..00000000
--- a/modules/update/update-rtl.css
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * @file
- * RTL styles used by the Update Manager module.
- */
-
-.update .project {
- padding-right: .25em;
-}
-
-.update .version-status {
- float: left;
- padding-left: 10px;
-}
-
-.update .version-status .icon {
- padding-right: .5em;
-}
-
-.update table.version .version-title {
- padding-left: 1em;
-}
-
-.update table.version .version-details {
- padding-left: .5em;
- direction: ltr;
-}
-
-.update table.version .version-links {
- text-align: left;
- padding-left: 1em;
-}
-
-.update .check-manually {
- padding-right: 1em;
-}
diff --git a/modules/update/update.api.php b/modules/update/update.api.php
deleted file mode 100644
index cb5669e3..00000000
--- a/modules/update/update.api.php
+++ /dev/null
@@ -1,133 +0,0 @@
- 'disabled_project_name',
- // Array of values from the main .info file for this project.
- 'info' => array(
- 'name' => 'Some disabled module',
- 'description' => 'A module not enabled on the site that you want to see in the available updates report.',
- 'version' => '7.x-1.0',
- 'core' => '7.x',
- // The maximum file change time (the "ctime" returned by the filectime()
- // PHP method) for all of the .info files included in this project.
- '_info_file_ctime' => 1243888165,
- ),
- // The date stamp when the project was released, if known. If the disabled
- // project was an officially packaged release from drupal.org, this will
- // be included in the .info file as the 'datestamp' field. This only
- // really matters for development snapshot releases that are regenerated,
- // so it can be left undefined or set to 0 in most cases.
- 'datestamp' => 1243888185,
- // Any modules (or themes) included in this project. Keyed by machine-
- // readable "short name", value is the human-readable project name printed
- // in the UI.
- 'includes' => array(
- 'disabled_project' => 'Disabled module',
- 'disabled_project_helper' => 'Disabled module helper module',
- 'disabled_project_foo' => 'Disabled module foo add-on module',
- ),
- // Does this project contain a 'module', 'theme', 'disabled-module', or
- // 'disabled-theme'?
- 'project_type' => 'disabled-module',
- );
-}
-
-/**
- * Alter the information about available updates for projects.
- *
- * @param $projects
- * Reference to an array of information about available updates to each
- * project installed on the system.
- *
- * @see update_calculate_project_data()
- */
-function hook_update_status_alter(&$projects) {
- $settings = variable_get('update_advanced_project_settings', array());
- foreach ($projects as $project => $project_info) {
- if (isset($settings[$project]) && isset($settings[$project]['check']) &&
- ($settings[$project]['check'] == 'never' ||
- (isset($project_info['recommended']) &&
- $settings[$project]['check'] === $project_info['recommended']))) {
- $projects[$project]['status'] = UPDATE_NOT_CHECKED;
- $projects[$project]['reason'] = t('Ignored from settings');
- if (!empty($settings[$project]['notes'])) {
- $projects[$project]['extra'][] = array(
- 'class' => array('admin-note'),
- 'label' => t('Administrator note'),
- 'data' => $settings[$project]['notes'],
- );
- }
- }
- }
-}
-
-/**
- * Verify an archive after it has been downloaded and extracted.
- *
- * @param string $project
- * The short name of the project that has been downloaded.
- * @param string $archive_file
- * The filename of the unextracted archive.
- * @param string $directory
- * The directory that the archive was extracted into.
- *
- * @return
- * If there are any problems, return an array of error messages. If there are
- * no problems, return an empty array.
- *
- * @see update_manager_archive_verify()
- * @ingroup update_manager_file
- */
-function hook_verify_update_archive($project, $archive_file, $directory) {
- $errors = array();
- if (!file_exists($directory)) {
- $errors[] = t('The %directory does not exist.', array('%directory' => $directory));
- }
- // Add other checks on the archive integrity here.
- return $errors;
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/modules/update/update.authorize.inc b/modules/update/update.authorize.inc
deleted file mode 100644
index 6ddd2c53..00000000
--- a/modules/update/update.authorize.inc
+++ /dev/null
@@ -1,333 +0,0 @@
- $project_info) {
- $operations[] = array(
- 'update_authorize_batch_copy_project',
- array(
- $project_info['project'],
- $project_info['updater_name'],
- $project_info['local_url'],
- $filetransfer,
- ),
- );
- }
-
- $batch = array(
- 'title' => t('Installing updates'),
- 'init_message' => t('Preparing to update your site'),
- 'operations' => $operations,
- 'finished' => 'update_authorize_update_batch_finished',
- 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc',
- );
-
- batch_set($batch);
- // Invoke the batch via authorize.php.
- system_authorized_batch_process();
-}
-
-/**
- * Installs a new project when invoked by authorize.php.
- *
- * Callback for system_authorized_init() in
- * update_manager_install_form_submit().
- *
- * @param FileTransfer $filetransfer
- * The FileTransfer object created by authorize.php for use during this
- * operation.
- * @param string $project
- * The canonical project short name (e.g., {system}.name).
- * @param string $updater_name
- * The name of the Updater class to use for installing this project.
- * @param string $local_url
- * The URL to the locally installed temp directory where the project has
- * already been downloaded and extracted into.
- */
-function update_authorize_run_install($filetransfer, $project, $updater_name, $local_url) {
- $operations[] = array(
- 'update_authorize_batch_copy_project',
- array(
- $project,
- $updater_name,
- $local_url,
- $filetransfer,
- ),
- );
-
- // @todo Instantiate our Updater to set the human-readable title?
- $batch = array(
- 'title' => t('Installing %project', array('%project' => $project)),
- 'init_message' => t('Preparing to install'),
- 'operations' => $operations,
- // @todo Use a different finished callback for different messages?
- 'finished' => 'update_authorize_install_batch_finished',
- 'file' => drupal_get_path('module', 'update') . '/update.authorize.inc',
- );
- batch_set($batch);
-
- // Invoke the batch via authorize.php.
- system_authorized_batch_process();
-}
-
-/**
- * Batch callback: Copies project to its proper place when authorized to do so.
- *
- * @param string $project
- * The canonical short name of the project being installed.
- * @param string $updater_name
- * The name of the Updater class to use for installing this project.
- * @param string $local_url
- * The URL to the locally installed temp directory where the project has
- * already been downloaded and extracted into.
- * @param FileTransfer $filetransfer
- * The FileTransfer object to use for performing this operation.
- * @param array $context
- * Reference to an array used for Batch API storage.
- */
-function update_authorize_batch_copy_project($project, $updater_name, $local_url, $filetransfer, &$context) {
-
- // Initialize some variables in the Batch API $context array.
- if (!isset($context['results']['log'])) {
- $context['results']['log'] = array();
- }
- if (!isset($context['results']['log'][$project])) {
- $context['results']['log'][$project] = array();
- }
-
- if (!isset($context['results']['tasks'])) {
- $context['results']['tasks'] = array();
- }
-
- // The batch API uses a session, and since all the arguments are serialized
- // and unserialized between requests, although the FileTransfer object itself
- // will be reconstructed, the connection pointer itself will be lost. However,
- // the FileTransfer object will still have the connection variable, even
- // though the connection itself is now gone. So, although it's ugly, we have
- // to unset the connection variable at this point so that the FileTransfer
- // object will re-initiate the actual connection.
- unset($filetransfer->connection);
-
- if (!empty($context['results']['log'][$project]['#abort'])) {
- $context['finished'] = 1;
- return;
- }
-
- $updater = new $updater_name($local_url);
-
- try {
- if ($updater->isInstalled()) {
- // This is an update.
- $tasks = $updater->update($filetransfer);
- }
- else {
- $tasks = $updater->install($filetransfer);
- }
- }
- catch (UpdaterException $e) {
- _update_batch_create_message($context['results']['log'][$project], t('Error installing / updating'), FALSE);
- _update_batch_create_message($context['results']['log'][$project], $e->getMessage(), FALSE);
- $context['results']['log'][$project]['#abort'] = TRUE;
- return;
- }
-
- _update_batch_create_message($context['results']['log'][$project], t('Installed %project_name successfully', array('%project_name' => $project)));
- if (!empty($tasks)) {
- $context['results']['tasks'] += $tasks;
- }
-
- // This particular operation is now complete, even though the batch might
- // have other operations to perform.
- $context['finished'] = 1;
-}
-
-/**
- * Batch callback: Performs actions when the authorized update batch is done.
- *
- * This processes the results and stashes them into SESSION such that
- * authorize.php will render a report. Also responsible for putting the site
- * back online and clearing the update status cache after a successful update.
- *
- * @param $success
- * TRUE if the batch operation was successful; FALSE if there were errors.
- * @param $results
- * An associative array of results from the batch operation.
- */
-function update_authorize_update_batch_finished($success, $results) {
- foreach ($results['log'] as $project => $messages) {
- if (!empty($messages['#abort'])) {
- $success = FALSE;
- }
- }
- $offline = variable_get('maintenance_mode', FALSE);
- if ($success) {
- // Now that the update completed, we need to clear the cache of available
- // update data and recompute our status, so prevent show bogus results.
- _update_authorize_clear_update_status();
-
- // Take the site out of maintenance mode if it was previously that way.
- if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
- variable_set('maintenance_mode', FALSE);
- $page_message = array(
- 'message' => t('Update was completed successfully. Your site has been taken out of maintenance mode.'),
- 'type' => 'status',
- );
- }
- else {
- $page_message = array(
- 'message' => t('Update was completed successfully.'),
- 'type' => 'status',
- );
- }
- }
- elseif (!$offline) {
- $page_message = array(
- 'message' => t('Update failed! See the log below for more information.'),
- 'type' => 'error',
- );
- }
- else {
- $page_message = array(
- 'message' => t('Update failed! See the log below for more information. Your site is still in maintenance mode.'),
- 'type' => 'error',
- );
- }
- // Since we're doing an update of existing code, always add a task for
- // running update.php.
- $results['tasks'][] = t('Your modules have been downloaded and updated.');
- $results['tasks'][] = t('Run database updates ', array('@update' => base_path() . 'update.php'));
-
- // Unset the variable since it is no longer needed.
- unset($_SESSION['maintenance_mode']);
-
- // Set all these values into the SESSION so authorize.php can display them.
- $_SESSION['authorize_results']['success'] = $success;
- $_SESSION['authorize_results']['page_message'] = $page_message;
- $_SESSION['authorize_results']['messages'] = $results['log'];
- $_SESSION['authorize_results']['tasks'] = $results['tasks'];
- $_SESSION['authorize_operation']['page_title'] = t('Update manager');
-}
-
-/**
- * Batch callback: Performs actions when the authorized install batch is done.
- *
- * This processes the results and stashes them into SESSION such that
- * authorize.php will render a report. Also responsible for putting the site
- * back online after a successful install if necessary.
- *
- * @param $success
- * TRUE if the batch operation was a success; FALSE if there were errors.
- * @param $results
- * An associative array of results from the batch operation.
- */
-function update_authorize_install_batch_finished($success, $results) {
- foreach ($results['log'] as $project => $messages) {
- if (!empty($messages['#abort'])) {
- $success = FALSE;
- }
- }
- $offline = variable_get('maintenance_mode', FALSE);
- if ($success) {
- // Take the site out of maintenance mode if it was previously that way.
- if ($offline && isset($_SESSION['maintenance_mode']) && $_SESSION['maintenance_mode'] == FALSE) {
- variable_set('maintenance_mode', FALSE);
- $page_message = array(
- 'message' => t('Installation was completed successfully. Your site has been taken out of maintenance mode.'),
- 'type' => 'status',
- );
- }
- else {
- $page_message = array(
- 'message' => t('Installation was completed successfully.'),
- 'type' => 'status',
- );
- }
- }
- elseif (!$success && !$offline) {
- $page_message = array(
- 'message' => t('Installation failed! See the log below for more information.'),
- 'type' => 'error',
- );
- }
- else {
- $page_message = array(
- 'message' => t('Installation failed! See the log below for more information. Your site is still in maintenance mode.'),
- 'type' => 'error',
- );
- }
-
- // Unset the variable since it is no longer needed.
- unset($_SESSION['maintenance_mode']);
-
- // Set all these values into the SESSION so authorize.php can display them.
- $_SESSION['authorize_results']['success'] = $success;
- $_SESSION['authorize_results']['page_message'] = $page_message;
- $_SESSION['authorize_results']['messages'] = $results['log'];
- $_SESSION['authorize_results']['tasks'] = $results['tasks'];
- $_SESSION['authorize_operation']['page_title'] = t('Update manager');
-}
-
-/**
- * Creates a structure of log messages.
- *
- * @param array $project_results
- * An associative array of results from the batch operation.
- * @param string $message
- * A string containing a log message.
- * @param bool $success
- * (optional) TRUE if the operation the message is about was a success, FALSE
- * if there were errors. Defaults to TRUE.
- */
-function _update_batch_create_message(&$project_results, $message, $success = TRUE) {
- $project_results[] = array('message' => $message, 'success' => $success);
-}
-
-/**
- * Clears cached available update status data.
- *
- * Since this function is run at such a low bootstrap level, the Update Manager
- * module is not loaded. So, we can't just call _update_cache_clear(). However,
- * the database is bootstrapped, so we can do a query ourselves to clear out
- * what we want to clear.
- *
- * Note that we do not want to just truncate the table, since that would remove
- * items related to currently pending fetch attempts.
- *
- * @see update_authorize_update_batch_finished()
- * @see _update_cache_clear()
- */
-function _update_authorize_clear_update_status() {
- $query = db_delete('cache_update');
- $query->condition(
- db_or()
- ->condition('cid', 'update_project_%', 'LIKE')
- ->condition('cid', 'available_releases::%', 'LIKE')
- );
- $query->execute();
-}
diff --git a/modules/update/update.compare.inc b/modules/update/update.compare.inc
deleted file mode 100644
index 6e0c5fee..00000000
--- a/modules/update/update.compare.inc
+++ /dev/null
@@ -1,831 +0,0 @@
-status && !empty($file->sub_themes)) {
- foreach ($file->sub_themes as $key => $name) {
- // Build a list of enabled sub-themes.
- if ($list[$key]->status) {
- $file->enabled_sub_themes[$key] = $name;
- }
- }
- // If there are no enabled subthemes, we should ignore this base theme
- // for the enabled case. If the site is trying to display disabled
- // themes, we'll catch it then.
- if (empty($file->enabled_sub_themes)) {
- continue;
- }
- }
- // Otherwise, just add projects of the proper status to our list.
- elseif ($file->status != $status) {
- continue;
- }
-
- // Skip if the .info file is broken.
- if (empty($file->info)) {
- continue;
- }
-
- // Skip if it's a hidden module or theme.
- if (!empty($file->info['hidden'])) {
- continue;
- }
-
- // If the .info doesn't define the 'project', try to figure it out.
- if (!isset($file->info['project'])) {
- $file->info['project'] = update_get_project_name($file);
- }
-
- // If we still don't know the 'project', give up.
- if (empty($file->info['project'])) {
- continue;
- }
-
- // If we don't already know it, grab the change time on the .info file
- // itself. Note: we need to use the ctime, not the mtime (modification
- // time) since many (all?) tar implementations will go out of their way to
- // set the mtime on the files it creates to the timestamps recorded in the
- // tarball. We want to see the last time the file was changed on disk,
- // which is left alone by tar and correctly set to the time the .info file
- // was unpacked.
- if (!isset($file->info['_info_file_ctime'])) {
- $info_filename = dirname($file->uri) . '/' . $file->name . '.info';
- $file->info['_info_file_ctime'] = filectime($info_filename);
- }
-
- if (!isset($file->info['datestamp'])) {
- $file->info['datestamp'] = 0;
- }
-
- $project_name = $file->info['project'];
-
- // Figure out what project type we're going to use to display this module
- // or theme. If the project name is 'drupal', we don't want it to show up
- // under the usual "Modules" section, we put it at a special "Drupal Core"
- // section at the top of the report.
- if ($project_name == 'drupal') {
- $project_display_type = 'core';
- }
- else {
- $project_display_type = $project_type;
- }
- if (empty($status) && empty($file->enabled_sub_themes)) {
- // If we're processing disabled modules or themes, append a suffix.
- // However, we don't do this to a a base theme with enabled
- // subthemes, since we treat that case as if it is enabled.
- $project_display_type .= '-disabled';
- }
- // Add a list of sub-themes that "depend on" the project and a list of base
- // themes that are "required by" the project.
- if ($project_name == 'drupal') {
- // Drupal core is always required, so this extra info would be noise.
- $sub_themes = array();
- $base_themes = array();
- }
- else {
- // Add list of enabled sub-themes.
- $sub_themes = !empty($file->enabled_sub_themes) ? $file->enabled_sub_themes : array();
- // Add list of base themes.
- $base_themes = !empty($file->base_themes) ? $file->base_themes : array();
- }
- if (!isset($projects[$project_name])) {
- // Only process this if we haven't done this project, since a single
- // project can have multiple modules or themes.
- $projects[$project_name] = array(
- 'name' => $project_name,
- // Only save attributes from the .info file we care about so we do not
- // bloat our RAM usage needlessly.
- 'info' => update_filter_project_info($file->info),
- 'datestamp' => $file->info['datestamp'],
- 'includes' => array($file->name => $file->info['name']),
- 'project_type' => $project_display_type,
- 'project_status' => $status,
- 'sub_themes' => $sub_themes,
- 'base_themes' => $base_themes,
- );
- }
- elseif ($projects[$project_name]['project_type'] == $project_display_type) {
- // Only add the file we're processing to the 'includes' array for this
- // project if it is of the same type and status (which is encoded in the
- // $project_display_type). This prevents listing all the disabled
- // modules included with an enabled project if we happen to be checking
- // for disabled modules, too.
- $projects[$project_name]['includes'][$file->name] = $file->info['name'];
- $projects[$project_name]['info']['_info_file_ctime'] = max($projects[$project_name]['info']['_info_file_ctime'], $file->info['_info_file_ctime']);
- $projects[$project_name]['datestamp'] = max($projects[$project_name]['datestamp'], $file->info['datestamp']);
- if (!empty($sub_themes)) {
- $projects[$project_name]['sub_themes'] += $sub_themes;
- }
- if (!empty($base_themes)) {
- $projects[$project_name]['base_themes'] += $base_themes;
- }
- }
- elseif (empty($status)) {
- // If we have a project_name that matches, but the project_display_type
- // does not, it means we're processing a disabled module or theme that
- // belongs to a project that has some enabled code. In this case, we add
- // the disabled thing into a separate array for separate display.
- $projects[$project_name]['disabled'][$file->name] = $file->info['name'];
- }
- }
-}
-
-/**
- * Determines what project a given file object belongs to.
- *
- * @param $file
- * A file object as returned by system_get_files_database().
- *
- * @return
- * The canonical project short name.
- *
- * @see system_get_files_database()
- */
-function update_get_project_name($file) {
- $project_name = '';
- if (isset($file->info['project'])) {
- $project_name = $file->info['project'];
- }
- elseif (isset($file->info['package']) && (strpos($file->info['package'], 'Core') === 0)) {
- $project_name = 'drupal';
- }
- return $project_name;
-}
-
-/**
- * Determines version and type information for currently installed projects.
- *
- * Processes the list of projects on the system to figure out the currently
- * installed versions, and other information that is required before we can
- * compare against the available releases to produce the status report.
- *
- * @param $projects
- * Array of project information from update_get_projects().
- */
-function update_process_project_info(&$projects) {
- foreach ($projects as $key => $project) {
- // Assume an official release until we see otherwise.
- $install_type = 'official';
-
- $info = $project['info'];
-
- if (isset($info['version'])) {
- // Check for development snapshots
- if (preg_match('@(dev|HEAD)@', $info['version'])) {
- $install_type = 'dev';
- }
-
- // Figure out what the currently installed major version is. We need
- // to handle both contribution (e.g. "5.x-1.3", major = 1) and core
- // (e.g. "5.1", major = 5) version strings.
- $matches = array();
- if (preg_match('/^(\d+\.x-)?(\d+)\..*$/', $info['version'], $matches)) {
- $info['major'] = $matches[2];
- }
- elseif (!isset($info['major'])) {
- // This would only happen for version strings that don't follow the
- // drupal.org convention. We let contribs define "major" in their
- // .info in this case, and only if that's missing would we hit this.
- $info['major'] = -1;
- }
- }
- else {
- // No version info available at all.
- $install_type = 'unknown';
- $info['version'] = t('Unknown');
- $info['major'] = -1;
- }
-
- // Finally, save the results we care about into the $projects array.
- $projects[$key]['existing_version'] = $info['version'];
- $projects[$key]['existing_major'] = $info['major'];
- $projects[$key]['install_type'] = $install_type;
- }
-}
-
-/**
- * Calculates the current update status of all projects on the site.
- *
- * The results of this function are expensive to compute, especially on sites
- * with lots of modules or themes, since it involves a lot of comparisons and
- * other operations. Therefore, we cache the results into the {cache_update}
- * table using the 'update_project_data' cache ID. However, since this is not
- * the data about available updates fetched from the network, it is ok to
- * invalidate it somewhat quickly. If we keep this data for very long, site
- * administrators are more likely to see incorrect results if they upgrade to a
- * newer version of a module or theme but do not visit certain pages that
- * automatically clear this cache.
- *
- * @param array $available
- * Data about available project releases.
- *
- * @return
- * An array of installed projects with current update status information.
- *
- * @see update_get_available()
- * @see update_get_projects()
- * @see update_process_project_info()
- * @see update_project_cache()
- */
-function update_calculate_project_data($available) {
- // Retrieve the projects from cache, if present.
- $projects = update_project_cache('update_project_data');
- // If $projects is empty, then the cache must be rebuilt.
- // Otherwise, return the cached data and skip the rest of the function.
- if (!empty($projects)) {
- return $projects;
- }
- $projects = update_get_projects();
- update_process_project_info($projects);
- foreach ($projects as $project => $project_info) {
- if (isset($available[$project])) {
- update_calculate_project_update_status($project, $projects[$project], $available[$project]);
- }
- else {
- $projects[$project]['status'] = UPDATE_UNKNOWN;
- $projects[$project]['reason'] = t('No available releases found');
- }
- }
- // Give other modules a chance to alter the status (for example, to allow a
- // contrib module to provide fine-grained settings to ignore specific
- // projects or releases).
- drupal_alter('update_status', $projects);
-
- // Cache the site's update status for at most 1 hour.
- _update_cache_set('update_project_data', $projects, REQUEST_TIME + 3600);
- return $projects;
-}
-
-/**
- * Calculates the current update status of a specific project.
- *
- * This function is the heart of the update status feature. For each project it
- * is invoked with, it first checks if the project has been flagged with a
- * special status like "unsupported" or "insecure", or if the project node
- * itself has been unpublished. In any of those cases, the project is marked
- * with an error and the next project is considered.
- *
- * If the project itself is valid, the function decides what major release
- * series to consider. The project defines what the currently supported major
- * versions are for each version of core, so the first step is to make sure the
- * current version is still supported. If so, that's the target version. If the
- * current version is unsupported, the project maintainer's recommended major
- * version is used. There's also a check to make sure that this function never
- * recommends an earlier release than the currently installed major version.
- *
- * Given a target major version, the available releases are scanned looking for
- * the specific release to recommend (avoiding beta releases and development
- * snapshots if possible). For the target major version, the highest patch level
- * is found. If there is a release at that patch level with no extra ("beta",
- * etc.), then the release at that patch level with the most recent release date
- * is recommended. If every release at that patch level has extra (only betas),
- * then the latest release from the previous patch level is recommended. For
- * example:
- *
- * - 1.6-bugfix <-- recommended version because 1.6 already exists.
- * - 1.6
- *
- * or
- *
- * - 1.6-beta
- * - 1.5 <-- recommended version because no 1.6 exists.
- * - 1.4
- *
- * Also, the latest release from the same major version is looked for, even beta
- * releases, to display to the user as the "Latest version" option.
- * Additionally, the latest official release from any higher major versions that
- * have been released is searched for to provide a set of "Also available"
- * options.
- *
- * Finally, and most importantly, the release history continues to be scanned
- * until the currently installed release is reached, searching for anything
- * marked as a security update. If any security updates have been found between
- * the recommended release and the installed version, all of the releases that
- * included a security fix are recorded so that the site administrator can be
- * warned their site is insecure, and links pointing to the release notes for
- * each security update can be included (which, in turn, will link to the
- * official security announcements for each vulnerability).
- *
- * This function relies on the fact that the .xml release history data comes
- * sorted based on major version and patch level, then finally by release date
- * if there are multiple releases such as betas from the same major.patch
- * version (e.g., 5.x-1.5-beta1, 5.x-1.5-beta2, and 5.x-1.5). Development
- * snapshots for a given major version are always listed last.
- *
- * @param $project
- * An array containing information about a specific project.
- * @param $project_data
- * An array containing information about a specific project.
- * @param $available
- * Data about available project releases of a specific project.
- */
-function update_calculate_project_update_status($project, &$project_data, $available) {
- foreach (array('title', 'link') as $attribute) {
- if (!isset($project_data[$attribute]) && isset($available[$attribute])) {
- $project_data[$attribute] = $available[$attribute];
- }
- }
-
- // If the project status is marked as something bad, there's nothing else
- // to consider.
- if (isset($available['project_status'])) {
- switch ($available['project_status']) {
- case 'insecure':
- $project_data['status'] = UPDATE_NOT_SECURE;
- if (empty($project_data['extra'])) {
- $project_data['extra'] = array();
- }
- $project_data['extra'][] = array(
- 'class' => array('project-not-secure'),
- 'label' => t('Project not secure'),
- 'data' => t('This project has been labeled insecure by the Drupal security team, and is no longer available for download. Immediately disabling everything included by this project is strongly recommended!'),
- );
- break;
- case 'unpublished':
- case 'revoked':
- $project_data['status'] = UPDATE_REVOKED;
- if (empty($project_data['extra'])) {
- $project_data['extra'] = array();
- }
- $project_data['extra'][] = array(
- 'class' => array('project-revoked'),
- 'label' => t('Project revoked'),
- 'data' => t('This project has been revoked, and is no longer available for download. Disabling everything included by this project is strongly recommended!'),
- );
- break;
- case 'unsupported':
- $project_data['status'] = UPDATE_NOT_SUPPORTED;
- if (empty($project_data['extra'])) {
- $project_data['extra'] = array();
- }
- $project_data['extra'][] = array(
- 'class' => array('project-not-supported'),
- 'label' => t('Project not supported'),
- 'data' => t('This project is no longer supported, and is no longer available for download. Disabling everything included by this project is strongly recommended!'),
- );
- break;
- case 'not-fetched':
- $project_data['status'] = UPDATE_NOT_FETCHED;
- $project_data['reason'] = t('Failed to get available update data.');
- break;
-
- default:
- // Assume anything else (e.g. 'published') is valid and we should
- // perform the rest of the logic in this function.
- break;
- }
- }
-
- if (!empty($project_data['status'])) {
- // We already know the status for this project, so there's nothing else to
- // compute. Record the project status into $project_data and we're done.
- $project_data['project_status'] = $available['project_status'];
- return;
- }
-
- // Figure out the target major version.
- $existing_major = $project_data['existing_major'];
- $supported_majors = array();
- if (isset($available['supported_majors'])) {
- $supported_majors = explode(',', $available['supported_majors']);
- }
- elseif (isset($available['default_major'])) {
- // Older release history XML file without supported or recommended.
- $supported_majors[] = $available['default_major'];
- }
-
- if (in_array($existing_major, $supported_majors)) {
- // Still supported, stay at the current major version.
- $target_major = $existing_major;
- }
- elseif (isset($available['recommended_major'])) {
- // Since 'recommended_major' is defined, we know this is the new XML
- // format. Therefore, we know the current release is unsupported since
- // its major version was not in the 'supported_majors' list. We should
- // find the best release from the recommended major version.
- $target_major = $available['recommended_major'];
- $project_data['status'] = UPDATE_NOT_SUPPORTED;
- }
- elseif (isset($available['default_major'])) {
- // Older release history XML file without recommended, so recommend
- // the currently defined "default_major" version.
- $target_major = $available['default_major'];
- }
- else {
- // Malformed XML file? Stick with the current version.
- $target_major = $existing_major;
- }
-
- // Make sure we never tell the admin to downgrade. If we recommended an
- // earlier version than the one they're running, they'd face an
- // impossible data migration problem, since Drupal never supports a DB
- // downgrade path. In the unfortunate case that what they're running is
- // unsupported, and there's nothing newer for them to upgrade to, we
- // can't print out a "Recommended version", but just have to tell them
- // what they have is unsupported and let them figure it out.
- $target_major = max($existing_major, $target_major);
-
- $release_patch_changed = '';
- $patch = '';
-
- // If the project is marked as UPDATE_FETCH_PENDING, it means that the
- // data we currently have (if any) is stale, and we've got a task queued
- // up to (re)fetch the data. In that case, we mark it as such, merge in
- // whatever data we have (e.g. project title and link), and move on.
- if (!empty($available['fetch_status']) && $available['fetch_status'] == UPDATE_FETCH_PENDING) {
- $project_data['status'] = UPDATE_FETCH_PENDING;
- $project_data['reason'] = t('No available update data');
- $project_data['fetch_status'] = $available['fetch_status'];
- return;
- }
-
- // Defend ourselves from XML history files that contain no releases.
- if (empty($available['releases'])) {
- $project_data['status'] = UPDATE_UNKNOWN;
- $project_data['reason'] = t('No available releases found');
- return;
- }
- foreach ($available['releases'] as $version => $release) {
- // First, if this is the existing release, check a few conditions.
- if ($project_data['existing_version'] === $version) {
- if (isset($release['terms']['Release type']) &&
- in_array('Insecure', $release['terms']['Release type'])) {
- $project_data['status'] = UPDATE_NOT_SECURE;
- }
- elseif ($release['status'] == 'unpublished') {
- $project_data['status'] = UPDATE_REVOKED;
- if (empty($project_data['extra'])) {
- $project_data['extra'] = array();
- }
- $project_data['extra'][] = array(
- 'class' => array('release-revoked'),
- 'label' => t('Release revoked'),
- 'data' => t('Your currently installed release has been revoked, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'),
- );
- }
- elseif (isset($release['terms']['Release type']) &&
- in_array('Unsupported', $release['terms']['Release type'])) {
- $project_data['status'] = UPDATE_NOT_SUPPORTED;
- if (empty($project_data['extra'])) {
- $project_data['extra'] = array();
- }
- $project_data['extra'][] = array(
- 'class' => array('release-not-supported'),
- 'label' => t('Release not supported'),
- 'data' => t('Your currently installed release is now unsupported, and is no longer available for download. Disabling everything included in this release or upgrading is strongly recommended!'),
- );
- }
- }
-
- // Otherwise, ignore unpublished, insecure, or unsupported releases.
- if ($release['status'] == 'unpublished' ||
- (isset($release['terms']['Release type']) &&
- (in_array('Insecure', $release['terms']['Release type']) ||
- in_array('Unsupported', $release['terms']['Release type'])))) {
- continue;
- }
-
- // See if this is a higher major version than our target and yet still
- // supported. If so, record it as an "Also available" release.
- // Note: some projects have a HEAD release from CVS days, which could
- // be one of those being compared. They would not have version_major
- // set, so we must call isset first.
- if (isset($release['version_major']) && $release['version_major'] > $target_major) {
- if (in_array($release['version_major'], $supported_majors)) {
- if (!isset($project_data['also'])) {
- $project_data['also'] = array();
- }
- if (!isset($project_data['also'][$release['version_major']])) {
- $project_data['also'][$release['version_major']] = $version;
- $project_data['releases'][$version] = $release;
- }
- }
- // Otherwise, this release can't matter to us, since it's neither
- // from the release series we're currently using nor the recommended
- // release. We don't even care about security updates for this
- // branch, since if a project maintainer puts out a security release
- // at a higher major version and not at the lower major version,
- // they must remove the lower version from the supported major
- // versions at the same time, in which case we won't hit this code.
- continue;
- }
-
- // Look for the 'latest version' if we haven't found it yet. Latest is
- // defined as the most recent version for the target major version.
- if (!isset($project_data['latest_version'])
- && $release['version_major'] == $target_major) {
- $project_data['latest_version'] = $version;
- $project_data['releases'][$version] = $release;
- }
-
- // Look for the development snapshot release for this branch.
- if (!isset($project_data['dev_version'])
- && $release['version_major'] == $target_major
- && isset($release['version_extra'])
- && $release['version_extra'] == 'dev') {
- $project_data['dev_version'] = $version;
- $project_data['releases'][$version] = $release;
- }
-
- // Look for the 'recommended' version if we haven't found it yet (see
- // phpdoc at the top of this function for the definition).
- if (!isset($project_data['recommended'])
- && $release['version_major'] == $target_major
- && isset($release['version_patch'])) {
- if ($patch != $release['version_patch']) {
- $patch = $release['version_patch'];
- $release_patch_changed = $release;
- }
- if (empty($release['version_extra']) && $patch == $release['version_patch']) {
- $project_data['recommended'] = $release_patch_changed['version'];
- $project_data['releases'][$release_patch_changed['version']] = $release_patch_changed;
- }
- }
-
- // Stop searching once we hit the currently installed version.
- if ($project_data['existing_version'] === $version) {
- break;
- }
-
- // If we're running a dev snapshot and have a timestamp, stop
- // searching for security updates once we hit an official release
- // older than what we've got. Allow 100 seconds of leeway to handle
- // differences between the datestamp in the .info file and the
- // timestamp of the tarball itself (which are usually off by 1 or 2
- // seconds) so that we don't flag that as a new release.
- if ($project_data['install_type'] == 'dev') {
- if (empty($project_data['datestamp'])) {
- // We don't have current timestamp info, so we can't know.
- continue;
- }
- elseif (isset($release['date']) && ($project_data['datestamp'] + 100 > $release['date'])) {
- // We're newer than this, so we can skip it.
- continue;
- }
- }
-
- // See if this release is a security update.
- if (isset($release['terms']['Release type'])
- && in_array('Security update', $release['terms']['Release type'])) {
- $project_data['security updates'][] = $release;
- }
- }
-
- // If we were unable to find a recommended version, then make the latest
- // version the recommended version if possible.
- if (!isset($project_data['recommended']) && isset($project_data['latest_version'])) {
- $project_data['recommended'] = $project_data['latest_version'];
- }
-
- //
- // Check to see if we need an update or not.
- //
-
- if (!empty($project_data['security updates'])) {
- // If we found security updates, that always trumps any other status.
- $project_data['status'] = UPDATE_NOT_SECURE;
- }
-
- if (isset($project_data['status'])) {
- // If we already know the status, we're done.
- return;
- }
-
- // If we don't know what to recommend, there's nothing we can report.
- // Bail out early.
- if (!isset($project_data['recommended'])) {
- $project_data['status'] = UPDATE_UNKNOWN;
- $project_data['reason'] = t('No available releases found');
- return;
- }
-
- // If we're running a dev snapshot, compare the date of the dev snapshot
- // with the latest official version, and record the absolute latest in
- // 'latest_dev' so we can correctly decide if there's a newer release
- // than our current snapshot.
- if ($project_data['install_type'] == 'dev') {
- if (isset($project_data['dev_version']) && $available['releases'][$project_data['dev_version']]['date'] > $available['releases'][$project_data['latest_version']]['date']) {
- $project_data['latest_dev'] = $project_data['dev_version'];
- }
- else {
- $project_data['latest_dev'] = $project_data['latest_version'];
- }
- }
-
- // Figure out the status, based on what we've seen and the install type.
- switch ($project_data['install_type']) {
- case 'official':
- if ($project_data['existing_version'] === $project_data['recommended'] || $project_data['existing_version'] === $project_data['latest_version']) {
- $project_data['status'] = UPDATE_CURRENT;
- }
- else {
- $project_data['status'] = UPDATE_NOT_CURRENT;
- }
- break;
-
- case 'dev':
- $latest = $available['releases'][$project_data['latest_dev']];
- if (empty($project_data['datestamp'])) {
- $project_data['status'] = UPDATE_NOT_CHECKED;
- $project_data['reason'] = t('Unknown release date');
- }
- elseif (($project_data['datestamp'] + 100 > $latest['date'])) {
- $project_data['status'] = UPDATE_CURRENT;
- }
- else {
- $project_data['status'] = UPDATE_NOT_CURRENT;
- }
- break;
-
- default:
- $project_data['status'] = UPDATE_UNKNOWN;
- $project_data['reason'] = t('Invalid info');
- }
-}
-
-/**
- * Retrieves data from {cache_update} or empties the cache when necessary.
- *
- * Two very expensive arrays computed by this module are the list of all
- * installed modules and themes (and .info data, project associations, etc), and
- * the current status of the site relative to the currently available releases.
- * These two arrays are cached in the {cache_update} table and used whenever
- * possible. The cache is cleared whenever the administrator visits the status
- * report, available updates report, or the module or theme administration
- * pages, since we should always recompute the most current values on any of
- * those pages.
- *
- * Note: while both of these arrays are expensive to compute (in terms of disk
- * I/O and some fairly heavy CPU processing), neither of these is the actual
- * data about available updates that we have to fetch over the network from
- * updates.drupal.org. That information is stored with the
- * 'update_available_releases' cache ID -- it needs to persist longer than 1
- * hour and never get invalidated just by visiting a page on the site.
- *
- * @param $cid
- * The cache ID of data to return from the cache. Valid options are
- * 'update_project_data' and 'update_project_projects'.
- *
- * @return
- * The cached value of the $projects array generated by
- * update_calculate_project_data() or update_get_projects(), or an empty array
- * when the cache is cleared.
- */
-function update_project_cache($cid) {
- $projects = array();
-
- // On certain paths, we should clear the cache and recompute the projects for
- // update status of the site to avoid presenting stale information.
- $q = $_GET['q'];
- $paths = array(
- 'admin/modules',
- 'admin/modules/update',
- 'admin/appearance',
- 'admin/appearance/update',
- 'admin/reports',
- 'admin/reports/updates',
- 'admin/reports/updates/update',
- 'admin/reports/status',
- 'admin/reports/updates/check',
- );
- if (in_array($q, $paths)) {
- _update_cache_clear($cid);
- }
- else {
- $cache = _update_cache_get($cid);
- if (!empty($cache->data) && $cache->expire > REQUEST_TIME) {
- $projects = $cache->data;
- }
- }
- return $projects;
-}
-
-/**
- * Filters the project .info data to only save attributes we need.
- *
- * @param array $info
- * Array of .info file data as returned by drupal_parse_info_file().
- *
- * @return
- * Array of .info file data we need for the update manager.
- *
- * @see _update_process_info_list()
- */
-function update_filter_project_info($info) {
- $whitelist = array(
- '_info_file_ctime',
- 'datestamp',
- 'major',
- 'name',
- 'package',
- 'project',
- 'project status url',
- 'version',
- );
- return array_intersect_key($info, drupal_map_assoc($whitelist));
-}
diff --git a/modules/update/update.css b/modules/update/update.css
deleted file mode 100644
index ba45fe6b..00000000
--- a/modules/update/update.css
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * @file
- * Styles used by the Update Manager module.
- */
-
-.update .project {
- font-weight: bold;
- font-size: 110%;
- padding-left: .25em; /* LTR */
- height: 22px;
-}
-
-.update .version-status {
- float: right; /* LTR */
- padding-right: 10px; /* LTR */
- font-size: 110%;
- height: 20px;
-}
-
-.update .version-status .icon {
- padding-left: .5em; /* LTR */
-}
-
-.update .version-date {
- white-space: nowrap;
-}
-
-.update .info {
- margin: 0;
- padding: 1em 1em .25em 1em;
-}
-
-.update tr.even,
-.update tr.odd {
- border: none;
-}
-
-.update tr td {
- border-top: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
-}
-
-.update tr.error {
- background: #fcc;
-}
-
-.update tr.error .version-recommended {
- background: #fdd;
-}
-
-.update tr.ok {
- background: #dfd;
-}
-
-.update tr.warning {
- background: #ffd;
-}
-
-.update tr.warning .version-recommended {
- background: #ffe;
-}
-
-.current-version,
-.new-version {
- direction: ltr; /* Note: version numbers should always be LTR. */
-}
-
-.update tr.unknown {
- background: #ddd;
-}
-
-table.update,
-.update table.version {
- width: 100%;
- margin-top: .5em;
- border: none;
-}
-
-.update table.version tbody {
- border: none;
-}
-
-.update table.version tr,
-.update table.version td {
- line-height: .9em;
- padding: 0;
- margin: 0;
- border: none;
- background: none;
-}
-
-.update table.version .version-title {
- padding-left: 1em; /* LTR */
- width: 14em;
-}
-
-.update table.version .version-details {
- padding-right: .5em; /* LTR */
-}
-
-.update table.version .version-links {
- text-align: right; /* LTR */
- padding-right: 1em; /* LTR */
-}
-
-.update table.version-security .version-title {
- color: #970F00;
-}
-
-.update table.version-recommended-strong .version-title {
- font-weight: bold;
-}
-
-.update .security-error {
- font-weight: bold;
- color: #970F00;
-}
-
-.update .check-manually {
- padding-left: 1em; /* LTR */
-}
-
-.update-major-version-warning {
- color: #ff0000;
-}
-
-table tbody tr.update-security,
-table tbody tr.update-unsupported {
- background: #fcc;
-}
-
-th.update-project-name {
- width: 50%;
-}
-
diff --git a/modules/update/update.fetch.inc b/modules/update/update.fetch.inc
deleted file mode 100644
index 9dd2f0ba..00000000
--- a/modules/update/update.fetch.inc
+++ /dev/null
@@ -1,423 +0,0 @@
- array(
- array('update_fetch_data_batch', array()),
- ),
- 'finished' => 'update_fetch_data_finished',
- 'title' => t('Checking available update data'),
- 'progress_message' => t('Trying to check available update data ...'),
- 'error_message' => t('Error checking available update data.'),
- 'file' => drupal_get_path('module', 'update') . '/update.fetch.inc',
- );
- batch_set($batch);
- batch_process('admin/reports/updates');
-}
-
-/**
- * Batch callback: Processes a step in batch for fetching available update data.
- *
- * @param $context
- * Reference to an array used for Batch API storage.
- */
-function update_fetch_data_batch(&$context) {
- $queue = DrupalQueue::get('update_fetch_tasks');
- if (empty($context['sandbox']['max'])) {
- $context['finished'] = 0;
- $context['sandbox']['max'] = $queue->numberOfItems();
- $context['sandbox']['progress'] = 0;
- $context['message'] = t('Checking available update data ...');
- $context['results']['updated'] = 0;
- $context['results']['failures'] = 0;
- $context['results']['processed'] = 0;
- }
-
- // Grab another item from the fetch queue.
- for ($i = 0; $i < 5; $i++) {
- if ($item = $queue->claimItem()) {
- if (_update_process_fetch_task($item->data)) {
- $context['results']['updated']++;
- $context['message'] = t('Checked available update data for %title.', array('%title' => $item->data['info']['name']));
- }
- else {
- $context['message'] = t('Failed to check available update data for %title.', array('%title' => $item->data['info']['name']));
- $context['results']['failures']++;
- }
- $context['sandbox']['progress']++;
- $context['results']['processed']++;
- $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
- $queue->deleteItem($item);
- }
- else {
- // If the queue is currently empty, we're done. It's possible that
- // another thread might have added new fetch tasks while we were
- // processing this batch. In that case, the usual 'finished' math could
- // get confused, since we'd end up processing more tasks that we thought
- // we had when we started and initialized 'max' with numberOfItems(). By
- // forcing 'finished' to be exactly 1 here, we ensure that batch
- // processing is terminated.
- $context['finished'] = 1;
- return;
- }
- }
-}
-
-/**
- * Batch callback: Performs actions when all fetch tasks have been completed.
- *
- * @param $success
- * TRUE if the batch operation was successful; FALSE if there were errors.
- * @param $results
- * An associative array of results from the batch operation, including the key
- * 'updated' which holds the total number of projects we fetched available
- * update data for.
- */
-function update_fetch_data_finished($success, $results) {
- if ($success) {
- if (!empty($results)) {
- if (!empty($results['updated'])) {
- drupal_set_message(format_plural($results['updated'], 'Checked available update data for one project.', 'Checked available update data for @count projects.'));
- }
- if (!empty($results['failures'])) {
- drupal_set_message(format_plural($results['failures'], 'Failed to get available update data for one project.', 'Failed to get available update data for @count projects.'), 'error');
- }
- }
- }
- else {
- drupal_set_message(t('An error occurred trying to get available update data.'), 'error');
- }
-}
-
-/**
- * Attempts to drain the queue of tasks for release history data to fetch.
- */
-function _update_fetch_data() {
- $queue = DrupalQueue::get('update_fetch_tasks');
- $end = time() + variable_get('update_max_fetch_time', UPDATE_MAX_FETCH_TIME);
- while (time() < $end && ($item = $queue->claimItem())) {
- _update_process_fetch_task($item->data);
- $queue->deleteItem($item);
- }
-}
-
-/**
- * Processes a task to fetch available update data for a single project.
- *
- * Once the release history XML data is downloaded, it is parsed and saved into
- * the {cache_update} table in an entry just for that project.
- *
- * @param $project
- * Associative array of information about the project to fetch data for.
- *
- * @return
- * TRUE if we fetched parsable XML, otherwise FALSE.
- */
-function _update_process_fetch_task($project) {
- global $base_url;
- $fail = &drupal_static(__FUNCTION__, array());
- // This can be in the middle of a long-running batch, so REQUEST_TIME won't
- // necessarily be valid.
- $now = time();
- if (empty($fail)) {
- // If we have valid data about release history XML servers that we have
- // failed to fetch from on previous attempts, load that from the cache.
- if (($cache = _update_cache_get('fetch_failures')) && ($cache->expire > $now)) {
- $fail = $cache->data;
- }
- }
-
- $max_fetch_attempts = variable_get('update_max_fetch_attempts', UPDATE_MAX_FETCH_ATTEMPTS);
-
- $success = FALSE;
- $available = array();
- $site_key = drupal_hmac_base64($base_url, drupal_get_private_key());
- $url = _update_build_fetch_url($project, $site_key);
- $fetch_url_base = _update_get_fetch_url_base($project);
- $project_name = $project['name'];
-
- if (empty($fail[$fetch_url_base]) || $fail[$fetch_url_base] < $max_fetch_attempts) {
- $xml = drupal_http_request($url);
- if (!isset($xml->error) && isset($xml->data)) {
- $data = $xml->data;
- }
- }
-
- if (!empty($data)) {
- $available = update_parse_xml($data);
- // @todo: Purge release data we don't need (http://drupal.org/node/238950).
- if (!empty($available)) {
- // Only if we fetched and parsed something sane do we return success.
- $success = TRUE;
- }
- }
- else {
- $available['project_status'] = 'not-fetched';
- if (empty($fail[$fetch_url_base])) {
- $fail[$fetch_url_base] = 1;
- }
- else {
- $fail[$fetch_url_base]++;
- }
- }
-
- $frequency = variable_get('update_check_frequency', 1);
- $cid = 'available_releases::' . $project_name;
- _update_cache_set($cid, $available, $now + (60 * 60 * 24 * $frequency));
-
- // Stash the $fail data back in the DB for the next 5 minutes.
- _update_cache_set('fetch_failures', $fail, $now + (60 * 5));
-
- // Whether this worked or not, we did just (try to) check for updates.
- variable_set('update_last_check', $now);
-
- // Now that we processed the fetch task for this project, clear out the
- // record in {cache_update} for this task so we're willing to fetch again.
- _update_cache_clear('fetch_task::' . $project_name);
-
- return $success;
-}
-
-/**
- * Clears out all the cached available update data and initiates re-fetching.
- */
-function _update_refresh() {
- module_load_include('inc', 'update', 'update.compare');
-
- // Since we're fetching new available update data, we want to clear
- // our cache of both the projects we care about, and the current update
- // status of the site. We do *not* want to clear the cache of available
- // releases just yet, since that data (even if it's stale) can be useful
- // during update_get_projects(); for example, to modules that implement
- // hook_system_info_alter() such as cvs_deploy.
- _update_cache_clear('update_project_projects');
- _update_cache_clear('update_project_data');
-
- $projects = update_get_projects();
-
- // Now that we have the list of projects, we should also clear our cache of
- // available release data, since even if we fail to fetch new data, we need
- // to clear out the stale data at this point.
- _update_cache_clear('available_releases::', TRUE);
-
- foreach ($projects as $key => $project) {
- update_create_fetch_task($project);
- }
-}
-
-/**
- * Adds a task to the queue for fetching release history data for a project.
- *
- * We only create a new fetch task if there's no task already in the queue for
- * this particular project (based on 'fetch_task::' entries in the
- * {cache_update} table).
- *
- * @param $project
- * Associative array of information about a project as created by
- * update_get_projects(), including keys such as 'name' (short name), and the
- * 'info' array with data from a .info file for the project.
- *
- * @see update_get_projects()
- * @see update_get_available()
- * @see update_refresh()
- * @see update_fetch_data()
- * @see _update_process_fetch_task()
- */
-function _update_create_fetch_task($project) {
- $fetch_tasks = &drupal_static(__FUNCTION__, array());
- if (empty($fetch_tasks)) {
- $fetch_tasks = _update_get_cache_multiple('fetch_task');
- }
- $cid = 'fetch_task::' . $project['name'];
- if (empty($fetch_tasks[$cid])) {
- $queue = DrupalQueue::get('update_fetch_tasks');
- $queue->createItem($project);
- // Due to race conditions, it is possible that another process already
- // inserted a row into the {cache_update} table and the following query will
- // throw an exception.
- // @todo: Remove the need for the manual check by relying on a queue that
- // enforces unique items.
- try {
- db_insert('cache_update')
- ->fields(array(
- 'cid' => $cid,
- 'created' => REQUEST_TIME,
- ))
- ->execute();
- }
- catch (Exception $e) {
- // The exception can be ignored safely.
- }
- $fetch_tasks[$cid] = REQUEST_TIME;
- }
-}
-
-/**
- * Generates the URL to fetch information about project updates.
- *
- * This figures out the right URL to use, based on the project's .info file and
- * the global defaults. Appends optional query arguments when the site is
- * configured to report usage stats.
- *
- * @param $project
- * The array of project information from update_get_projects().
- * @param $site_key
- * (optional) The anonymous site key hash. Defaults to an empty string.
- *
- * @return
- * The URL for fetching information about updates to the specified project.
- *
- * @see update_fetch_data()
- * @see _update_process_fetch_task()
- * @see update_get_projects()
- */
-function _update_build_fetch_url($project, $site_key = '') {
- $name = $project['name'];
- $url = _update_get_fetch_url_base($project);
- $url .= '/' . $name . '/' . DRUPAL_CORE_COMPATIBILITY;
-
- // Only append usage information if we have a site key and the project is
- // enabled. We do not want to record usage statistics for disabled projects.
- if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) {
- // Append the site key.
- $url .= (strpos($url, '?') !== FALSE) ? '&' : '?';
- $url .= 'site_key=';
- $url .= rawurlencode($site_key);
-
- // Append the version.
- if (!empty($project['info']['version'])) {
- $url .= '&version=';
- $url .= rawurlencode($project['info']['version']);
- }
-
- // Append the list of modules or themes enabled.
- $list = array_keys($project['includes']);
- $url .= '&list=';
- $url .= rawurlencode(implode(',', $list));
- }
- return $url;
-}
-
-/**
- * Returns the base of the URL to fetch available update data for a project.
- *
- * @param $project
- * The array of project information from update_get_projects().
- *
- * @return
- * The base of the URL used for fetching available update data. This does
- * not include the path elements to specify a particular project, version,
- * site_key, etc.
- *
- * @see _update_build_fetch_url()
- */
-function _update_get_fetch_url_base($project) {
- return isset($project['info']['project status url']) ? $project['info']['project status url'] : variable_get('update_fetch_url', UPDATE_DEFAULT_URL);
-}
-
-/**
- * Performs any notifications that should be done once cron fetches new data.
- *
- * This method checks the status of the site using the new data and, depending
- * on the configuration of the site, notifies administrators via e-mail if there
- * are new releases or missing security updates.
- *
- * @see update_requirements()
- */
-function _update_cron_notify() {
- module_load_install('update');
- $status = update_requirements('runtime');
- $params = array();
- $notify_all = (variable_get('update_notification_threshold', 'all') == 'all');
- foreach (array('core', 'contrib') as $report_type) {
- $type = 'update_' . $report_type;
- if (isset($status[$type]['severity'])
- && ($status[$type]['severity'] == REQUIREMENT_ERROR || ($notify_all && $status[$type]['reason'] == UPDATE_NOT_CURRENT))) {
- $params[$report_type] = $status[$type]['reason'];
- }
- }
- if (!empty($params)) {
- $notify_list = variable_get('update_notify_emails', '');
- if (!empty($notify_list)) {
- $default_language = language_default();
- foreach ($notify_list as $target) {
- if ($target_user = user_load_by_mail($target)) {
- $target_language = user_preferred_language($target_user);
- }
- else {
- $target_language = $default_language;
- }
- $message = drupal_mail('update', 'status_notify', $target, $target_language, $params);
- // Track when the last mail was successfully sent to avoid sending
- // too many e-mails.
- if ($message['result']) {
- variable_set('update_last_email_notification', REQUEST_TIME);
- }
- }
- }
- }
-}
-
-/**
- * Parses the XML of the Drupal release history info files.
- *
- * @param $raw_xml
- * A raw XML string of available release data for a given project.
- *
- * @return
- * Array of parsed data about releases for a given project, or NULL if there
- * was an error parsing the string.
- */
-function update_parse_xml($raw_xml) {
- try {
- $xml = new SimpleXMLElement($raw_xml);
- }
- catch (Exception $e) {
- // SimpleXMLElement::__construct produces an E_WARNING error message for
- // each error found in the XML data and throws an exception if errors
- // were detected. Catch any exception and return failure (NULL).
- return;
- }
- // If there is no valid project data, the XML is invalid, so return failure.
- if (!isset($xml->short_name)) {
- return;
- }
- $short_name = (string) $xml->short_name;
- $data = array();
- foreach ($xml as $k => $v) {
- $data[$k] = (string) $v;
- }
- $data['releases'] = array();
- if (isset($xml->releases)) {
- foreach ($xml->releases->children() as $release) {
- $version = (string) $release->version;
- $data['releases'][$version] = array();
- foreach ($release->children() as $k => $v) {
- $data['releases'][$version][$k] = (string) $v;
- }
- $data['releases'][$version]['terms'] = array();
- if ($release->terms) {
- foreach ($release->terms->children() as $term) {
- if (!isset($data['releases'][$version]['terms'][(string) $term->name])) {
- $data['releases'][$version]['terms'][(string) $term->name] = array();
- }
- $data['releases'][$version]['terms'][(string) $term->name][] = (string) $term->value;
- }
- }
- }
- }
- return $data;
-}
diff --git a/modules/update/update.info b/modules/update/update.info
deleted file mode 100644
index 978470bc..00000000
--- a/modules/update/update.info
+++ /dev/null
@@ -1,13 +0,0 @@
-name = Update manager
-description = Checks for available updates, and can securely install or update modules and themes via a web interface.
-version = VERSION
-package = Core
-core = 7.x
-files[] = update.test
-configure = admin/reports/updates/settings
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/update/update.install b/modules/update/update.install
deleted file mode 100644
index baf49538..00000000
--- a/modules/update/update.install
+++ /dev/null
@@ -1,190 +0,0 @@
-createQueue();
-}
-
-/**
- * Implements hook_uninstall().
- */
-function update_uninstall() {
- // Clear any variables that might be in use
- $variables = array(
- 'update_check_frequency',
- 'update_fetch_url',
- 'update_last_check',
- 'update_last_email_notification',
- 'update_notification_threshold',
- 'update_notify_emails',
- 'update_max_fetch_attempts',
- 'update_max_fetch_time',
- );
- foreach ($variables as $variable) {
- variable_del($variable);
- }
- $queue = DrupalQueue::get('update_fetch_tasks');
- $queue->deleteQueue();
-}
-
-/**
- * Fills in the requirements array.
- *
- * This is shared for both core and contrib to generate the right elements in
- * the array for hook_requirements().
- *
- * @param $project
- * Array of information about the project we're testing as returned by
- * update_calculate_project_data().
- * @param $type
- * What kind of project this is ('core' or 'contrib').
- *
- * @return
- * An array to be included in the nested $requirements array.
- *
- * @see hook_requirements()
- * @see update_requirements()
- * @see update_calculate_project_data()
- */
-function _update_requirement_check($project, $type) {
- $requirement = array();
- if ($type == 'core') {
- $requirement['title'] = t('Drupal core update status');
- }
- else {
- $requirement['title'] = t('Module and theme update status');
- }
- $status = $project['status'];
- if ($status != UPDATE_CURRENT) {
- $requirement['reason'] = $status;
- $requirement['description'] = _update_message_text($type, $status, TRUE);
- $requirement['severity'] = REQUIREMENT_ERROR;
- }
- switch ($status) {
- case UPDATE_NOT_SECURE:
- $requirement_label = t('Not secure!');
- break;
- case UPDATE_REVOKED:
- $requirement_label = t('Revoked!');
- break;
- case UPDATE_NOT_SUPPORTED:
- $requirement_label = t('Unsupported release');
- break;
- case UPDATE_NOT_CURRENT:
- $requirement_label = t('Out of date');
- $requirement['severity'] = REQUIREMENT_WARNING;
- break;
- case UPDATE_UNKNOWN:
- case UPDATE_NOT_CHECKED:
- case UPDATE_NOT_FETCHED:
- $requirement_label = isset($project['reason']) ? $project['reason'] : t('Can not determine status');
- $requirement['severity'] = REQUIREMENT_WARNING;
- break;
- default:
- $requirement_label = t('Up to date');
- }
- if ($status != UPDATE_CURRENT && $type == 'core' && isset($project['recommended'])) {
- $requirement_label .= ' ' . t('(version @version available)', array('@version' => $project['recommended']));
- }
- $requirement['value'] = l($requirement_label, update_manager_access() ? 'admin/reports/updates/update' : 'admin/reports/updates');
- return $requirement;
-}
-
-/**
- * @addtogroup updates-6.x-to-7.x
- * @{
- */
-
-/**
- * Create a queue to store tasks for requests to fetch available update data.
- */
-function update_update_7000() {
- module_load_include('inc', 'system', 'system.queue');
- $queue = DrupalQueue::get('update_fetch_tasks');
- $queue->createQueue();
-}
-
-/**
- * Recreates cache_update table.
- *
- * Converts fields that hold serialized variables from text to blob.
- * Removes 'headers' column.
- */
-function update_update_7001() {
- $schema = system_schema_cache_7054();
-
- db_drop_table('cache_update');
- db_create_table('cache_update', $schema);
-}
-
-/**
- * @} End of "addtogroup updates-6.x-to-7.x".
- */
diff --git a/modules/update/update.manager.inc b/modules/update/update.manager.inc
deleted file mode 100644
index 85b587de..00000000
--- a/modules/update/update.manager.inc
+++ /dev/null
@@ -1,943 +0,0 @@
- t('There was a problem getting update information. Try again later.'),
- );
- return $form;
- }
-
- $form['#attached']['css'][] = drupal_get_path('module', 'update') . '/update.css';
-
- // This will be a nested array. The first key is the kind of project, which
- // can be either 'enabled', 'disabled', 'manual' (projects which require
- // manual updates, such as core). Then, each subarray is an array of
- // projects of that type, indexed by project short name, and containing an
- // array of data for cells in that project's row in the appropriate table.
- $projects = array();
-
- // This stores the actual download link we're going to update from for each
- // project in the form, regardless of if it's enabled or disabled.
- $form['project_downloads'] = array('#tree' => TRUE);
-
- module_load_include('inc', 'update', 'update.compare');
- $project_data = update_calculate_project_data($available);
- foreach ($project_data as $name => $project) {
- // Filter out projects which are up to date already.
- if ($project['status'] == UPDATE_CURRENT) {
- continue;
- }
- // The project name to display can vary based on the info we have.
- if (!empty($project['title'])) {
- if (!empty($project['link'])) {
- $project_name = l($project['title'], $project['link']);
- }
- else {
- $project_name = check_plain($project['title']);
- }
- }
- elseif (!empty($project['info']['name'])) {
- $project_name = check_plain($project['info']['name']);
- }
- else {
- $project_name = check_plain($name);
- }
- if ($project['project_type'] == 'theme' || $project['project_type'] == 'theme-disabled') {
- $project_name .= ' ' . t('(Theme)');
- }
-
- if (empty($project['recommended'])) {
- // If we don't know what to recommend they upgrade to, we should skip
- // the project entirely.
- continue;
- }
-
- $recommended_release = $project['releases'][$project['recommended']];
- $recommended_version = $recommended_release['version'] . ' ' . l(t('(Release notes)'), $recommended_release['release_link'], array('attributes' => array('title' => t('Release notes for @project_title', array('@project_title' => $project['title'])))));
- if ($recommended_release['version_major'] != $project['existing_major']) {
- $recommended_version .= '' . t('This update is a major version update which means that it may not be backwards compatible with your currently running version. It is recommended that you read the release notes and proceed at your own risk.') . '
';
- }
-
- // Create an entry for this project.
- $entry = array(
- 'title' => $project_name,
- 'installed_version' => $project['existing_version'],
- 'recommended_version' => $recommended_version,
- );
-
- switch ($project['status']) {
- case UPDATE_NOT_SECURE:
- case UPDATE_REVOKED:
- $entry['title'] .= ' ' . t('(Security update)');
- $entry['#weight'] = -2;
- $type = 'security';
- break;
-
- case UPDATE_NOT_SUPPORTED:
- $type = 'unsupported';
- $entry['title'] .= ' ' . t('(Unsupported)');
- $entry['#weight'] = -1;
- break;
-
- case UPDATE_UNKNOWN:
- case UPDATE_NOT_FETCHED:
- case UPDATE_NOT_CHECKED:
- case UPDATE_NOT_CURRENT:
- $type = 'recommended';
- break;
-
- default:
- // Jump out of the switch and onto the next project in foreach.
- continue 2;
- }
-
- $entry['#attributes'] = array('class' => array('update-' . $type));
-
- // Drupal core needs to be upgraded manually.
- $needs_manual = $project['project_type'] == 'core';
-
- if ($needs_manual) {
- // There are no checkboxes in the 'Manual updates' table so it will be
- // rendered by theme('table'), not theme('tableselect'). Since the data
- // formats are incompatible, we convert now to the format expected by
- // theme('table').
- unset($entry['#weight']);
- $attributes = $entry['#attributes'];
- unset($entry['#attributes']);
- $entry = array(
- 'data' => $entry,
- ) + $attributes;
- }
- else {
- $form['project_downloads'][$name] = array(
- '#type' => 'value',
- '#value' => $recommended_release['download_link'],
- );
- }
-
- // Based on what kind of project this is, save the entry into the
- // appropriate subarray.
- switch ($project['project_type']) {
- case 'core':
- // Core needs manual updates at this time.
- $projects['manual'][$name] = $entry;
- break;
-
- case 'module':
- case 'theme':
- $projects['enabled'][$name] = $entry;
- break;
-
- case 'module-disabled':
- case 'theme-disabled':
- $projects['disabled'][$name] = $entry;
- break;
- }
- }
-
- if (empty($projects)) {
- $form['message'] = array(
- '#markup' => t('All of your projects are up to date.'),
- );
- return $form;
- }
-
- $headers = array(
- 'title' => array(
- 'data' => t('Name'),
- 'class' => array('update-project-name'),
- ),
- 'installed_version' => t('Installed version'),
- 'recommended_version' => t('Recommended version'),
- );
-
- if (!empty($projects['enabled'])) {
- $form['projects'] = array(
- '#type' => 'tableselect',
- '#header' => $headers,
- '#options' => $projects['enabled'],
- );
- if (!empty($projects['disabled'])) {
- $form['projects']['#prefix'] = '' . t('Enabled') . ' ';
- }
- }
-
- if (!empty($projects['disabled'])) {
- $form['disabled_projects'] = array(
- '#type' => 'tableselect',
- '#header' => $headers,
- '#options' => $projects['disabled'],
- '#weight' => 1,
- '#prefix' => '' . t('Disabled') . ' ',
- );
- }
-
- // If either table has been printed yet, we need a submit button and to
- // validate the checkboxes.
- if (!empty($projects['enabled']) || !empty($projects['disabled'])) {
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Download these updates'),
- );
- $form['#validate'][] = 'update_manager_update_form_validate';
- }
-
- if (!empty($projects['manual'])) {
- $prefix = '' . t('Manual updates required') . ' ';
- $prefix .= '' . t('Updates of Drupal core are not supported at this time.') . '
';
- $form['manual_updates'] = array(
- '#type' => 'markup',
- '#markup' => theme('table', array('header' => $headers, 'rows' => $projects['manual'])),
- '#prefix' => $prefix,
- '#weight' => 120,
- );
- }
-
- return $form;
-}
-
-/**
- * Returns HTML for the first page in the process of updating projects.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @ingroup themeable
- */
-function theme_update_manager_update_form($variables) {
- $form = $variables['form'];
- $last = variable_get('update_last_check', 0);
- $output = theme('update_last_check', array('last' => $last));
- $output .= drupal_render_children($form);
- return $output;
-}
-
-/**
- * Form validation handler for update_manager_update_form().
- *
- * Ensures that at least one project is selected.
- *
- * @see update_manager_update_form_submit()
- */
-function update_manager_update_form_validate($form, &$form_state) {
- if (!empty($form_state['values']['projects'])) {
- $enabled = array_filter($form_state['values']['projects']);
- }
- if (!empty($form_state['values']['disabled_projects'])) {
- $disabled = array_filter($form_state['values']['disabled_projects']);
- }
- if (empty($enabled) && empty($disabled)) {
- form_set_error('projects', t('You must select at least one project to update.'));
- }
-}
-
-/**
- * Form submission handler for update_manager_update_form().
- *
- * Sets up a batch that downloads, extracts, and verifies the selected releases.
- *
- * @see update_manager_update_form_validate()
- */
-function update_manager_update_form_submit($form, &$form_state) {
- $projects = array();
- foreach (array('projects', 'disabled_projects') as $type) {
- if (!empty($form_state['values'][$type])) {
- $projects = array_merge($projects, array_keys(array_filter($form_state['values'][$type])));
- }
- }
- $operations = array();
- foreach ($projects as $project) {
- $operations[] = array(
- 'update_manager_batch_project_get',
- array(
- $project,
- $form_state['values']['project_downloads'][$project],
- ),
- );
- }
- $batch = array(
- 'title' => t('Downloading updates'),
- 'init_message' => t('Preparing to download selected updates'),
- 'operations' => $operations,
- 'finished' => 'update_manager_download_batch_finished',
- 'file' => drupal_get_path('module', 'update') . '/update.manager.inc',
- );
- batch_set($batch);
-}
-
-/**
- * Batch callback: Performs actions when the download batch is completed.
- *
- * @param $success
- * TRUE if the batch operation was successful, FALSE if there were errors.
- * @param $results
- * An associative array of results from the batch operation.
- */
-function update_manager_download_batch_finished($success, $results) {
- if (!empty($results['errors'])) {
- $error_list = array(
- 'title' => t('Downloading updates failed:'),
- 'items' => $results['errors'],
- );
- drupal_set_message(theme('item_list', $error_list), 'error');
- }
- elseif ($success) {
- drupal_set_message(t('Updates downloaded successfully.'));
- $_SESSION['update_manager_update_projects'] = $results['projects'];
- drupal_goto('admin/update/ready');
- }
- else {
- // Ideally we're catching all Exceptions, so they should never see this,
- // but just in case, we have to tell them something.
- drupal_set_message(t('Fatal error trying to download.'), 'error');
- }
-}
-
-/**
- * Form constructor for the update ready form.
- *
- * Build the form when the site is ready to update (after downloading).
- *
- * This form is an intermediary step in the automated update workflow. It is
- * presented to the site administrator after all the required updates have been
- * downloaded and verified. The point of this page is to encourage the user to
- * backup their site, give them the opportunity to put the site offline, and
- * then ask them to confirm that the update should continue. After this step,
- * the user is redirected to authorize.php to enter their file transfer
- * credentials and attempt to complete the update.
- *
- * @see update_manager_update_ready_form_submit()
- * @see update_menu()
- * @ingroup forms
- */
-function update_manager_update_ready_form($form, &$form_state) {
- if (!_update_manager_check_backends($form, 'update')) {
- return $form;
- }
-
- $form['backup'] = array(
- '#prefix' => '',
- '#markup' => t('Back up your database and site before you continue. Learn how .', array('@backup_url' => url('http://drupal.org/node/22281'))),
- '#suffix' => ' ',
- );
-
- $form['maintenance_mode'] = array(
- '#title' => t('Perform updates with site in maintenance mode (strongly recommended)'),
- '#type' => 'checkbox',
- '#default_value' => TRUE,
- );
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Continue'),
- );
-
- return $form;
-}
-
-/**
- * Form submission handler for update_manager_update_ready_form().
- *
- * If the site administrator requested that the site is put offline during the
- * update, do so now. Otherwise, pull information about all the required updates
- * out of the SESSION, figure out what Drupal\Core\Updater\Updater class is
- * needed for each one, generate an array of update operations to perform, and
- * hand it all off to system_authorized_init(), then redirect to authorize.php.
- *
- * @see update_authorize_run_update()
- * @see system_authorized_init()
- * @see system_authorized_get_url()
- */
-function update_manager_update_ready_form_submit($form, &$form_state) {
- // Store maintenance_mode setting so we can restore it when done.
- $_SESSION['maintenance_mode'] = variable_get('maintenance_mode', FALSE);
- if ($form_state['values']['maintenance_mode'] == TRUE) {
- variable_set('maintenance_mode', TRUE);
- }
-
- if (!empty($_SESSION['update_manager_update_projects'])) {
- // Make sure the Updater registry is loaded.
- drupal_get_updaters();
-
- $updates = array();
- $directory = _update_manager_extract_directory();
-
- $projects = $_SESSION['update_manager_update_projects'];
- unset($_SESSION['update_manager_update_projects']);
-
- foreach ($projects as $project => $url) {
- $project_location = $directory . '/' . $project;
- $updater = Updater::factory($project_location);
- $project_real_location = drupal_realpath($project_location);
- $updates[] = array(
- 'project' => $project,
- 'updater_name' => get_class($updater),
- 'local_url' => $project_real_location,
- );
- }
-
- // If the owner of the last directory we extracted is the same as the
- // owner of our configuration directory (e.g. sites/default) where we're
- // trying to install the code, there's no need to prompt for FTP/SSH
- // credentials. Instead, we instantiate a FileTransferLocal and invoke
- // update_authorize_run_update() directly.
- if (fileowner($project_real_location) == fileowner(conf_path())) {
- module_load_include('inc', 'update', 'update.authorize');
- $filetransfer = new FileTransferLocal(DRUPAL_ROOT);
- update_authorize_run_update($filetransfer, $updates);
- }
- // Otherwise, go through the regular workflow to prompt for FTP/SSH
- // credentials and invoke update_authorize_run_update() indirectly with
- // whatever FileTransfer object authorize.php creates for us.
- else {
- system_authorized_init('update_authorize_run_update', drupal_get_path('module', 'update') . '/update.authorize.inc', array($updates), t('Update manager'));
- $form_state['redirect'] = system_authorized_get_url();
- }
- }
-}
-
-/**
- * @} End of "defgroup update_manager_update".
- */
-
-/**
- * @defgroup update_manager_install Update Manager module: install
- * @{
- * Update Manager module functionality for installing new code.
- *
- * Provides a user interface to install new code.
- */
-
-/**
- * Form constructor for the install form of the Update Manager module.
- *
- * This presents a place to enter a URL or upload an archive file to use to
- * install a new module or theme.
- *
- * @param $context
- * String representing the context from which we're trying to install.
- * Allowed values are 'module', 'theme', and 'report'.
- *
- * @see update_manager_install_form_validate()
- * @see update_manager_install_form_submit()
- * @see update_menu()
- * @ingroup forms
- */
-function update_manager_install_form($form, &$form_state, $context) {
- if (!_update_manager_check_backends($form, 'install')) {
- return $form;
- }
-
- $form['help_text'] = array(
- '#prefix' => '',
- '#markup' => t('You can find modules and themes on drupal.org . The following file extensions are supported: %extensions.', array(
- '@module_url' => 'http://drupal.org/project/modules',
- '@theme_url' => 'http://drupal.org/project/themes',
- '@drupal_org_url' => 'http://drupal.org',
- '%extensions' => archiver_get_extensions(),
- )),
- '#suffix' => '
',
- );
-
- $form['project_url'] = array(
- '#type' => 'textfield',
- '#title' => t('Install from a URL'),
- '#description' => t('For example: %url', array('%url' => 'http://ftp.drupal.org/files/projects/name.tar.gz')),
- );
-
- $form['information'] = array(
- '#prefix' => '',
- '#markup' => t('Or'),
- '#suffix' => ' ',
- );
-
- $form['project_upload'] = array(
- '#type' => 'file',
- '#title' => t('Upload a module or theme archive to install'),
- '#description' => t('For example: %filename from your local computer', array('%filename' => 'name.tar.gz')),
- );
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Install'),
- );
-
- return $form;
-}
-
-/**
- * Checks for file transfer backends and prepares a form fragment about them.
- *
- * @param array $form
- * Reference to the form array we're building.
- * @param string $operation
- * The update manager operation we're in the middle of. Can be either 'update'
- * or 'install'. Use to provide operation-specific interface text.
- *
- * @return
- * TRUE if the update manager should continue to the next step in the
- * workflow, or FALSE if we've hit a fatal configuration and must halt the
- * workflow.
- */
-function _update_manager_check_backends(&$form, $operation) {
- // If file transfers will be performed locally, we do not need to display any
- // warnings or notices to the user and should automatically continue the
- // workflow, since we won't be using a FileTransfer backend that requires
- // user input or a specific server configuration.
- if (update_manager_local_transfers_allowed()) {
- return TRUE;
- }
-
- // Otherwise, show the available backends.
- $form['available_backends'] = array(
- '#prefix' => '',
- '#suffix' => '
',
- );
-
- $available_backends = drupal_get_filetransfer_info();
- if (empty($available_backends)) {
- if ($operation == 'update') {
- $form['available_backends']['#markup'] = t('Your server does not support updating modules and themes from this interface. Instead, update modules and themes by uploading the new versions directly to the server, as described in the handbook .', array('@handbook_url' => 'http://drupal.org/getting-started/install-contrib'));
- }
- else {
- $form['available_backends']['#markup'] = t('Your server does not support installing modules and themes from this interface. Instead, install modules and themes by uploading them directly to the server, as described in the handbook .', array('@handbook_url' => 'http://drupal.org/getting-started/install-contrib'));
- }
- return FALSE;
- }
-
- $backend_names = array();
- foreach ($available_backends as $backend) {
- $backend_names[] = $backend['title'];
- }
- if ($operation == 'update') {
- $form['available_backends']['#markup'] = format_plural(
- count($available_backends),
- 'Updating modules and themes requires @backends access to your server. See the handbook for other update methods.',
- 'Updating modules and themes requires access to your server via one of the following methods: @backends . See the handbook for other update methods.',
- array(
- '@backends' => implode(', ', $backend_names),
- '@handbook_url' => 'http://drupal.org/getting-started/install-contrib',
- ));
- }
- else {
- $form['available_backends']['#markup'] = format_plural(
- count($available_backends),
- 'Installing modules and themes requires @backends access to your server. See the handbook for other installation methods.',
- 'Installing modules and themes requires access to your server via one of the following methods: @backends . See the handbook for other installation methods.',
- array(
- '@backends' => implode(', ', $backend_names),
- '@handbook_url' => 'http://drupal.org/getting-started/install-contrib',
- ));
- }
- return TRUE;
-}
-
-/**
- * Form validation handler for update_manager_install_form().
- *
- * @see update_manager_install_form_submit()
- */
-function update_manager_install_form_validate($form, &$form_state) {
- if (!($form_state['values']['project_url'] XOR !empty($_FILES['files']['name']['project_upload']))) {
- form_set_error('project_url', t('You must either provide a URL or upload an archive file to install.'));
- }
-
- if ($form_state['values']['project_url']) {
- if (!valid_url($form_state['values']['project_url'], TRUE)) {
- form_set_error('project_url', t('The provided URL is invalid.'));
- }
- }
-}
-
-/**
- * Form submission handler for update_manager_install_form().
- *
- * Either downloads the file specified in the URL to a temporary cache, or
- * uploads the file attached to the form, then attempts to extract the archive
- * into a temporary location and verify it. Instantiate the appropriate
- * Updater class for this project and make sure it is not already installed in
- * the live webroot. If everything is successful, setup an operation to run
- * via authorize.php which will copy the extracted files from the temporary
- * location into the live site.
- *
- * @see update_manager_install_form_validate()
- * @see update_authorize_run_install()
- * @see system_authorized_init()
- * @see system_authorized_get_url()
- */
-function update_manager_install_form_submit($form, &$form_state) {
- if ($form_state['values']['project_url']) {
- $field = 'project_url';
- $local_cache = update_manager_file_get($form_state['values']['project_url']);
- if (!$local_cache) {
- form_set_error($field, t('Unable to retrieve Drupal project from %url.', array('%url' => $form_state['values']['project_url'])));
- return;
- }
- }
- elseif ($_FILES['files']['name']['project_upload']) {
- $validators = array('file_validate_extensions' => array(archiver_get_extensions()));
- $field = 'project_upload';
- if (!($finfo = file_save_upload($field, $validators, NULL, FILE_EXISTS_REPLACE))) {
- // Failed to upload the file. file_save_upload() calls form_set_error() on
- // failure.
- return;
- }
- $local_cache = $finfo->uri;
- }
-
- $directory = _update_manager_extract_directory();
- try {
- $archive = update_manager_archive_extract($local_cache, $directory);
- }
- catch (Exception $e) {
- form_set_error($field, $e->getMessage());
- return;
- }
-
- $files = $archive->listContents();
- if (!$files) {
- form_set_error($field, t('Provided archive contains no files.'));
- return;
- }
-
- // Unfortunately, we can only use the directory name to determine the project
- // name. Some archivers list the first file as the directory (i.e., MODULE/)
- // and others list an actual file (i.e., MODULE/README.TXT).
- $project = strtok($files[0], '/\\');
-
- $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
- if (!empty($archive_errors)) {
- form_set_error($field, array_shift($archive_errors));
- // @todo: Fix me in D8: We need a way to set multiple errors on the same
- // form element and have all of them appear!
- if (!empty($archive_errors)) {
- foreach ($archive_errors as $error) {
- drupal_set_message($error, 'error');
- }
- }
- return;
- }
-
- // Make sure the Updater registry is loaded.
- drupal_get_updaters();
-
- $project_location = $directory . '/' . $project;
- try {
- $updater = Updater::factory($project_location);
- }
- catch (Exception $e) {
- form_set_error($field, $e->getMessage());
- return;
- }
-
- try {
- $project_title = Updater::getProjectTitle($project_location);
- }
- catch (Exception $e) {
- form_set_error($field, $e->getMessage());
- return;
- }
-
- if (!$project_title) {
- form_set_error($field, t('Unable to determine %project name.', array('%project' => $project)));
- }
-
- if ($updater->isInstalled()) {
- form_set_error($field, t('%project is already installed.', array('%project' => $project_title)));
- return;
- }
-
- $project_real_location = drupal_realpath($project_location);
- $arguments = array(
- 'project' => $project,
- 'updater_name' => get_class($updater),
- 'local_url' => $project_real_location,
- );
-
- // If the owner of the directory we extracted is the same as the
- // owner of our configuration directory (e.g. sites/default) where we're
- // trying to install the code, there's no need to prompt for FTP/SSH
- // credentials. Instead, we instantiate a FileTransferLocal and invoke
- // update_authorize_run_install() directly.
- if (fileowner($project_real_location) == fileowner(conf_path())) {
- module_load_include('inc', 'update', 'update.authorize');
- $filetransfer = new FileTransferLocal(DRUPAL_ROOT);
- call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
- }
- // Otherwise, go through the regular workflow to prompt for FTP/SSH
- // credentials and invoke update_authorize_run_install() indirectly with
- // whatever FileTransfer object authorize.php creates for us.
- else {
- system_authorized_init('update_authorize_run_install', drupal_get_path('module', 'update') . '/update.authorize.inc', $arguments, t('Update manager'));
- $form_state['redirect'] = system_authorized_get_url();
- }
-}
-
-/**
- * @} End of "defgroup update_manager_install".
- */
-
-/**
- * @defgroup update_manager_file Update Manager module: file management
- * @{
- * Update Manager module file management functions.
- *
- * These functions are used by the update manager to copy, extract, and verify
- * archive files.
- */
-
-/**
- * Unpacks a downloaded archive file.
- *
- * @param string $file
- * The filename of the archive you wish to extract.
- * @param string $directory
- * The directory you wish to extract the archive into.
- *
- * @return Archiver
- * The Archiver object used to extract the archive.
- *
- * @throws Exception
- */
-function update_manager_archive_extract($file, $directory) {
- $archiver = archiver_get_archiver($file);
- if (!$archiver) {
- throw new Exception(t('Cannot extract %file, not a valid archive.', array ('%file' => $file)));
- }
-
- // Remove the directory if it exists, otherwise it might contain a mixture of
- // old files mixed with the new files (e.g. in cases where files were removed
- // from a later release).
- $files = $archiver->listContents();
-
- // Unfortunately, we can only use the directory name to determine the project
- // name. Some archivers list the first file as the directory (i.e., MODULE/)
- // and others list an actual file (i.e., MODULE/README.TXT).
- $project = strtok($files[0], '/\\');
-
- $extract_location = $directory . '/' . $project;
- if (file_exists($extract_location)) {
- file_unmanaged_delete_recursive($extract_location);
- }
-
- $archiver->extract($directory);
- return $archiver;
-}
-
-/**
- * Verifies an archive after it has been downloaded and extracted.
- *
- * This function is responsible for invoking hook_verify_update_archive().
- *
- * @param string $project
- * The short name of the project to download.
- * @param string $archive_file
- * The filename of the unextracted archive.
- * @param string $directory
- * The directory that the archive was extracted into.
- *
- * @return array
- * An array of error messages to display if the archive was invalid. If there
- * are no errors, it will be an empty array.
- */
-function update_manager_archive_verify($project, $archive_file, $directory) {
- return module_invoke_all('verify_update_archive', $project, $archive_file, $directory);
-}
-
-/**
- * Copies a file from the specified URL to the temporary directory for updates.
- *
- * Returns the local path if the file has already been downloaded.
- *
- * @param $url
- * The URL of the file on the server.
- *
- * @return string
- * Path to local file.
- */
-function update_manager_file_get($url) {
- $parsed_url = parse_url($url);
- $remote_schemes = array('http', 'https', 'ftp', 'ftps', 'smb', 'nfs');
- if (!in_array($parsed_url['scheme'], $remote_schemes)) {
- // This is a local file, just return the path.
- return drupal_realpath($url);
- }
-
- // Check the cache and download the file if needed.
- $cache_directory = _update_manager_cache_directory();
- $local = $cache_directory . '/' . drupal_basename($parsed_url['path']);
-
- if (!file_exists($local) || update_delete_file_if_stale($local)) {
- return system_retrieve_file($url, $local, FALSE, FILE_EXISTS_REPLACE);
- }
- else {
- return $local;
- }
-}
-
-/**
- * Batch callback: Downloads, unpacks, and verifies a project.
- *
- * This function assumes that the provided URL points to a file archive of some
- * sort. The URL can have any scheme that we have a file stream wrapper to
- * support. The file is downloaded to a local cache.
- *
- * @param string $project
- * The short name of the project to download.
- * @param string $url
- * The URL to download a specific project release archive file.
- * @param array $context
- * Reference to an array used for Batch API storage.
- *
- * @see update_manager_download_page()
- */
-function update_manager_batch_project_get($project, $url, &$context) {
- // This is here to show the user that we are in the process of downloading.
- if (!isset($context['sandbox']['started'])) {
- $context['sandbox']['started'] = TRUE;
- $context['message'] = t('Downloading %project', array('%project' => $project));
- $context['finished'] = 0;
- return;
- }
-
- // Actually try to download the file.
- if (!($local_cache = update_manager_file_get($url))) {
- $context['results']['errors'][$project] = t('Failed to download %project from %url', array('%project' => $project, '%url' => $url));
- return;
- }
-
- // Extract it.
- $extract_directory = _update_manager_extract_directory();
- try {
- update_manager_archive_extract($local_cache, $extract_directory);
- }
- catch (Exception $e) {
- $context['results']['errors'][$project] = $e->getMessage();
- return;
- }
-
- // Verify it.
- $archive_errors = update_manager_archive_verify($project, $local_cache, $extract_directory);
- if (!empty($archive_errors)) {
- // We just need to make sure our array keys don't collide, so use the
- // numeric keys from the $archive_errors array.
- foreach ($archive_errors as $key => $error) {
- $context['results']['errors']["$project-$key"] = $error;
- }
- return;
- }
-
- // Yay, success.
- $context['results']['projects'][$project] = $url;
- $context['finished'] = 1;
-}
-
-/**
- * Determines if file transfers will be performed locally.
- *
- * If the server is configured such that webserver-created files have the same
- * owner as the configuration directory (e.g., sites/default) where new code
- * will eventually be installed, the update manager can transfer files entirely
- * locally, without changing their ownership (in other words, without prompting
- * the user for FTP, SSH or other credentials).
- *
- * This server configuration is an inherent security weakness because it allows
- * a malicious webserver process to append arbitrary PHP code and then execute
- * it. However, it is supported here because it is a common configuration on
- * shared hosting, and there is nothing Drupal can do to prevent it.
- *
- * @return
- * TRUE if local file transfers are allowed on this server, or FALSE if not.
- *
- * @see update_manager_update_ready_form_submit()
- * @see update_manager_install_form_submit()
- * @see install_check_requirements()
- */
-function update_manager_local_transfers_allowed() {
- // Compare the owner of a webserver-created temporary file to the owner of
- // the configuration directory to determine if local transfers will be
- // allowed.
- $temporary_file = drupal_tempnam('temporary://', 'update_');
- $local_transfers_allowed = fileowner($temporary_file) === fileowner(conf_path());
-
- // Clean up. If this fails, we can ignore it (since this is just a temporary
- // file anyway).
- @drupal_unlink($temporary_file);
-
- return $local_transfers_allowed;
-}
-
-/**
- * @} End of "defgroup update_manager_file".
- */
diff --git a/modules/update/update.module b/modules/update/update.module
deleted file mode 100644
index d5728be3..00000000
--- a/modules/update/update.module
+++ /dev/null
@@ -1,993 +0,0 @@
-' . t('Here you can find information about available updates for your installed modules and themes. Note that each module or theme is part of a "project", which may or may not have the same name, and might include multiple modules or themes within it.') . '';
-
- case 'admin/help#update':
- $output = '';
- $output .= '' . t('About') . ' ';
- $output .= '' . t("The Update manager module periodically checks for new versions of your site's software (including contributed modules and themes), and alerts administrators to available updates. In order to provide update information, anonymous usage statistics are sent to Drupal.org. If desired, you may disable the Update manager module from the Module administration page . For more information, see the online handbook entry for Update manager module .", array('@update' => 'http://drupal.org/documentation/modules/update', '@modules' => url('admin/modules'))) . '
';
- // Only explain the Update manager if it has not been disabled.
- if (update_manager_access()) {
- $output .= '' . t('The Update manager also allows administrators to update and install modules and themes through the administration interface.') . '
';
- }
- $output .= '' . t('Uses') . ' ';
- $output .= '';
- $output .= '' . t('Checking for available updates') . ' ';
- $output .= '' . t('A report of available updates will alert you when new releases are available for download. You may configure options for the frequency for checking updates (which are performed during cron runs) and e-mail notifications at the Update manager settings page.', array('@update-report' => url('admin/reports/updates'), '@cron' => 'http://drupal.org/cron', '@update-settings' => url('admin/reports/updates/settings'))) . ' ';
- // Only explain the Update manager if it has not been disabled.
- if (update_manager_access()) {
- $output .= '' . t('Performing updates through the user interface') . ' ';
- $output .= '' . t('The Update manager module allows administrators to perform updates directly through the administration interface. At the top of the modules and themes pages you will see a link to update to new releases. This will direct you to the update page where you see a listing of all the missing updates and confirm which ones you want to upgrade. From there, you are prompted for your FTP/SSH password, which then transfers the files into your Drupal installation, overwriting your old files. More detailed instructions can be found in the online handbook .', array('@modules_page' => url('admin/modules'), '@themes_page' => url('admin/appearance'), '@update-page' => url('admin/reports/updates/update'), '@update' => 'http://drupal.org/documentation/modules/update')) . ' ';
- $output .= '' . t('Installing new modules and themes through the user interface') . ' ';
- $output .= '' . t('You can also install new modules and themes in the same fashion, through the install page , or by clicking the Install new module/theme link at the top of the modules and themes pages. In this case, you are prompted to provide either the URL to the download, or to upload a packaged release file from your local computer.', array('@modules_page' => url('admin/modules'), '@themes_page' => url('admin/appearance'), '@install' => url('admin/reports/updates/install'))) . ' ';
- }
- $output .= ' ';
- return $output;
- }
-}
-
-/**
- * Implements hook_init().
- */
-function update_init() {
- if (arg(0) == 'admin' && user_access('administer site configuration')) {
- switch ($_GET['q']) {
- // These pages don't need additional nagging.
- case 'admin/appearance/update':
- case 'admin/appearance/install':
- case 'admin/modules/update':
- case 'admin/modules/install':
- case 'admin/reports/updates':
- case 'admin/reports/updates/update':
- case 'admin/reports/updates/install':
- case 'admin/reports/updates/settings':
- case 'admin/reports/status':
- case 'admin/update/ready':
- return;
-
- // If we are on the appearance or modules list, display a detailed report
- // of the update status.
- case 'admin/appearance':
- case 'admin/modules':
- $verbose = TRUE;
- break;
-
- }
- module_load_install('update');
- $status = update_requirements('runtime');
- foreach (array('core', 'contrib') as $report_type) {
- $type = 'update_' . $report_type;
- if (!empty($verbose)) {
- if (isset($status[$type]['severity'])) {
- if ($status[$type]['severity'] == REQUIREMENT_ERROR) {
- drupal_set_message($status[$type]['description'], 'error', FALSE);
- }
- elseif ($status[$type]['severity'] == REQUIREMENT_WARNING) {
- drupal_set_message($status[$type]['description'], 'warning', FALSE);
- }
- }
- }
- // Otherwise, if we're on *any* admin page and there's a security
- // update missing, print an error message about it.
- else {
- if (isset($status[$type])
- && isset($status[$type]['reason'])
- && $status[$type]['reason'] === UPDATE_NOT_SECURE) {
- drupal_set_message($status[$type]['description'], 'error', FALSE);
- }
- }
- }
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function update_menu() {
- $items = array();
-
- $items['admin/reports/updates'] = array(
- 'title' => 'Available updates',
- 'description' => 'Get a status report about available updates for your installed modules and themes.',
- 'page callback' => 'update_status',
- 'access arguments' => array('administer site configuration'),
- 'weight' => -50,
- 'file' => 'update.report.inc',
- );
- $items['admin/reports/updates/list'] = array(
- 'title' => 'List',
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/reports/updates/settings'] = array(
- 'title' => 'Settings',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('update_settings'),
- 'access arguments' => array('administer site configuration'),
- 'file' => 'update.settings.inc',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 50,
- );
- $items['admin/reports/updates/check'] = array(
- 'title' => 'Manual update check',
- 'page callback' => 'update_manual_status',
- 'access arguments' => array('administer site configuration'),
- 'type' => MENU_CALLBACK,
- 'file' => 'update.fetch.inc',
- );
-
- // We want action links for updating projects at a few different locations:
- // both the module and theme administration pages, and on the available
- // updates report itself. The menu items will be mostly identical, except the
- // paths and titles, so we just define them in a loop. We pass in a string
- // indicating what context we're entering the action from, so that can
- // customize the appearance as needed.
- $paths = array(
- 'report' => 'admin/reports/updates',
- 'module' => 'admin/modules',
- 'theme' => 'admin/appearance',
- );
- foreach ($paths as $context => $path) {
- $items[$path . '/install'] = array(
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('update_manager_install_form', $context),
- 'access callback' => 'update_manager_access',
- 'access arguments' => array(),
- 'weight' => 25,
- 'type' => MENU_LOCAL_ACTION,
- 'file' => 'update.manager.inc',
- );
- $items[$path . '/update'] = array(
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('update_manager_update_form', $context),
- 'access callback' => 'update_manager_access',
- 'access arguments' => array(),
- 'weight' => 10,
- 'title' => 'Update',
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'update.manager.inc',
- );
- }
- // Customize the titles of the action links depending on where they appear.
- // We use += array() to let the translation extractor find these menu titles.
- $items['admin/reports/updates/install'] += array('title' => 'Install new module or theme');
- $items['admin/modules/install'] += array('title' => 'Install new module');
- $items['admin/appearance/install'] += array('title' => 'Install new theme');
-
- // Menu callback used for the confirmation page after all the releases
- // have been downloaded, asking you to backup before installing updates.
- $items['admin/update/ready'] = array(
- 'title' => 'Ready to update',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('update_manager_update_ready_form'),
- 'access callback' => 'update_manager_access',
- 'access arguments' => array(),
- 'type' => MENU_CALLBACK,
- 'file' => 'update.manager.inc',
- );
-
- return $items;
-}
-
-/**
- * Access callback: Resolves if the current user can access updater menu items.
- *
- * It both enforces the 'administer software updates' permission and the global
- * kill switch for the authorize.php script.
- *
- * @return
- * TRUE if the current user can access the updater menu items; FALSE
- * otherwise.
- *
- * @see update_menu()
- */
-function update_manager_access() {
- return variable_get('allow_authorize_operations', TRUE) && user_access('administer software updates');
-}
-
-/**
- * Implements hook_theme().
- */
-function update_theme() {
- return array(
- 'update_manager_update_form' => array(
- 'render element' => 'form',
- 'file' => 'update.manager.inc',
- ),
- 'update_last_check' => array(
- 'variables' => array('last' => NULL),
- ),
- 'update_report' => array(
- 'variables' => array('data' => NULL),
- ),
- 'update_version' => array(
- 'variables' => array('version' => NULL, 'tag' => NULL, 'class' => array()),
- ),
- 'update_status_label' => array(
- 'variables' => array('status' => NULL),
- ),
- );
-}
-
-/**
- * Implements hook_cron().
- */
-function update_cron() {
- $frequency = variable_get('update_check_frequency', 1);
- $interval = 60 * 60 * 24 * $frequency;
- if ((REQUEST_TIME - variable_get('update_last_check', 0)) > $interval) {
- // If the configured update interval has elapsed, we want to invalidate
- // the cached data for all projects, attempt to re-fetch, and trigger any
- // configured notifications about the new status.
- update_refresh();
- update_fetch_data();
- }
- else {
- // Otherwise, see if any individual projects are now stale or still
- // missing data, and if so, try to fetch the data.
- update_get_available(TRUE);
- }
- if ((REQUEST_TIME - variable_get('update_last_email_notification', 0)) > $interval) {
- // If configured time between notifications elapsed, send email about
- // updates possibly available.
- module_load_include('inc', 'update', 'update.fetch');
- _update_cron_notify();
- }
-
- // Clear garbage from disk.
- update_clear_update_disk_cache();
-}
-
-/**
- * Implements hook_themes_enabled().
- *
- * If themes are enabled, we invalidate the cache of available updates.
- */
-function update_themes_enabled($themes) {
- // Clear all update module caches.
- _update_cache_clear();
-}
-
-/**
- * Implements hook_themes_disabled().
- *
- * If themes are disabled, we invalidate the cache of available updates.
- */
-function update_themes_disabled($themes) {
- // Clear all update module caches.
- _update_cache_clear();
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for system_modules().
- *
- * Adds a form submission handler to the system modules form, so that if a site
- * admin saves the form, we invalidate the cache of available updates.
- *
- * @see _update_cache_clear()
- */
-function update_form_system_modules_alter(&$form, $form_state) {
- $form['#submit'][] = 'update_cache_clear_submit';
-}
-
-/**
- * Form submission handler for system_modules().
- *
- * @see update_form_system_modules_alter()
- */
-function update_cache_clear_submit($form, &$form_state) {
- // Clear all update module caches.
- _update_cache_clear();
-}
-
-/**
- * Returns a warning message when there is no data about available updates.
- */
-function _update_no_data() {
- $destination = drupal_get_destination();
- return t('No update information available. Run cron or check manually .', array(
- '@run_cron' => url('admin/reports/status/run-cron', array('query' => $destination)),
- '@check_manually' => url('admin/reports/updates/check', array('query' => $destination)),
- ));
-}
-
-/**
- * Tries to get update information from cache and refreshes it when necessary.
- *
- * In addition to checking the cache lifetime, this function also ensures that
- * there are no .info files for enabled modules or themes that have a newer
- * modification timestamp than the last time we checked for available update
- * data. If any .info file was modified, it almost certainly means a new version
- * of something was installed. Without fresh available update data, the logic in
- * update_calculate_project_data() will be wrong and produce confusing, bogus
- * results.
- *
- * @param $refresh
- * (optional) Boolean to indicate if this method should refresh the cache
- * automatically if there's no data. Defaults to FALSE.
- *
- * @return
- * Array of data about available releases, keyed by project shortname.
- *
- * @see update_refresh()
- * @see update_get_projects()
- */
-function update_get_available($refresh = FALSE) {
- module_load_include('inc', 'update', 'update.compare');
- $needs_refresh = FALSE;
-
- // Grab whatever data we currently have cached in the DB.
- $available = _update_get_cached_available_releases();
- $num_avail = count($available);
-
- $projects = update_get_projects();
- foreach ($projects as $key => $project) {
- // If there's no data at all, we clearly need to fetch some.
- if (empty($available[$key])) {
- update_create_fetch_task($project);
- $needs_refresh = TRUE;
- continue;
- }
-
- // See if the .info file is newer than the last time we checked for data,
- // and if so, mark this project's data as needing to be re-fetched. Any
- // time an admin upgrades their local installation, the .info file will
- // be changed, so this is the only way we can be sure we're not showing
- // bogus information right after they upgrade.
- if ($project['info']['_info_file_ctime'] > $available[$key]['last_fetch']) {
- $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
- }
-
- // If we have project data but no release data, we need to fetch. This
- // can be triggered when we fail to contact a release history server.
- if (empty($available[$key]['releases'])) {
- $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
- }
-
- // If we think this project needs to fetch, actually create the task now
- // and remember that we think we're missing some data.
- if (!empty($available[$key]['fetch_status']) && $available[$key]['fetch_status'] == UPDATE_FETCH_PENDING) {
- update_create_fetch_task($project);
- $needs_refresh = TRUE;
- }
- }
-
- if ($needs_refresh && $refresh) {
- // Attempt to drain the queue of fetch tasks.
- update_fetch_data();
- // After processing the queue, we've (hopefully) got better data, so pull
- // the latest from the cache again and use that directly.
- $available = _update_get_cached_available_releases();
- }
-
- return $available;
-}
-
-/**
- * Creates a new fetch task after loading the necessary include file.
- *
- * @param $project
- * Associative array of information about a project. See update_get_projects()
- * for the keys used.
- *
- * @see _update_create_fetch_task()
- */
-function update_create_fetch_task($project) {
- module_load_include('inc', 'update', 'update.fetch');
- return _update_create_fetch_task($project);
-}
-
-/**
- * Refreshes the release data after loading the necessary include file.
- *
- * @see _update_refresh()
- */
-function update_refresh() {
- module_load_include('inc', 'update', 'update.fetch');
- return _update_refresh();
-}
-
-/**
- * Attempts to fetch update data after loading the necessary include file.
- *
- * @see _update_fetch_data()
- */
-function update_fetch_data() {
- module_load_include('inc', 'update', 'update.fetch');
- return _update_fetch_data();
-}
-
-/**
- * Returns all currently cached data about available releases for all projects.
- *
- * @return
- * Array of data about available releases, keyed by project shortname.
- */
-function _update_get_cached_available_releases() {
- $data = array();
- $cache_items = _update_get_cache_multiple('available_releases');
- foreach ($cache_items as $cid => $cache) {
- $cache->data['last_fetch'] = $cache->created;
- if ($cache->expire < REQUEST_TIME) {
- $cache->data['fetch_status'] = UPDATE_FETCH_PENDING;
- }
- // The project shortname is embedded in the cache ID, even if there's no
- // data for this project in the DB at all, so use that for the indexes in
- // the array.
- $parts = explode('::', $cid, 2);
- $data[$parts[1]] = $cache->data;
- }
- return $data;
-}
-
-/**
- * Implements hook_mail().
- *
- * Constructs the e-mail notification message when the site is out of date.
- *
- * @param $key
- * Unique key to indicate what message to build, always 'status_notify'.
- * @param $message
- * Reference to the message array being built.
- * @param $params
- * Array of parameters to indicate what kind of text to include in the message
- * body. This is a keyed array of message type ('core' or 'contrib') as the
- * keys, and the status reason constant (UPDATE_NOT_SECURE, etc) for the
- * values.
- *
- * @see drupal_mail()
- * @see _update_cron_notify()
- * @see _update_message_text()
- */
-function update_mail($key, &$message, $params) {
- $language = $message['language'];
- $langcode = $language->language;
- $message['subject'] .= t('New release(s) available for !site_name', array('!site_name' => variable_get('site_name', 'Drupal')), array('langcode' => $langcode));
- foreach ($params as $msg_type => $msg_reason) {
- $message['body'][] = _update_message_text($msg_type, $msg_reason, FALSE, $language);
- }
- $message['body'][] = t('See the available updates page for more information:', array(), array('langcode' => $langcode)) . "\n" . url('admin/reports/updates', array('absolute' => TRUE, 'language' => $language));
- if (update_manager_access()) {
- $message['body'][] = t('You can automatically install your missing updates using the Update manager:', array(), array('langcode' => $langcode)) . "\n" . url('admin/reports/updates/update', array('absolute' => TRUE, 'language' => $language));
- }
- $settings_url = url('admin/reports/updates/settings', array('absolute' => TRUE));
- if (variable_get('update_notification_threshold', 'all') == 'all') {
- $message['body'][] = t('Your site is currently configured to send these emails when any updates are available. To get notified only for security updates, !url.', array('!url' => $settings_url));
- }
- else {
- $message['body'][] = t('Your site is currently configured to send these emails only when security updates are available. To get notified for any available updates, !url.', array('!url' => $settings_url));
- }
-}
-
-/**
- * Returns the appropriate message text when site is out of date or not secure.
- *
- * These error messages are shared by both update_requirements() for the
- * site-wide status report at admin/reports/status and in the body of the
- * notification e-mail messages generated by update_cron().
- *
- * @param $msg_type
- * String to indicate what kind of message to generate. Can be either 'core'
- * or 'contrib'.
- * @param $msg_reason
- * Integer constant specifying why message is generated.
- * @param $report_link
- * (optional) Boolean that controls if a link to the updates report should be
- * added. Defaults to FALSE.
- * @param $language
- * (optional) A language object to use. Defaults to NULL.
- *
- * @return
- * The properly translated error message for the given key.
- */
-function _update_message_text($msg_type, $msg_reason, $report_link = FALSE, $language = NULL) {
- $langcode = isset($language) ? $language->language : NULL;
- $text = '';
- switch ($msg_reason) {
- case UPDATE_NOT_SECURE:
- if ($msg_type == 'core') {
- $text = t('There is a security update available for your version of Drupal. To ensure the security of your server, you should update immediately!', array(), array('langcode' => $langcode));
- }
- else {
- $text = t('There are security updates available for one or more of your modules or themes. To ensure the security of your server, you should update immediately!', array(), array('langcode' => $langcode));
- }
- break;
-
- case UPDATE_REVOKED:
- if ($msg_type == 'core') {
- $text = t('Your version of Drupal has been revoked and is no longer available for download. Upgrading is strongly recommended!', array(), array('langcode' => $langcode));
- }
- else {
- $text = t('The installed version of at least one of your modules or themes has been revoked and is no longer available for download. Upgrading or disabling is strongly recommended!', array(), array('langcode' => $langcode));
- }
- break;
-
- case UPDATE_NOT_SUPPORTED:
- if ($msg_type == 'core') {
- $text = t('Your version of Drupal is no longer supported. Upgrading is strongly recommended!', array(), array('langcode' => $langcode));
- }
- else {
- $text = t('The installed version of at least one of your modules or themes is no longer supported. Upgrading or disabling is strongly recommended. See the project homepage for more details.', array(), array('langcode' => $langcode));
- }
- break;
-
- case UPDATE_NOT_CURRENT:
- if ($msg_type == 'core') {
- $text = t('There are updates available for your version of Drupal. To ensure the proper functioning of your site, you should update as soon as possible.', array(), array('langcode' => $langcode));
- }
- else {
- $text = t('There are updates available for one or more of your modules or themes. To ensure the proper functioning of your site, you should update as soon as possible.', array(), array('langcode' => $langcode));
- }
- break;
-
- case UPDATE_UNKNOWN:
- case UPDATE_NOT_CHECKED:
- case UPDATE_NOT_FETCHED:
- case UPDATE_FETCH_PENDING:
- if ($msg_type == 'core') {
- $text = t('There was a problem checking available updates for Drupal.', array('@update-report' => url('admin/reports/updates')), array('langcode' => $langcode));
- }
- else {
- $text = t('There was a problem checking available updates for your modules or themes.', array('@update-report' => url('admin/reports/updates')), array('langcode' => $langcode));
- }
- break;
- }
-
- if ($report_link) {
- if (update_manager_access()) {
- $text .= ' ' . t('See the available updates page for more information and to install your missing updates.', array('@available_updates' => url('admin/reports/updates/update', array('language' => $language))), array('langcode' => $langcode));
- }
- else {
- $text .= ' ' . t('See the available updates page for more information.', array('@available_updates' => url('admin/reports/updates', array('language' => $language))), array('langcode' => $langcode));
- }
- }
-
- return $text;
-}
-
-/**
- * Orders projects based on their status.
- *
- * Callback for uasort() within update_requirements().
- */
-function _update_project_status_sort($a, $b) {
- // The status constants are numerically in the right order, so we can
- // usually subtract the two to compare in the order we want. However,
- // negative status values should be treated as if they are huge, since we
- // always want them at the bottom of the list.
- $a_status = $a['status'] > 0 ? $a['status'] : (-10 * $a['status']);
- $b_status = $b['status'] > 0 ? $b['status'] : (-10 * $b['status']);
- return $a_status - $b_status;
-}
-
-/**
- * Returns HTML for the last time we checked for update data.
- *
- * In addition to properly formatting the given timestamp, this function also
- * provides a "Check manually" link that refreshes the available update and
- * redirects back to the same page.
- *
- * @param $variables
- * An associative array containing:
- * - last: The timestamp when the site last checked for available updates.
- *
- * @see theme_update_report()
- * @see theme_update_available_updates_form()
- * @ingroup themeable
- */
-function theme_update_last_check($variables) {
- $last = $variables['last'];
- $output = '';
- $output .= $last ? t('Last checked: @time ago', array('@time' => format_interval(REQUEST_TIME - $last))) : t('Last checked: never');
- $output .= ' (' . l(t('Check manually'), 'admin/reports/updates/check', array('query' => drupal_get_destination())) . ') ';
- $output .= "
\n";
- return $output;
-}
-
-/**
- * Implements hook_verify_update_archive().
- *
- * First, we ensure that the archive isn't a copy of Drupal core, which the
- * update manager does not yet support. See http://drupal.org/node/606592
- *
- * Then, we make sure that at least one module included in the archive file has
- * an .info file which claims that the code is compatible with the current
- * version of Drupal core.
- *
- * @see drupal_system_listing()
- * @see _system_rebuild_module_data()
- */
-function update_verify_update_archive($project, $archive_file, $directory) {
- $errors = array();
-
- // Make sure this isn't a tarball of Drupal core.
- if (
- file_exists("$directory/$project/index.php")
- && file_exists("$directory/$project/update.php")
- && file_exists("$directory/$project/includes/bootstrap.inc")
- && file_exists("$directory/$project/modules/node/node.module")
- && file_exists("$directory/$project/modules/system/system.module")
- ) {
- return array(
- 'no-core' => t('Automatic updating of Drupal core is not supported. See the upgrade guide for information on how to update Drupal core manually.', array('@upgrade-guide' => 'http://drupal.org/upgrade')),
- );
- }
-
- // Parse all the .info files and make sure at least one is compatible with
- // this version of Drupal core. If one is compatible, then the project as a
- // whole is considered compatible (since, for example, the project may ship
- // with some out-of-date modules that are not necessary for its overall
- // functionality).
- $compatible_project = FALSE;
- $incompatible = array();
- $files = file_scan_directory("$directory/$project", '/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', array('key' => 'name', 'min_depth' => 0));
- foreach ($files as $key => $file) {
- // Get the .info file for the module or theme this file belongs to.
- $info = drupal_parse_info_file($file->uri);
-
- // If the module or theme is incompatible with Drupal core, set an error.
- if (empty($info['core']) || $info['core'] != DRUPAL_CORE_COMPATIBILITY) {
- $incompatible[] = !empty($info['name']) ? $info['name'] : t('Unknown');
- }
- else {
- $compatible_project = TRUE;
- break;
- }
- }
-
- if (empty($files)) {
- $errors[] = t('%archive_file does not contain any .info files.', array('%archive_file' => drupal_basename($archive_file)));
- }
- elseif (!$compatible_project) {
- $errors[] = format_plural(
- count($incompatible),
- '%archive_file contains a version of %names that is not compatible with Drupal !version.',
- '%archive_file contains versions of modules or themes that are not compatible with Drupal !version: %names',
- array('!version' => DRUPAL_CORE_COMPATIBILITY, '%archive_file' => drupal_basename($archive_file), '%names' => implode(', ', $incompatible))
- );
- }
-
- return $errors;
-}
-
-/**
- * @defgroup update_status_cache Private update status cache system
- * @{
- * Functions to manage the update status cache.
- *
- * We specifically do NOT use the core cache API for saving the fetched data
- * about available updates. It is vitally important that this cache is only
- * cleared when we're populating it after successfully fetching new available
- * update data. Usage of the core cache API results in all sorts of potential
- * problems that would result in attempting to fetch available update data all
- * the time, including if a site has a "minimum cache lifetime" (which is both a
- * minimum and a maximum) defined, or if a site uses memcache or another
- * pluggable cache system that assumes volatile caches.
- *
- * The Update Manager module still uses the {cache_update} table, but instead of
- * using cache_set(), cache_get(), and cache_clear_all(), there are private
- * helper functions that implement these same basic tasks but ensure that the
- * cache is not prematurely cleared, and that the data is always stored in the
- * database, even if memcache or another cache backend is in use.
- */
-
-/**
- * Stores data in the private update status cache table.
- *
- * @param $cid
- * The cache ID to save the data with.
- * @param $data
- * The data to store.
- * @param $expire
- * One of the following values:
- * - CACHE_PERMANENT: Indicates that the item should never be removed except
- * by explicitly using _update_cache_clear().
- * - A Unix timestamp: Indicates that the item should be kept at least until
- * the given time, after which it will be invalidated.
- *
- * @see _update_cache_get()
- */
-function _update_cache_set($cid, $data, $expire) {
- $fields = array(
- 'created' => REQUEST_TIME,
- 'expire' => $expire,
- );
- if (!is_string($data)) {
- $fields['data'] = serialize($data);
- $fields['serialized'] = 1;
- }
- else {
- $fields['data'] = $data;
- $fields['serialized'] = 0;
- }
- db_merge('cache_update')
- ->key(array('cid' => $cid))
- ->fields($fields)
- ->execute();
-}
-
-/**
- * Retrieves data from the private update status cache table.
- *
- * @param $cid
- * The cache ID to retrieve.
- *
- * @return
- * An array of data for the given cache ID, or NULL if the ID was not found.
- *
- * @see _update_cache_set()
- */
-function _update_cache_get($cid) {
- $cache = db_query("SELECT data, created, expire, serialized FROM {cache_update} WHERE cid = :cid", array(':cid' => $cid))->fetchObject();
- if (isset($cache->data)) {
- if ($cache->serialized) {
- $cache->data = unserialize($cache->data);
- }
- }
- return $cache;
-}
-
-/**
- * Returns an array of cache items with a given cache ID prefix.
- *
- * @param string $cid_prefix
- * The cache ID prefix.
- *
- * @return
- * Associative array of cache items, keyed by cache ID.
- */
-function _update_get_cache_multiple($cid_prefix) {
- $data = array();
- $result = db_select('cache_update')
- ->fields('cache_update', array('cid', 'data', 'created', 'expire', 'serialized'))
- ->condition('cache_update.cid', $cid_prefix . '::%', 'LIKE')
- ->execute();
- foreach ($result as $cache) {
- if ($cache) {
- if ($cache->serialized) {
- $cache->data = unserialize($cache->data);
- }
- $data[$cache->cid] = $cache;
- }
- }
- return $data;
-}
-
-/**
- * Invalidates cached data relating to update status.
- *
- * @param $cid
- * (optional) Cache ID of the record to clear from the private update module
- * cache. If empty, all records will be cleared from the table except fetch
- * tasks. Defaults to NULL.
- * @param $wildcard
- * (optional) If TRUE, cache IDs starting with $cid are deleted in addition to
- * the exact cache ID specified by $cid. Defaults to FALSE.
- */
-function _update_cache_clear($cid = NULL, $wildcard = FALSE) {
- if (empty($cid)) {
- db_delete('cache_update')
- // Clear everything except fetch task information because these are used
- // to ensure that the fetch task queue items are not added multiple times.
- ->condition('cid', 'fetch_task::%', 'NOT LIKE')
- ->execute();
- }
- else {
- $query = db_delete('cache_update');
- if ($wildcard) {
- $query->condition('cid', $cid . '%', 'LIKE');
- }
- else {
- $query->condition('cid', $cid);
- }
- $query->execute();
- }
-}
-
-/**
- * Implements hook_flush_caches().
- *
- * Called from update.php (among others) to flush the caches. Since we're
- * running update.php, we are likely to install a new version of something, in
- * which case, we want to check for available update data again. However,
- * because we have our own caching system, we need to directly clear the
- * database table ourselves at this point and return nothing, for example, on
- * sites that use memcache where cache_clear_all() won't know how to purge this
- * data.
- *
- * However, we only want to do this from update.php, since otherwise, we'd lose
- * all the available update data on every cron run. So, we specifically check if
- * the site is in MAINTENANCE_MODE == 'update' (which indicates update.php is
- * running, not update module... alas for overloaded names).
- */
-function update_flush_caches() {
- if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
- _update_cache_clear();
- }
- return array();
-}
-
-/**
- * @} End of "defgroup update_status_cache".
- */
-
-/**
- * Returns a short unique identifier for this Drupal installation.
- *
- * @return
- * An eight character string uniquely identifying this Drupal installation.
- */
-function _update_manager_unique_identifier() {
- $id = &drupal_static(__FUNCTION__, '');
- if (empty($id)) {
- $id = substr(hash('sha256', drupal_get_hash_salt()), 0, 8);
- }
- return $id;
-}
-
-/**
- * Returns the directory where update archive files should be extracted.
- *
- * @param $create
- * (optional) Whether to attempt to create the directory if it does not
- * already exist. Defaults to TRUE.
- *
- * @return
- * The full path to the temporary directory where update file archives should
- * be extracted.
- */
-function _update_manager_extract_directory($create = TRUE) {
- $directory = &drupal_static(__FUNCTION__, '');
- if (empty($directory)) {
- $directory = 'temporary://update-extraction-' . _update_manager_unique_identifier();
- if ($create && !file_exists($directory)) {
- mkdir($directory);
- }
- }
- return $directory;
-}
-
-/**
- * Returns the directory where update archive files should be cached.
- *
- * @param $create
- * (optional) Whether to attempt to create the directory if it does not
- * already exist. Defaults to TRUE.
- *
- * @return
- * The full path to the temporary directory where update file archives should
- * be cached.
- */
-function _update_manager_cache_directory($create = TRUE) {
- $directory = &drupal_static(__FUNCTION__, '');
- if (empty($directory)) {
- $directory = 'temporary://update-cache-' . _update_manager_unique_identifier();
- if ($create && !file_exists($directory)) {
- mkdir($directory);
- }
- }
- return $directory;
-}
-
-/**
- * Clears the temporary files and directories based on file age from disk.
- */
-function update_clear_update_disk_cache() {
- // List of update module cache directories. Do not create the directories if
- // they do not exist.
- $directories = array(
- _update_manager_cache_directory(FALSE),
- _update_manager_extract_directory(FALSE),
- );
-
- // Search for files and directories in base folder only without recursion.
- foreach ($directories as $directory) {
- file_scan_directory($directory, '/.*/', array('callback' => 'update_delete_file_if_stale', 'recurse' => FALSE));
- }
-}
-
-/**
- * Deletes stale files and directories from the update manager disk cache.
- *
- * Files and directories older than 6 hours and development snapshots older than
- * 5 minutes are considered stale. We only cache development snapshots for 5
- * minutes since otherwise updated snapshots might not be downloaded as
- * expected.
- *
- * When checking file ages, we need to use the ctime, not the mtime
- * (modification time) since many (all?) tar implementations go out of their way
- * to set the mtime on the files they create to the timestamps recorded in the
- * tarball. We want to see the last time the file was changed on disk, which is
- * left alone by tar and correctly set to the time the archive file was
- * unpacked.
- *
- * @param $path
- * A string containing a file path or (streamwrapper) URI.
- */
-function update_delete_file_if_stale($path) {
- if (file_exists($path)) {
- $filectime = filectime($path);
- if (REQUEST_TIME - $filectime > DRUPAL_MAXIMUM_TEMP_FILE_AGE || (preg_match('/.*-dev\.(tar\.gz|zip)/i', $path) && REQUEST_TIME - $filectime > 300)) {
- file_unmanaged_delete_recursive($path);
- }
- }
-}
diff --git a/modules/update/update.report.inc b/modules/update/update.report.inc
deleted file mode 100644
index f256575f..00000000
--- a/modules/update/update.report.inc
+++ /dev/null
@@ -1,327 +0,0 @@
- $data));
- }
- else {
- return theme('update_report', array('data' => _update_no_data()));
- }
-}
-
-/**
- * Returns HTML for the project status report.
- *
- * @param array $variables
- * An associative array containing:
- * - data: An array of data about each project's status.
- *
- * @ingroup themeable
- */
-function theme_update_report($variables) {
- $data = $variables['data'];
-
- $last = variable_get('update_last_check', 0);
- $output = theme('update_last_check', array('last' => $last));
-
- if (!is_array($data)) {
- $output .= '' . $data . '
';
- return $output;
- }
-
- $header = array();
- $rows = array();
-
- $notification_level = variable_get('update_notification_threshold', 'all');
-
- // Create an array of status values keyed by module or theme name, since
- // we'll need this while generating the report if we have to cross reference
- // anything (e.g. subthemes which have base themes missing an update).
- foreach ($data as $project) {
- foreach ($project['includes'] as $key => $name) {
- $status[$key] = $project['status'];
- }
- }
-
- foreach ($data as $project) {
- switch ($project['status']) {
- case UPDATE_CURRENT:
- $class = 'ok';
- $icon = theme('image', array('path' => 'misc/watchdog-ok.png', 'width' => 18, 'height' => 18, 'alt' => t('ok'), 'title' => t('ok')));
- break;
- case UPDATE_UNKNOWN:
- case UPDATE_FETCH_PENDING:
- case UPDATE_NOT_FETCHED:
- $class = 'unknown';
- $icon = theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('warning'), 'title' => t('warning')));
- break;
- case UPDATE_NOT_SECURE:
- case UPDATE_REVOKED:
- case UPDATE_NOT_SUPPORTED:
- $class = 'error';
- $icon = theme('image', array('path' => 'misc/watchdog-error.png', 'width' => 18, 'height' => 18, 'alt' => t('error'), 'title' => t('error')));
- break;
- case UPDATE_NOT_CHECKED:
- case UPDATE_NOT_CURRENT:
- default:
- $class = 'warning';
- $icon = theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('warning'), 'title' => t('warning')));
- break;
- }
-
- $row = '';
- $status_label = theme('update_status_label', array('status' => $project['status']));
- $row .= !empty($status_label) ? $status_label : check_plain($project['reason']);
- $row .= '' . $icon . ' ';
- $row .= "
\n";
-
- $row .= '';
- if (isset($project['title'])) {
- if (isset($project['link'])) {
- $row .= l($project['title'], $project['link']);
- }
- else {
- $row .= check_plain($project['title']);
- }
- }
- else {
- $row .= check_plain($project['name']);
- }
- $row .= ' ' . check_plain($project['existing_version']);
- if ($project['install_type'] == 'dev' && !empty($project['datestamp'])) {
- $row .= ' (' . format_date($project['datestamp'], 'custom', 'Y-M-d') . ') ';
- }
- $row .= "
\n";
-
- $versions_inner = '';
- $security_class = array();
- $version_class = array();
- if (isset($project['recommended'])) {
- if ($project['status'] != UPDATE_CURRENT || $project['existing_version'] !== $project['recommended']) {
-
- // First, figure out what to recommend.
- // If there's only 1 security update and it has the same version we're
- // recommending, give it the same CSS class as if it was recommended,
- // but don't print out a separate "Recommended" line for this project.
- if (!empty($project['security updates']) && count($project['security updates']) == 1 && $project['security updates'][0]['version'] === $project['recommended']) {
- $security_class[] = 'version-recommended';
- $security_class[] = 'version-recommended-strong';
- }
- else {
- $version_class[] = 'version-recommended';
- // Apply an extra class if we're displaying both a recommended
- // version and anything else for an extra visual hint.
- if ($project['recommended'] !== $project['latest_version']
- || !empty($project['also'])
- || ($project['install_type'] == 'dev'
- && isset($project['dev_version'])
- && $project['latest_version'] !== $project['dev_version']
- && $project['recommended'] !== $project['dev_version'])
- || (isset($project['security updates'][0])
- && $project['recommended'] !== $project['security updates'][0])
- ) {
- $version_class[] = 'version-recommended-strong';
- }
- $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['recommended']], 'tag' => t('Recommended version:'), 'class' => $version_class));
- }
-
- // Now, print any security updates.
- if (!empty($project['security updates'])) {
- $security_class[] = 'version-security';
- foreach ($project['security updates'] as $security_update) {
- $versions_inner .= theme('update_version', array('version' => $security_update, 'tag' => t('Security update:'), 'class' => $security_class));
- }
- }
- }
-
- if ($project['recommended'] !== $project['latest_version']) {
- $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['latest_version']], 'tag' => t('Latest version:'), 'class' => array('version-latest')));
- }
- if ($project['install_type'] == 'dev'
- && $project['status'] != UPDATE_CURRENT
- && isset($project['dev_version'])
- && $project['recommended'] !== $project['dev_version']) {
- $versions_inner .= theme('update_version', array('version' => $project['releases'][$project['dev_version']], 'tag' => t('Development version:'), 'class' => array('version-latest')));
- }
- }
-
- if (isset($project['also'])) {
- foreach ($project['also'] as $also) {
- $versions_inner .= theme('update_version', array('version' => $project['releases'][$also], 'tag' => t('Also available:'), 'class' => array('version-also-available')));
- }
- }
-
- if (!empty($versions_inner)) {
- $row .= "\n" . $versions_inner . "
\n";
- }
- $row .= "\n";
- if (!empty($project['extra'])) {
- $row .= '\n"; // extra div.
- }
-
- $row .= '
';
- sort($project['includes']);
- if (!empty($project['disabled'])) {
- sort($project['disabled']);
- // Make sure we start with a clean slate for each project in the report.
- $includes_items = array();
- $row .= t('Includes:');
- $includes_items[] = t('Enabled: %includes', array('%includes' => implode(', ', $project['includes'])));
- $includes_items[] = t('Disabled: %disabled', array('%disabled' => implode(', ', $project['disabled'])));
- $row .= theme('item_list', array('items' => $includes_items));
- }
- else {
- $row .= t('Includes: %includes', array('%includes' => implode(', ', $project['includes'])));
- }
- $row .= "
\n";
-
- if (!empty($project['base_themes'])) {
- $row .= '
';
- asort($project['base_themes']);
- $base_themes = array();
- foreach ($project['base_themes'] as $base_key => $base_theme) {
- switch ($status[$base_key]) {
- case UPDATE_NOT_SECURE:
- case UPDATE_REVOKED:
- case UPDATE_NOT_SUPPORTED:
- $base_themes[] = t('%base_theme (!base_label)', array('%base_theme' => $base_theme, '!base_label' => theme('update_status_label', array('status' => $status[$base_key]))));
- break;
-
- default:
- $base_themes[] = drupal_placeholder($base_theme);
- }
- }
- $row .= t('Depends on: !basethemes', array('!basethemes' => implode(', ', $base_themes)));
- $row .= "
\n";
- }
-
- if (!empty($project['sub_themes'])) {
- $row .= '
';
- sort($project['sub_themes']);
- $row .= t('Required by: %subthemes', array('%subthemes' => implode(', ', $project['sub_themes'])));
- $row .= "
\n";
- }
-
- $row .= "
\n"; // info div.
-
- if (!isset($rows[$project['project_type']])) {
- $rows[$project['project_type']] = array();
- }
- $row_key = isset($project['title']) ? drupal_strtolower($project['title']) : drupal_strtolower($project['name']);
- $rows[$project['project_type']][$row_key] = array(
- 'class' => array($class),
- 'data' => array($row),
- );
- }
-
- $project_types = array(
- 'core' => t('Drupal core'),
- 'module' => t('Modules'),
- 'theme' => t('Themes'),
- 'module-disabled' => t('Disabled modules'),
- 'theme-disabled' => t('Disabled themes'),
- );
- foreach ($project_types as $type_name => $type_label) {
- if (!empty($rows[$type_name])) {
- ksort($rows[$type_name]);
- $output .= "\n" . $type_label . " \n";
- $output .= theme('table', array('header' => $header, 'rows' => $rows[$type_name], 'attributes' => array('class' => array('update'))));
- }
- }
- drupal_add_css(drupal_get_path('module', 'update') . '/update.css');
- return $output;
-}
-
-/**
- * Returns HTML for a label to display for a project's update status.
- *
- * @param array $variables
- * An associative array containing:
- * - status: The integer code for a project's current update status.
- *
- * @see update_calculate_project_data()
- * @ingroup themeable
- */
-function theme_update_status_label($variables) {
- switch ($variables['status']) {
- case UPDATE_NOT_SECURE:
- return '' . t('Security update required!') . ' ';
-
- case UPDATE_REVOKED:
- return '' . t('Revoked!') . ' ';
-
- case UPDATE_NOT_SUPPORTED:
- return '' . t('Not supported!') . ' ';
-
- case UPDATE_NOT_CURRENT:
- return '' . t('Update available') . ' ';
-
- case UPDATE_CURRENT:
- return '' . t('Up to date') . ' ';
-
- }
-}
-
-/**
- * Returns HTML for the version display of a project.
- *
- * @param array $variables
- * An associative array containing:
- * - version: An array of data about the latest released version, containing:
- * - version: The version number.
- * - release_link: The URL for the release notes.
- * - date: The date of the release.
- * - download_link: The URL for the downloadable file.
- * - tag: The title of the project.
- * - class: A string containing extra classes for the wrapping table.
- *
- * @ingroup themeable
- */
-function theme_update_version($variables) {
- $version = $variables['version'];
- $tag = $variables['tag'];
- $class = implode(' ', $variables['class']);
-
- $output = '';
- $output .= '';
- $output .= '';
- $output .= '' . $tag . " \n";
- $output .= '';
- $output .= l($version['version'], $version['release_link']);
- $output .= ' (' . format_date($version['date'], 'custom', 'Y-M-d') . ') ';
- $output .= " \n";
- $output .= '';
- $links = array();
- $links['update-download'] = array(
- 'title' => t('Download'),
- 'href' => $version['download_link'],
- );
- $links['update-release-notes'] = array(
- 'title' => t('Release notes'),
- 'href' => $version['release_link'],
- );
- $output .= theme('links__update_version', array('links' => $links));
- $output .= ' ';
- $output .= ' ';
- $output .= "
\n";
- return $output;
-}
diff --git a/modules/update/update.settings.inc b/modules/update/update.settings.inc
deleted file mode 100644
index 5cd24149..00000000
--- a/modules/update/update.settings.inc
+++ /dev/null
@@ -1,128 +0,0 @@
- 'radios',
- '#title' => t('Check for updates'),
- '#default_value' => variable_get('update_check_frequency', 1),
- '#options' => array(
- '1' => t('Daily'),
- '7' => t('Weekly'),
- ),
- '#description' => t('Select how frequently you want to automatically check for new releases of your currently installed modules and themes.'),
- );
-
- $form['update_check_disabled'] = array(
- '#type' => 'checkbox',
- '#title' => t('Check for updates of disabled modules and themes'),
- '#default_value' => variable_get('update_check_disabled', FALSE),
- );
-
- $notify_emails = variable_get('update_notify_emails', array());
- $form['update_notify_emails'] = array(
- '#type' => 'textarea',
- '#title' => t('E-mail addresses to notify when updates are available'),
- '#rows' => 4,
- '#default_value' => implode("\n", $notify_emails),
- '#description' => t('Whenever your site checks for available updates and finds new releases, it can notify a list of users via e-mail. Put each address on a separate line. If blank, no e-mails will be sent.'),
- );
-
- $form['update_notification_threshold'] = array(
- '#type' => 'radios',
- '#title' => t('E-mail notification threshold'),
- '#default_value' => variable_get('update_notification_threshold', 'all'),
- '#options' => array(
- 'all' => t('All newer versions'),
- 'security' => t('Only security updates'),
- ),
- '#description' => t('You can choose to send e-mail only if a security update is available, or to be notified about all newer versions. If there are updates available of Drupal core or any of your installed modules and themes, your site will always print a message on the status report page, and will also display an error message on administration pages if there is a security update.', array('@status_report' => url('admin/reports/status')))
- );
-
- $form = system_settings_form($form);
- // Custom validation callback for the email notification setting.
- $form['#validate'][] = 'update_settings_validate';
- // We need to call our own submit callback first, not the one from
- // system_settings_form(), so that we can process and save the emails.
- unset($form['#submit']);
-
- return $form;
-}
-
-/**
- * Form validation handler for update_settings().
- *
- * Validates the e-mail addresses and ensures the field is formatted correctly.
- *
- * @see update_settings_submit()
- */
-function update_settings_validate($form, &$form_state) {
- if (!empty($form_state['values']['update_notify_emails'])) {
- $valid = array();
- $invalid = array();
- foreach (explode("\n", trim($form_state['values']['update_notify_emails'])) as $email) {
- $email = trim($email);
- if (!empty($email)) {
- if (valid_email_address($email)) {
- $valid[] = $email;
- }
- else {
- $invalid[] = $email;
- }
- }
- }
- if (empty($invalid)) {
- $form_state['notify_emails'] = $valid;
- }
- elseif (count($invalid) == 1) {
- form_set_error('update_notify_emails', t('%email is not a valid e-mail address.', array('%email' => reset($invalid))));
- }
- else {
- form_set_error('update_notify_emails', t('%emails are not valid e-mail addresses.', array('%emails' => implode(', ', $invalid))));
- }
- }
-}
-
-/**
- * Form submission handler for update_settings().
- *
- * Also invalidates the cache of available updates if the "Check for updates of
- * disabled modules and themes" setting is being changed. The available updates
- * report needs to refetch available update data after this setting changes or
- * it would show misleading things (e.g., listing the disabled projects on the
- * site with the "No available releases found" warning).
- *
- * @see update_settings_validate()
- */
-function update_settings_submit($form, $form_state) {
- $op = $form_state['values']['op'];
-
- if (empty($form_state['notify_emails'])) {
- variable_del('update_notify_emails');
- }
- else {
- variable_set('update_notify_emails', $form_state['notify_emails']);
- }
- unset($form_state['notify_emails']);
- unset($form_state['values']['update_notify_emails']);
-
- // See if the update_check_disabled setting is being changed, and if so,
- // invalidate all cached update status data.
- $check_disabled = variable_get('update_check_disabled', FALSE);
- if ($form_state['values']['update_check_disabled'] != $check_disabled) {
- _update_cache_clear();
- }
-
- system_settings_form_submit($form, $form_state);
-}
diff --git a/modules/update/update.test b/modules/update/update.test
deleted file mode 100644
index 9e04cdae..00000000
--- a/modules/update/update.test
+++ /dev/null
@@ -1,803 +0,0 @@
- TRUE)));
- // Save the map for update_test_mock_page() to use.
- variable_set('update_test_xml_map', $xml_map);
- // Manually check the update status.
- $this->drupalGet('admin/reports/updates/check');
- }
-
- /**
- * Runs a series of assertions that are applicable to all update statuses.
- */
- protected function standardTests() {
- $this->assertRaw('' . t('Drupal core') . ' ');
- $this->assertRaw(l(t('Drupal'), 'http://example.com/project/drupal'), 'Link to the Drupal project appears.');
- $this->assertNoText(t('No available releases found'));
- }
-
-}
-
-/**
- * Tests behavior related to discovering and listing updates to Drupal core.
- */
-class UpdateCoreTestCase extends UpdateTestHelper {
-
- public static function getInfo() {
- return array(
- 'name' => 'Update core functionality',
- 'description' => 'Tests the Update Manager module through a series of functional tests using mock XML data.',
- 'group' => 'Update',
- );
- }
-
- function setUp() {
- parent::setUp('update_test', 'update');
- $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer modules'));
- $this->drupalLogin($admin_user);
- }
-
- /**
- * Tests the Update Manager module when no updates are available.
- */
- function testNoUpdatesAvailable() {
- $this->setSystemInfo7_0();
- $this->refreshUpdateStatus(array('drupal' => '0'));
- $this->standardTests();
- $this->assertText(t('Up to date'));
- $this->assertNoText(t('Update available'));
- $this->assertNoText(t('Security update required!'));
- }
-
- /**
- * Tests the Update Manager module when one normal update is available.
- */
- function testNormalUpdateAvailable() {
- $this->setSystemInfo7_0();
- $this->refreshUpdateStatus(array('drupal' => '1'));
- $this->standardTests();
- $this->assertNoText(t('Up to date'));
- $this->assertText(t('Update available'));
- $this->assertNoText(t('Security update required!'));
- $this->assertRaw(l('7.1', 'http://example.com/drupal-7-1-release'), 'Link to release appears.');
- $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-1.tar.gz'), 'Link to download appears.');
- $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-1-release'), 'Link to release notes appears.');
- }
-
- /**
- * Tests the Update Manager module when a security update is available.
- */
- function testSecurityUpdateAvailable() {
- $this->setSystemInfo7_0();
- $this->refreshUpdateStatus(array('drupal' => '2-sec'));
- $this->standardTests();
- $this->assertNoText(t('Up to date'));
- $this->assertNoText(t('Update available'));
- $this->assertText(t('Security update required!'));
- $this->assertRaw(l('7.2', 'http://example.com/drupal-7-2-release'), 'Link to release appears.');
- $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-2.tar.gz'), 'Link to download appears.');
- $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-2-release'), 'Link to release notes appears.');
- }
-
- /**
- * Ensures proper results where there are date mismatches among modules.
- */
- function testDatestampMismatch() {
- $system_info = array(
- '#all' => array(
- // We need to think we're running a -dev snapshot to see dates.
- 'version' => '7.0-dev',
- 'datestamp' => time(),
- ),
- 'block' => array(
- // This is 2001-09-09 01:46:40 GMT, so test for "2001-Sep-".
- 'datestamp' => '1000000000',
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $this->refreshUpdateStatus(array('drupal' => 'dev'));
- $this->assertNoText(t('2001-Sep-'));
- $this->assertText(t('Up to date'));
- $this->assertNoText(t('Update available'));
- $this->assertNoText(t('Security update required!'));
- }
-
- /**
- * Checks that running cron updates the list of available updates.
- */
- function testModulePageRunCron() {
- $this->setSystemInfo7_0();
- variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
- variable_set('update_test_xml_map', array('drupal' => '0'));
-
- $this->cronRun();
- $this->drupalGet('admin/modules');
- $this->assertNoText(t('No update information available.'));
- }
-
- /**
- * Checks the messages at admin/modules when the site is up to date.
- */
- function testModulePageUpToDate() {
- $this->setSystemInfo7_0();
- // Instead of using refreshUpdateStatus(), set these manually.
- variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
- variable_set('update_test_xml_map', array('drupal' => '0'));
-
- $this->drupalGet('admin/reports/updates');
- $this->clickLink(t('Check manually'));
- $this->assertText(t('Checked available update data for one project.'));
- $this->drupalGet('admin/modules');
- $this->assertNoText(t('There are updates available for your version of Drupal.'));
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
- }
-
- /**
- * Checks the messages at admin/modules when an update is missing.
- */
- function testModulePageRegularUpdate() {
- $this->setSystemInfo7_0();
- // Instead of using refreshUpdateStatus(), set these manually.
- variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
- variable_set('update_test_xml_map', array('drupal' => '1'));
-
- $this->drupalGet('admin/reports/updates');
- $this->clickLink(t('Check manually'));
- $this->assertText(t('Checked available update data for one project.'));
- $this->drupalGet('admin/modules');
- $this->assertText(t('There are updates available for your version of Drupal.'));
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
- }
-
- /**
- * Checks the messages at admin/modules when a security update is missing.
- */
- function testModulePageSecurityUpdate() {
- $this->setSystemInfo7_0();
- // Instead of using refreshUpdateStatus(), set these manually.
- variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
- variable_set('update_test_xml_map', array('drupal' => '2-sec'));
-
- $this->drupalGet('admin/reports/updates');
- $this->clickLink(t('Check manually'));
- $this->assertText(t('Checked available update data for one project.'));
- $this->drupalGet('admin/modules');
- $this->assertNoText(t('There are updates available for your version of Drupal.'));
- $this->assertText(t('There is a security update available for your version of Drupal.'));
-
- // Make sure admin/appearance warns you you're missing a security update.
- $this->drupalGet('admin/appearance');
- $this->assertNoText(t('There are updates available for your version of Drupal.'));
- $this->assertText(t('There is a security update available for your version of Drupal.'));
-
- // Make sure duplicate messages don't appear on Update status pages.
- $this->drupalGet('admin/reports/status');
- // We're expecting "There is a security update..." inside the status report
- // itself, but the drupal_set_message() appears as an li so we can prefix
- // with that and search for the raw HTML.
- $this->assertNoRaw('' . t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/reports/updates');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/reports/updates/settings');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
- }
-
- /**
- * Tests the Update Manager module when the update server returns 503 errors.
- */
- function testServiceUnavailable() {
- $this->refreshUpdateStatus(array(), '503-error');
- // Ensure that no "Warning: SimpleXMLElement..." parse errors are found.
- $this->assertNoText('SimpleXMLElement');
- $this->assertUniqueText(t('Failed to get available update data for one project.'));
- }
-
- /**
- * Tests that exactly one fetch task per project is created and not more.
- */
- function testFetchTasks() {
- $projecta = array(
- 'name' => 'aaa_update_test',
- );
- $projectb = array(
- 'name' => 'bbb_update_test',
- );
- $queue = DrupalQueue::get('update_fetch_tasks');
- $this->assertEqual($queue->numberOfItems(), 0, 'Queue is empty');
- update_create_fetch_task($projecta);
- $this->assertEqual($queue->numberOfItems(), 1, 'Queue contains one item');
- update_create_fetch_task($projectb);
- $this->assertEqual($queue->numberOfItems(), 2, 'Queue contains two items');
- // Try to add project a again.
- update_create_fetch_task($projecta);
- $this->assertEqual($queue->numberOfItems(), 2, 'Queue still contains two items');
-
- // Clear cache and try again.
- _update_cache_clear();
- drupal_static_reset('_update_create_fetch_task');
- update_create_fetch_task($projecta);
- $this->assertEqual($queue->numberOfItems(), 2, 'Queue contains two items');
- }
-
- /**
- * Sets the version to 7.0 when no project-specific mapping is defined.
- */
- protected function setSystemInfo7_0() {
- $setting = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- );
- variable_set('update_test_system_info', $setting);
- }
-
-}
-
-/**
- * Tests behavior related to handling updates to contributed modules and themes.
- */
-class UpdateTestContribCase extends UpdateTestHelper {
-
- public static function getInfo() {
- return array(
- 'name' => 'Update contrib functionality',
- 'description' => 'Tests how the Update Manager module handles contributed modules and themes in a series of functional tests using mock XML data.',
- 'group' => 'Update',
- );
- }
-
- function setUp() {
- parent::setUp('update_test', 'update', 'aaa_update_test', 'bbb_update_test', 'ccc_update_test');
- $admin_user = $this->drupalCreateUser(array('administer site configuration'));
- $this->drupalLogin($admin_user);
- }
-
- /**
- * Tests when there is no available release data for a contrib module.
- */
- function testNoReleasesAvailable() {
- $system_info = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- 'aaa_update_test' => array(
- 'project' => 'aaa_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $this->refreshUpdateStatus(array('drupal' => '0', 'aaa_update_test' => 'no-releases'));
- $this->drupalGet('admin/reports/updates');
- // Cannot use $this->standardTests() because we need to check for the
- // 'No available releases found' string.
- $this->assertRaw('' . t('Drupal core') . ' ');
- $this->assertRaw(l(t('Drupal'), 'http://example.com/project/drupal'));
- $this->assertText(t('Up to date'));
- $this->assertRaw('' . t('Modules') . ' ');
- $this->assertNoText(t('Update available'));
- $this->assertText(t('No available releases found'));
- $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'));
- }
-
- /**
- * Tests the basic functionality of a contrib module on the status report.
- */
- function testUpdateContribBasic() {
- $system_info = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- 'aaa_update_test' => array(
- 'project' => 'aaa_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $this->refreshUpdateStatus(
- array(
- 'drupal' => '0',
- 'aaa_update_test' => '1_0',
- )
- );
- $this->standardTests();
- $this->assertText(t('Up to date'));
- $this->assertRaw('' . t('Modules') . ' ');
- $this->assertNoText(t('Update available'));
- $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.');
- }
-
- /**
- * Tests that contrib projects are ordered by project name.
- *
- * If a project contains multiple modules, we want to make sure that the
- * available updates report is sorted by the parent project names, not by the
- * names of the modules included in each project. In this test case, we have
- * two contrib projects, "BBB Update test" and "CCC Update test". However, we
- * have a module called "aaa_update_test" that's part of the "CCC Update test"
- * project. We need to make sure that we see the "BBB" project before the
- * "CCC" project, even though "CCC" includes a module that's processed first
- * if you sort alphabetically by module name (which is the order we see things
- * inside system_rebuild_module_data() for example).
- */
- function testUpdateContribOrder() {
- // We want core to be version 7.0.
- $system_info = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- // All the rest should be visible as contrib modules at version 7.x-1.0.
-
- // aaa_update_test needs to be part of the "CCC Update test" project,
- // which would throw off the report if we weren't properly sorting by
- // the project names.
- 'aaa_update_test' => array(
- 'project' => 'ccc_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
-
- // This should be its own project, and listed first on the report.
- 'bbb_update_test' => array(
- 'project' => 'bbb_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
-
- // This will contain both aaa_update_test and ccc_update_test, and
- // should come after the bbb_update_test project.
- 'ccc_update_test' => array(
- 'project' => 'ccc_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $this->refreshUpdateStatus(array('drupal' => '0', '#all' => '1_0'));
- $this->standardTests();
- // We're expecting the report to say all projects are up to date.
- $this->assertText(t('Up to date'));
- $this->assertNoText(t('Update available'));
- // We want to see all 3 module names listed, since they'll show up either
- // as project names or as modules under the "Includes" listing.
- $this->assertText(t('AAA Update test'));
- $this->assertText(t('BBB Update test'));
- $this->assertText(t('CCC Update test'));
- // We want aaa_update_test included in the ccc_update_test project, not as
- // its own project on the report.
- $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project does not appear.');
- // The other two should be listed as projects.
- $this->assertRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), 'Link to bbb_update_test project appears.');
- $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), 'Link to bbb_update_test project appears.');
-
- // We want to make sure we see the BBB project before the CCC project.
- // Instead of just searching for 'BBB Update test' or something, we want
- // to use the full markup that starts the project entry itself, so that
- // we're really testing that the project listings are in the right order.
- $bbb_project_link = 'BBB Update test ';
- $ccc_project_link = '
CCC Update test ';
- $this->assertTrue(strpos($this->drupalGetContent(), $bbb_project_link) < strpos($this->drupalGetContent(), $ccc_project_link), "'BBB Update test' project is listed before the 'CCC Update test' project");
- }
-
- /**
- * Tests that subthemes are notified about security updates for base themes.
- */
- function testUpdateBaseThemeSecurityUpdate() {
- // Only enable the subtheme, not the base theme.
- db_update('system')
- ->fields(array('status' => 1))
- ->condition('type', 'theme')
- ->condition('name', 'update_test_subtheme')
- ->execute();
-
- // Define the initial state for core and the subtheme.
- $system_info = array(
- // We want core to be version 7.0.
- '#all' => array(
- 'version' => '7.0',
- ),
- // Show the update_test_basetheme
- 'update_test_basetheme' => array(
- 'project' => 'update_test_basetheme',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- // Show the update_test_subtheme
- 'update_test_subtheme' => array(
- 'project' => 'update_test_subtheme',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $xml_mapping = array(
- 'drupal' => '0',
- 'update_test_subtheme' => '1_0',
- 'update_test_basetheme' => '1_1-sec',
- );
- $this->refreshUpdateStatus($xml_mapping);
- $this->assertText(t('Security update required!'));
- $this->assertRaw(l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'), 'Link to the Update test base theme project appears.');
- }
-
- /**
- * Tests that disabled themes are only shown when desired.
- */
- function testUpdateShowDisabledThemes() {
- // Make sure all the update_test_* themes are disabled.
- db_update('system')
- ->fields(array('status' => 0))
- ->condition('type', 'theme')
- ->condition('name', 'update_test_%', 'LIKE')
- ->execute();
-
- // Define the initial state for core and the test contrib themes.
- $system_info = array(
- // We want core to be version 7.0.
- '#all' => array(
- 'version' => '7.0',
- ),
- // The update_test_basetheme should be visible and up to date.
- 'update_test_basetheme' => array(
- 'project' => 'update_test_basetheme',
- 'version' => '7.x-1.1',
- 'hidden' => FALSE,
- ),
- // The update_test_subtheme should be visible and up to date.
- 'update_test_subtheme' => array(
- 'project' => 'update_test_subtheme',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- // When there are contributed modules in the site's file system, the
- // total number of attempts made in the test may exceed the default value
- // of update_max_fetch_attempts. Therefore this variable is set very high
- // to avoid test failures in those cases.
- variable_set('update_max_fetch_attempts', 99999);
- variable_set('update_test_system_info', $system_info);
- $xml_mapping = array(
- 'drupal' => '0',
- 'update_test_subtheme' => '1_0',
- 'update_test_basetheme' => '1_1-sec',
- );
- $base_theme_project_link = l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme');
- $sub_theme_project_link = l(t('Update test subtheme'), 'http://example.com/project/update_test_subtheme');
- foreach (array(TRUE, FALSE) as $check_disabled) {
- variable_set('update_check_disabled', $check_disabled);
- $this->refreshUpdateStatus($xml_mapping);
- // In neither case should we see the "Themes" heading for enabled themes.
- $this->assertNoText(t('Themes'));
- if ($check_disabled) {
- $this->assertText(t('Disabled themes'));
- $this->assertRaw($base_theme_project_link, 'Link to the Update test base theme project appears.');
- $this->assertRaw($sub_theme_project_link, 'Link to the Update test subtheme project appears.');
- }
- else {
- $this->assertNoText(t('Disabled themes'));
- $this->assertNoRaw($base_theme_project_link, 'Link to the Update test base theme project does not appear.');
- $this->assertNoRaw($sub_theme_project_link, 'Link to the Update test subtheme project does not appear.');
- }
- }
- }
-
- /**
- * Makes sure that if we fetch from a broken URL, sane things happen.
- */
- function testUpdateBrokenFetchURL() {
- $system_info = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- 'aaa_update_test' => array(
- 'project' => 'aaa_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- 'bbb_update_test' => array(
- 'project' => 'bbb_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- 'ccc_update_test' => array(
- 'project' => 'ccc_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
-
- $xml_mapping = array(
- 'drupal' => '0',
- 'aaa_update_test' => '1_0',
- 'bbb_update_test' => 'does-not-exist',
- 'ccc_update_test' => '1_0',
- );
- $this->refreshUpdateStatus($xml_mapping);
-
- $this->assertText(t('Up to date'));
- // We're expecting the report to say most projects are up to date, so we
- // hope that 'Up to date' is not unique.
- $this->assertNoUniqueText(t('Up to date'));
- // It should say we failed to get data, not that we're missing an update.
- $this->assertNoText(t('Update available'));
-
- // We need to check that this string is found as part of a project row,
- // not just in the "Failed to get available update data for ..." message
- // at the top of the page.
- $this->assertRaw('
' . t('Failed to get available update data'));
-
- // We should see the output messages from fetching manually.
- $this->assertUniqueText(t('Checked available update data for 3 projects.'));
- $this->assertUniqueText(t('Failed to get available update data for one project.'));
-
- // The other two should be listed as projects.
- $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.');
- $this->assertNoRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), 'Link to bbb_update_test project does not appear.');
- $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), 'Link to bbb_update_test project appears.');
- }
-
- /**
- * Checks that hook_update_status_alter() works to change a status.
- *
- * We provide the same external data as if aaa_update_test 7.x-1.0 were
- * installed and that was the latest release. Then we use
- * hook_update_status_alter() to try to mark this as missing a security
- * update, then assert if we see the appropriate warnings on the right pages.
- */
- function testHookUpdateStatusAlter() {
- variable_set('allow_authorize_operations', TRUE);
- $update_admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer software updates'));
- $this->drupalLogin($update_admin_user);
-
- $system_info = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- 'aaa_update_test' => array(
- 'project' => 'aaa_update_test',
- 'version' => '7.x-1.0',
- 'hidden' => FALSE,
- ),
- );
- variable_set('update_test_system_info', $system_info);
- $update_status = array(
- 'aaa_update_test' => array(
- 'status' => UPDATE_NOT_SECURE,
- ),
- );
- variable_set('update_test_update_status', $update_status);
- $this->refreshUpdateStatus(
- array(
- 'drupal' => '0',
- 'aaa_update_test' => '1_0',
- )
- );
- $this->drupalGet('admin/reports/updates');
- $this->assertRaw('
' . t('Modules') . ' ');
- $this->assertText(t('Security update required!'));
- $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.');
-
- // Visit the reports page again without the altering and make sure the
- // status is back to normal.
- variable_set('update_test_update_status', array());
- $this->drupalGet('admin/reports/updates');
- $this->assertRaw('
' . t('Modules') . ' ');
- $this->assertNoText(t('Security update required!'));
- $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.');
-
- // Turn the altering back on and visit the Update manager UI.
- variable_set('update_test_update_status', $update_status);
- $this->drupalGet('admin/modules/update');
- $this->assertText(t('Security update'));
-
- // Turn the altering back off and visit the Update manager UI.
- variable_set('update_test_update_status', array());
- $this->drupalGet('admin/modules/update');
- $this->assertNoText(t('Security update'));
- }
-
-}
-
-/**
- * Tests project upload and extract functionality.
- */
-class UpdateTestUploadCase extends UpdateTestHelper {
-
- public static function getInfo() {
- return array(
- 'name' => 'Upload and extract module functionality',
- 'description' => 'Tests the Update Manager module\'s upload and extraction functionality.',
- 'group' => 'Update',
- );
- }
-
- public function setUp() {
- parent::setUp('update', 'update_test');
- variable_set('allow_authorize_operations', TRUE);
- $admin_user = $this->drupalCreateUser(array('administer software updates', 'administer site configuration'));
- $this->drupalLogin($admin_user);
- }
-
- /**
- * Tests upload and extraction of a module.
- */
- public function testUploadModule() {
- // Images are not valid archives, so get one and try to install it. We
- // need an extra variable to store the result of drupalGetTestFiles()
- // since reset() takes an argument by reference and passing in a constant
- // emits a notice in strict mode.
- $imageTestFiles = $this->drupalGetTestFiles('image');
- $invalidArchiveFile = reset($imageTestFiles);
- $edit = array(
- 'files[project_upload]' => $invalidArchiveFile->uri,
- );
- // This also checks that the correct archive extensions are allowed.
- $this->drupalPost('admin/modules/install', $edit, t('Install'));
- $this->assertText(t('Only files with the following extensions are allowed: @archive_extensions.', array('@archive_extensions' => archiver_get_extensions())),'Only valid archives can be uploaded.');
-
- // Check to ensure an existing module can't be reinstalled. Also checks that
- // the archive was extracted since we can't know if the module is already
- // installed until after extraction.
- $validArchiveFile = drupal_get_path('module', 'update') . '/tests/aaa_update_test.tar.gz';
- $edit = array(
- 'files[project_upload]' => $validArchiveFile,
- );
- $this->drupalPost('admin/modules/install', $edit, t('Install'));
- $this->assertText(t('@module_name is already installed.', array('@module_name' => 'AAA Update test')), 'Existing module was extracted and not reinstalled.');
- }
-
- /**
- * Ensures that archiver extensions are properly merged in the UI.
- */
- function testFileNameExtensionMerging() {
- $this->drupalGet('admin/modules/install');
- // Make sure the bogus extension supported by update_test.module is there.
- $this->assertPattern('/file extensions are supported:.*update-test-extension/', "Found 'update-test-extension' extension");
- // Make sure it didn't clobber the first option from core.
- $this->assertPattern('/file extensions are supported:.*tar/', "Found 'tar' extension");
- }
-
- /**
- * Checks the messages on update manager pages when missing a security update.
- */
- function testUpdateManagerCoreSecurityUpdateMessages() {
- $setting = array(
- '#all' => array(
- 'version' => '7.0',
- ),
- );
- variable_set('update_test_system_info', $setting);
- variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
- variable_set('update_test_xml_map', array('drupal' => '2-sec'));
- // Initialize the update status.
- $this->drupalGet('admin/reports/updates');
-
- // Now, make sure none of the Update manager pages have duplicate messages
- // about core missing a security update.
-
- $this->drupalGet('admin/modules/install');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/modules/update');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/appearance/install');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/appearance/update');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/reports/updates/install');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/reports/updates/update');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
-
- $this->drupalGet('admin/update/ready');
- $this->assertNoText(t('There is a security update available for your version of Drupal.'));
- }
-
-}
-
-/**
- * Tests update functionality unrelated to the database.
- */
-class UpdateCoreUnitTestCase extends DrupalUnitTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => "Unit tests",
- 'description' => 'Test update funcionality unrelated to the database.',
- 'group' => 'Update',
- );
- }
-
- function setUp() {
- parent::setUp('update');
- module_load_include('inc', 'update', 'update.fetch');
- }
-
- /**
- * Tests that _update_build_fetch_url() builds the URL correctly.
- */
- function testUpdateBuildFetchUrl() {
- //first test that we didn't break the trivial case
- $project['name'] = 'update_test';
- $project['project_type'] = '';
- $project['info']['version'] = '';
- $project['info']['project status url'] = 'http://www.example.com';
- $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2');
- $site_key = '';
- $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
- $url = _update_build_fetch_url($project, $site_key);
- $this->assertEqual($url, $expected, "'$url' when no site_key provided should be '$expected'.");
-
- //For disabled projects it shouldn't add the site key either.
- $site_key = 'site_key';
- $project['project_type'] = 'disabled';
- $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
- $url = _update_build_fetch_url($project, $site_key);
- $this->assertEqual($url, $expected, "'$url' should be '$expected' for disabled projects.");
-
- //for enabled projects, adding the site key
- $project['project_type'] = '';
- $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
- $expected .= '?site_key=site_key';
- $expected .= '&list=' . rawurlencode('module1,module2');
- $url = _update_build_fetch_url($project, $site_key);
- $this->assertEqual($url, $expected, "When site_key provided, '$url' should be '$expected'.");
-
- // http://drupal.org/node/1481156 test incorrect logic when URL contains
- // a question mark.
- $project['info']['project status url'] = 'http://www.example.com/?project=';
- $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY;
- $expected .= '&site_key=site_key';
- $expected .= '&list=' . rawurlencode('module1,module2');
- $url = _update_build_fetch_url($project, $site_key);
- $this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'.");
-
- }
-}
\ No newline at end of file
diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info
deleted file mode 100644
index bc1bc835..00000000
--- a/modules/user/tests/user_form_test.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = "User module form tests"
-description = "Support module for user form testing."
-package = Testing
-version = VERSION
-core = 7.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/user/tests/user_form_test.module b/modules/user/tests/user_form_test.module
deleted file mode 100644
index 4e907f36..00000000
--- a/modules/user/tests/user_form_test.module
+++ /dev/null
@@ -1,64 +0,0 @@
- 'User form test for current password validation',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_form_test_current_password',1),
- 'access arguments' => array('administer users'),
- 'type' => MENU_SUGGESTED_ITEM,
- );
- return $items;
-}
-
-/**
- * A test form for user_validate_current_pass().
- */
-function user_form_test_current_password($form, &$form_state, $account) {
- $account->user_form_test_field = '';
- $form['#user'] = $account;
-
- $form['user_form_test_field'] = array(
- '#type' => 'textfield',
- '#title' => t('Test field'),
- '#description' => t('A field that would require a correct password to change.'),
- '#required' => TRUE,
- );
-
- $form['current_pass'] = array(
- '#type' => 'password',
- '#title' => t('Current password'),
- '#size' => 25,
- '#description' => t('Enter your current password'),
- );
-
- $form['current_pass_required_values'] = array(
- '#type' => 'value',
- '#value' => array('user_form_test_field' => t('Test field')),
- );
-
- $form['#validate'][] = 'user_validate_current_pass';
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Test'),
- );
- return $form;
-}
-
-/**
- * Submit function for the test form for user_validate_current_pass().
- */
-function user_form_test_current_password_submit($form, &$form_state) {
- drupal_set_message(t('The password has been validated and the form submitted successfully.'));
-}
diff --git a/modules/user/user-picture.tpl.php b/modules/user/user-picture.tpl.php
deleted file mode 100644
index ee821878..00000000
--- a/modules/user/user-picture.tpl.php
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
diff --git a/modules/user/user-profile-category.tpl.php b/modules/user/user-profile-category.tpl.php
deleted file mode 100644
index 0a86c762..00000000
--- a/modules/user/user-profile-category.tpl.php
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
>
-
-
diff --git a/modules/user/user-profile-item.tpl.php b/modules/user/user-profile-item.tpl.php
deleted file mode 100644
index 042d43a8..00000000
--- a/modules/user/user-profile-item.tpl.php
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
>
-
>
diff --git a/modules/user/user-profile.tpl.php b/modules/user/user-profile.tpl.php
deleted file mode 100644
index 0a64fed8..00000000
--- a/modules/user/user-profile.tpl.php
+++ /dev/null
@@ -1,39 +0,0 @@
-field_example has a
- * variable $field_example defined. When needing to access a field's raw
- * values, developers/themers are strongly encouraged to use these
- * variables. Otherwise they will have to explicitly specify the desired
- * field language, e.g. $account->field_example['en'], thus overriding any
- * language negotiation rule that was previously applied.
- *
- * @see user-profile-category.tpl.php
- * Where the html is handled for the group.
- * @see user-profile-item.tpl.php
- * Where the html is handled for each item in the group.
- * @see template_preprocess_user_profile()
- *
- * @ingroup themeable
- */
-?>
-
>
-
-
diff --git a/modules/user/user-rtl.css b/modules/user/user-rtl.css
deleted file mode 100644
index 642c9434..00000000
--- a/modules/user/user-rtl.css
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#permissions td.permission {
- padding-left: 0;
- padding-right: 1.5em;
-}
-
-#user-admin-roles .form-item-name {
- float: right;
- margin-left: 1em;
- margin-right: 0;
-}
-
-/**
- * Password strength indicator.
- */
-.password-strength {
- float: left;
-}
-.password-strength-text {
- float: left;
-}
-div.password-confirm {
- float: left;
-}
-.confirm-parent,
-.password-parent {
- clear: right;
-}
-
-/* Generated by user.module but used by profile.module: */
-.profile .user-picture {
- float: left;
- margin: 0 0 1em 1em;
-}
diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc
deleted file mode 100644
index 6ca330b0..00000000
--- a/modules/user/user.admin.inc
+++ /dev/null
@@ -1,1053 +0,0 @@
- 'fieldset',
- '#title' => t('Show only users where'),
- '#theme' => 'exposed_filters__user',
- );
- foreach ($session as $filter) {
- list($type, $value) = $filter;
- if ($type == 'permission') {
- // Merge arrays of module permissions into one.
- // Slice past the first element '[any]' whose value is not an array.
- $options = call_user_func_array('array_merge', array_slice($filters[$type]['options'], 1));
- $value = $options[$value];
- }
- else {
- $value = $filters[$type]['options'][$value];
- }
- $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
- if ($i++) {
- $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
- }
- else {
- $form['filters']['current'][] = array('#markup' => t('%property is %value', $t_args));
- }
- }
-
- $form['filters']['status'] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('clearfix')),
- '#prefix' => ($i ? '
' . t('and where') . '
' : ''),
- );
- $form['filters']['status']['filters'] = array(
- '#type' => 'container',
- '#attributes' => array('class' => array('filters')),
- );
- foreach ($filters as $key => $filter) {
- $form['filters']['status']['filters'][$key] = array(
- '#type' => 'select',
- '#options' => $filter['options'],
- '#title' => $filter['title'],
- '#default_value' => '[any]',
- );
- }
-
- $form['filters']['status']['actions'] = array(
- '#type' => 'actions',
- '#attributes' => array('class' => array('container-inline')),
- );
- $form['filters']['status']['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => (count($session) ? t('Refine') : t('Filter')),
- );
- if (count($session)) {
- $form['filters']['status']['actions']['undo'] = array(
- '#type' => 'submit',
- '#value' => t('Undo'),
- );
- $form['filters']['status']['actions']['reset'] = array(
- '#type' => 'submit',
- '#value' => t('Reset'),
- );
- }
-
- drupal_add_library('system', 'drupal.form');
-
- return $form;
-}
-
-/**
- * Process result from user administration filter form.
- */
-function user_filter_form_submit($form, &$form_state) {
- $op = $form_state['values']['op'];
- $filters = user_filters();
- switch ($op) {
- case t('Filter'):
- case t('Refine'):
- // Apply every filter that has a choice selected other than 'any'.
- foreach ($filters as $filter => $options) {
- if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != '[any]') {
- // Merge an array of arrays into one if necessary.
- $options = ($filter == 'permission') ? form_options_flatten($filters[$filter]['options']) : $filters[$filter]['options'];
- // Only accept valid selections offered on the dropdown, block bad input.
- if (isset($options[$form_state['values'][$filter]])) {
- $_SESSION['user_overview_filter'][] = array($filter, $form_state['values'][$filter]);
- }
- }
- }
- break;
- case t('Undo'):
- array_pop($_SESSION['user_overview_filter']);
- break;
- case t('Reset'):
- $_SESSION['user_overview_filter'] = array();
- break;
- case t('Update'):
- return;
- }
-
- $form_state['redirect'] = 'admin/people';
- return;
-}
-
-/**
- * Form builder; User administration page.
- *
- * @ingroup forms
- * @see user_admin_account_validate()
- * @see user_admin_account_submit()
- */
-function user_admin_account() {
-
- $header = array(
- 'username' => array('data' => t('Username'), 'field' => 'u.name'),
- 'status' => array('data' => t('Status'), 'field' => 'u.status'),
- 'roles' => array('data' => t('Roles')),
- 'member_for' => array('data' => t('Member for'), 'field' => 'u.created', 'sort' => 'desc'),
- 'access' => array('data' => t('Last access'), 'field' => 'u.access'),
- 'operations' => array('data' => t('Operations')),
- );
-
- $query = db_select('users', 'u');
- $query->condition('u.uid', 0, '<>');
- user_build_filter_query($query);
-
- $count_query = clone $query;
- $count_query->addExpression('COUNT(u.uid)');
-
- $query = $query->extend('PagerDefault')->extend('TableSort');
- $query
- ->fields('u', array('uid', 'name', 'status', 'created', 'access'))
- ->limit(50)
- ->orderByHeader($header)
- ->setCountQuery($count_query);
- $result = $query->execute();
-
- $form['options'] = array(
- '#type' => 'fieldset',
- '#title' => t('Update options'),
- '#attributes' => array('class' => array('container-inline')),
- );
- $options = array();
- foreach (module_invoke_all('user_operations') as $operation => $array) {
- $options[$operation] = $array['label'];
- }
- $form['options']['operation'] = array(
- '#type' => 'select',
- '#title' => t('Operation'),
- '#title_display' => 'invisible',
- '#options' => $options,
- '#default_value' => 'unblock',
- );
- $options = array();
- $form['options']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Update'),
- );
-
- $destination = drupal_get_destination();
-
- $status = array(t('blocked'), t('active'));
- $roles = array_map('check_plain', user_roles(TRUE));
- $accounts = array();
- foreach ($result as $account) {
- $users_roles = array();
- $roles_result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $account->uid));
- foreach ($roles_result as $user_role) {
- $users_roles[] = $roles[$user_role->rid];
- }
- asort($users_roles);
-
- $options[$account->uid] = array(
- 'username' => theme('username', array('account' => $account)),
- 'status' => $status[$account->status],
- 'roles' => theme('item_list', array('items' => $users_roles)),
- 'member_for' => format_interval(REQUEST_TIME - $account->created),
- 'access' => $account->access ? t('@time ago', array('@time' => format_interval(REQUEST_TIME - $account->access))) : t('never'),
- 'operations' => array('data' => array('#type' => 'link', '#title' => t('edit'), '#href' => "user/$account->uid/edit", '#options' => array('query' => $destination))),
- );
- }
-
- $form['accounts'] = array(
- '#type' => 'tableselect',
- '#header' => $header,
- '#options' => $options,
- '#empty' => t('No people available.'),
- );
- $form['pager'] = array('#markup' => theme('pager'));
-
- return $form;
-}
-
-/**
- * Submit the user administration update form.
- */
-function user_admin_account_submit($form, &$form_state) {
- $operations = module_invoke_all('user_operations', $form, $form_state);
- $operation = $operations[$form_state['values']['operation']];
- // Filter out unchecked accounts.
- $accounts = array_filter($form_state['values']['accounts']);
- if ($function = $operation['callback']) {
- // Add in callback arguments if present.
- if (isset($operation['callback arguments'])) {
- $args = array_merge(array($accounts), $operation['callback arguments']);
- }
- else {
- $args = array($accounts);
- }
- call_user_func_array($function, $args);
-
- drupal_set_message(t('The update has been performed.'));
- }
-}
-
-function user_admin_account_validate($form, &$form_state) {
- $form_state['values']['accounts'] = array_filter($form_state['values']['accounts']);
- if (count($form_state['values']['accounts']) == 0) {
- form_set_error('', t('No users selected.'));
- }
-}
-
-/**
- * Form builder; Configure user settings for this site.
- *
- * @ingroup forms
- * @see system_settings_form()
- */
-function user_admin_settings() {
- // Settings for anonymous users.
- $form['anonymous_settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Anonymous users'),
- );
- $form['anonymous_settings']['anonymous'] = array(
- '#type' => 'textfield',
- '#title' => t('Name'),
- '#default_value' => variable_get('anonymous', t('Anonymous')),
- '#description' => t('The name used to indicate anonymous users.'),
- '#required' => TRUE,
- );
-
- // Administrative role option.
- $form['admin_role'] = array(
- '#type' => 'fieldset',
- '#title' => t('Administrator role'),
- );
-
- // Do not allow users to set the anonymous or authenticated user roles as the
- // administrator role.
- $roles = user_roles();
- unset($roles[DRUPAL_ANONYMOUS_RID]);
- unset($roles[DRUPAL_AUTHENTICATED_RID]);
- $roles[0] = t('disabled');
-
- $form['admin_role']['user_admin_role'] = array(
- '#type' => 'select',
- '#title' => t('Administrator role'),
- '#default_value' => variable_get('user_admin_role', 0),
- '#options' => $roles,
- '#description' => t('This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions.'),
- );
-
- // User registration settings.
- $form['registration_cancellation'] = array(
- '#type' => 'fieldset',
- '#title' => t('Registration and cancellation'),
- );
- $form['registration_cancellation']['user_register'] = array(
- '#type' => 'radios',
- '#title' => t('Who can register accounts?'),
- '#default_value' => variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
- '#options' => array(
- USER_REGISTER_ADMINISTRATORS_ONLY => t('Administrators only'),
- USER_REGISTER_VISITORS => t('Visitors'),
- USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => t('Visitors, but administrator approval is required'),
- )
- );
- $form['registration_cancellation']['user_email_verification'] = array(
- '#type' => 'checkbox',
- '#title' => t('Require e-mail verification when a visitor creates an account.'),
- '#default_value' => variable_get('user_email_verification', TRUE),
- '#description' => t('New users will be required to validate their e-mail address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.')
- );
- module_load_include('inc', 'user', 'user.pages');
- $form['registration_cancellation']['user_cancel_method'] = array(
- '#type' => 'item',
- '#title' => t('When cancelling a user account'),
- '#description' => t('Users with the %select-cancel-method or %administer-users
permissions can override this default method.', array('%select-cancel-method' => t('Select method for cancelling account'), '%administer-users' => t('Administer users'), '@permissions-url' => url('admin/people/permissions'))),
- );
- $form['registration_cancellation']['user_cancel_method'] += user_cancel_methods();
- foreach (element_children($form['registration_cancellation']['user_cancel_method']) as $element) {
- // Remove all account cancellation methods that have #access defined, as
- // those cannot be configured as default method.
- if (isset($form['registration_cancellation']['user_cancel_method'][$element]['#access'])) {
- $form['registration_cancellation']['user_cancel_method'][$element]['#access'] = FALSE;
- }
- // Remove the description (only displayed on the confirmation form).
- else {
- unset($form['registration_cancellation']['user_cancel_method'][$element]['#description']);
- }
- }
-
- // Account settings.
- $form['personalization'] = array(
- '#type' => 'fieldset',
- '#title' => t('Personalization'),
- );
- $form['personalization']['user_signatures'] = array(
- '#type' => 'checkbox',
- '#title' => t('Enable signatures.'),
- '#default_value' => variable_get('user_signatures', 0),
- );
- // If picture support is enabled, check whether the picture directory exists.
- if (variable_get('user_pictures', 0)) {
- $picture_path = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures');
- if (!file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY)) {
- form_set_error('user_picture_path', t('The directory %directory does not exist or is not writable.', array('%directory' => $picture_path)));
- watchdog('file system', 'The directory %directory does not exist or is not writable.', array('%directory' => $picture_path), WATCHDOG_ERROR);
- }
- }
- $picture_support = variable_get('user_pictures', 0);
- $form['personalization']['user_pictures'] = array(
- '#type' => 'checkbox',
- '#title' => t('Enable user pictures.'),
- '#default_value' => $picture_support,
- );
- drupal_add_js(drupal_get_path('module', 'user') . '/user.js');
- $form['personalization']['pictures'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the additional picture settings when user pictures are disabled.
- 'invisible' => array(
- 'input[name="user_pictures"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['personalization']['pictures']['user_picture_path'] = array(
- '#type' => 'textfield',
- '#title' => t('Picture directory'),
- '#default_value' => variable_get('user_picture_path', 'pictures'),
- '#size' => 30,
- '#maxlength' => 255,
- '#description' => t('Subdirectory in the file upload directory where pictures will be stored.'),
- );
- $form['personalization']['pictures']['user_picture_default'] = array(
- '#type' => 'textfield',
- '#title' => t('Default picture'),
- '#default_value' => variable_get('user_picture_default', ''),
- '#size' => 30,
- '#maxlength' => 255,
- '#description' => t('URL of picture to display for users with no custom picture selected. Leave blank for none.'),
- );
- if (module_exists('image')) {
- $form['personalization']['pictures']['settings']['user_picture_style'] = array(
- '#type' => 'select',
- '#title' => t('Picture display style'),
- '#options' => image_style_options(TRUE, PASS_THROUGH),
- '#default_value' => variable_get('user_picture_style', ''),
- '#description' => t('The style selected will be used on display, while the original image is retained. Styles may be configured in the
Image styles administration area.', array('!url' => url('admin/config/media/image-styles'))),
- );
- }
- $form['personalization']['pictures']['user_picture_dimensions'] = array(
- '#type' => 'textfield',
- '#title' => t('Picture upload dimensions'),
- '#default_value' => variable_get('user_picture_dimensions', '85x85'),
- '#size' => 10,
- '#maxlength' => 10,
- '#field_suffix' => ' ' . t('pixels'),
- '#description' => t('Pictures larger than this will be scaled down to this size.'),
- );
- $form['personalization']['pictures']['user_picture_file_size'] = array(
- '#type' => 'textfield',
- '#title' => t('Picture upload file size'),
- '#default_value' => variable_get('user_picture_file_size', '30'),
- '#size' => 10,
- '#maxlength' => 10,
- '#field_suffix' => ' ' . t('KB'),
- '#description' => t('Maximum allowed file size for uploaded pictures. Upload size is normally limited only by the PHP maximum post and file upload settings, and images are automatically scaled down to the dimensions specified above.'),
- '#element_validate' => array('element_validate_integer_positive'),
- );
- $form['personalization']['pictures']['user_picture_guidelines'] = array(
- '#type' => 'textarea',
- '#title' => t('Picture guidelines'),
- '#default_value' => variable_get('user_picture_guidelines', ''),
- '#description' => t("This text is displayed at the picture upload form in addition to the default guidelines. It's useful for helping or instructing your users."),
- );
-
- $form['email_title'] = array(
- '#type' => 'item',
- '#title' => t('E-mails'),
- );
- $form['email'] = array(
- '#type' => 'vertical_tabs',
- );
- // These email tokens are shared for all settings, so just define
- // the list once to help ensure they stay in sync.
- $email_token_help = t('Available variables are: [site:name], [site:url], [user:name], [user:mail], [site:login-url], [site:url-brief], [user:edit-url], [user:one-time-login-url], [user:cancel-url].');
-
- $form['email_admin_created'] = array(
- '#type' => 'fieldset',
- '#title' => t('Welcome (new user created by administrator)'),
- '#collapsible' => TRUE,
- '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_ADMINISTRATORS_ONLY),
- '#description' => t('Edit the welcome e-mail messages sent to new member accounts created by an administrator.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_admin_created']['user_mail_register_admin_created_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('register_admin_created_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_admin_created']['user_mail_register_admin_created_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('register_admin_created_body', NULL, array(), FALSE),
- '#rows' => 15,
- );
-
- $form['email_pending_approval'] = array(
- '#type' => 'fieldset',
- '#title' => t('Welcome (awaiting approval)'),
- '#collapsible' => TRUE,
- '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL),
- '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when administrative approval is required.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_pending_approval']['user_mail_register_pending_approval_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('register_pending_approval_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_pending_approval']['user_mail_register_pending_approval_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('register_pending_approval_body', NULL, array(), FALSE),
- '#rows' => 8,
- );
-
- $form['email_no_approval_required'] = array(
- '#type' => 'fieldset',
- '#title' => t('Welcome (no approval required)'),
- '#collapsible' => TRUE,
- '#collapsed' => (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) != USER_REGISTER_VISITORS),
- '#description' => t('Edit the welcome e-mail messages sent to new members upon registering, when no administrator approval is required.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_no_approval_required']['user_mail_register_no_approval_required_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('register_no_approval_required_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_no_approval_required']['user_mail_register_no_approval_required_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('register_no_approval_required_body', NULL, array(), FALSE),
- '#rows' => 15,
- );
-
- $form['email_password_reset'] = array(
- '#type' => 'fieldset',
- '#title' => t('Password recovery'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Edit the e-mail messages sent to users who request a new password.') . ' ' . $email_token_help,
- '#group' => 'email',
- '#weight' => 10,
- );
- $form['email_password_reset']['user_mail_password_reset_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('password_reset_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_password_reset']['user_mail_password_reset_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('password_reset_body', NULL, array(), FALSE),
- '#rows' => 12,
- );
-
- $form['email_activated'] = array(
- '#type' => 'fieldset',
- '#title' => t('Account activation'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Enable and edit e-mail messages sent to users upon account activation (when an administrator activates an account of a user who has already registered, on a site where administrative approval is required).') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_activated']['user_mail_status_activated_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is activated.'),
- '#default_value' => variable_get('user_mail_status_activated_notify', TRUE),
- );
- $form['email_activated']['settings'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the additional settings when this email is disabled.
- 'invisible' => array(
- 'input[name="user_mail_status_activated_notify"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['email_activated']['settings']['user_mail_status_activated_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('status_activated_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_activated']['settings']['user_mail_status_activated_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('status_activated_body', NULL, array(), FALSE),
- '#rows' => 15,
- );
-
- $form['email_blocked'] = array(
- '#type' => 'fieldset',
- '#title' => t('Account blocked'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Enable and edit e-mail messages sent to users when their accounts are blocked.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_blocked']['user_mail_status_blocked_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is blocked.'),
- '#default_value' => variable_get('user_mail_status_blocked_notify', FALSE),
- );
- $form['email_blocked']['settings'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the additional settings when the blocked email is disabled.
- 'invisible' => array(
- 'input[name="user_mail_status_blocked_notify"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['email_blocked']['settings']['user_mail_status_blocked_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('status_blocked_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_blocked']['settings']['user_mail_status_blocked_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('status_blocked_body', NULL, array(), FALSE),
- '#rows' => 3,
- );
-
- $form['email_cancel_confirm'] = array(
- '#type' => 'fieldset',
- '#title' => t('Account cancellation confirmation'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Edit the e-mail messages sent to users when they attempt to cancel their accounts.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_cancel_confirm']['user_mail_cancel_confirm_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('cancel_confirm_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_cancel_confirm']['user_mail_cancel_confirm_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('cancel_confirm_body', NULL, array(), FALSE),
- '#rows' => 3,
- );
-
- $form['email_canceled'] = array(
- '#type' => 'fieldset',
- '#title' => t('Account canceled'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#description' => t('Enable and edit e-mail messages sent to users when their accounts are canceled.') . ' ' . $email_token_help,
- '#group' => 'email',
- );
- $form['email_canceled']['user_mail_status_canceled_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is canceled.'),
- '#default_value' => variable_get('user_mail_status_canceled_notify', FALSE),
- );
- $form['email_canceled']['settings'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the settings when the cancel notify checkbox is disabled.
- 'invisible' => array(
- 'input[name="user_mail_status_canceled_notify"]' => array('checked' => FALSE),
- ),
- ),
- );
- $form['email_canceled']['settings']['user_mail_status_canceled_subject'] = array(
- '#type' => 'textfield',
- '#title' => t('Subject'),
- '#default_value' => _user_mail_text('status_canceled_subject', NULL, array(), FALSE),
- '#maxlength' => 180,
- );
- $form['email_canceled']['settings']['user_mail_status_canceled_body'] = array(
- '#type' => 'textarea',
- '#title' => t('Body'),
- '#default_value' => _user_mail_text('status_canceled_body', NULL, array(), FALSE),
- '#rows' => 3,
- );
-
- return system_settings_form($form);
-}
-
-/**
- * Menu callback: administer permissions.
- *
- * @ingroup forms
- * @see user_admin_permissions_submit()
- * @see theme_user_admin_permissions()
- */
-function user_admin_permissions($form, $form_state, $rid = NULL) {
-
- // Retrieve role names for columns.
- $role_names = user_roles();
- if (is_numeric($rid)) {
- $role_names = array($rid => $role_names[$rid]);
- }
- // Fetch permissions for all roles or the one selected role.
- $role_permissions = user_role_permissions($role_names);
-
- // Store $role_names for use when saving the data.
- $form['role_names'] = array(
- '#type' => 'value',
- '#value' => $role_names,
- );
- // Render role/permission overview:
- $options = array();
- $module_info = system_get_info('module');
- $hide_descriptions = system_admin_compact_mode();
-
- // Get a list of all the modules implementing a hook_permission() and sort by
- // display name.
- $modules = array();
- foreach (module_implements('permission') as $module) {
- $modules[$module] = $module_info[$module]['name'];
- }
- asort($modules);
-
- foreach ($modules as $module => $display_name) {
- if ($permissions = module_invoke($module, 'permission')) {
- $form['permission'][] = array(
- '#markup' => $module_info[$module]['name'],
- '#id' => $module,
- );
- foreach ($permissions as $perm => $perm_item) {
- // Fill in default values for the permission.
- $perm_item += array(
- 'description' => '',
- 'restrict access' => FALSE,
- 'warning' => !empty($perm_item['restrict access']) ? t('Warning: Give to trusted roles only; this permission has security implications.') : '',
- );
- $options[$perm] = '';
- $form['permission'][$perm] = array(
- '#type' => 'item',
- '#markup' => $perm_item['title'],
- '#description' => theme('user_permission_description', array('permission_item' => $perm_item, 'hide' => $hide_descriptions)),
- );
- foreach ($role_names as $rid => $name) {
- // Builds arrays for checked boxes for each role
- if (isset($role_permissions[$rid][$perm])) {
- $status[$rid][] = $perm;
- }
- }
- }
- }
- }
-
- // 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(),
- '#attributes' => array('class' => array('rid-' . $rid)),
- );
- $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
- }
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save permissions'));
-
- $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
-
- return $form;
-}
-
-/**
- * Save permissions selected on the administer permissions page.
- *
- * @see user_admin_permissions()
- */
-function user_admin_permissions_submit($form, &$form_state) {
- foreach ($form_state['values']['role_names'] as $rid => $name) {
- user_role_change_permissions($rid, $form_state['values'][$rid]);
- }
-
- drupal_set_message(t('The changes have been saved.'));
-
- // Clear the cached pages and blocks.
- cache_clear_all();
-}
-
-/**
- * Returns HTML for the administer permissions page.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @ingroup themeable
- */
-function theme_user_admin_permissions($variables) {
- $form = $variables['form'];
-
- $roles = user_roles();
- foreach (element_children($form['permission']) as $key) {
- $row = array();
- // Module name
- if (is_numeric($key)) {
- $row[] = array('data' => drupal_render($form['permission'][$key]), 'class' => array('module'), 'id' => 'module-' . $form['permission'][$key]['#id'], 'colspan' => count($form['role_names']['#value']) + 1);
- }
- else {
- // Permission row.
- $row[] = array(
- 'data' => drupal_render($form['permission'][$key]),
- 'class' => array('permission'),
- );
- foreach (element_children($form['checkboxes']) as $rid) {
- $form['checkboxes'][$rid][$key]['#title'] = $roles[$rid] . ': ' . $form['permission'][$key]['#markup'];
- $form['checkboxes'][$rid][$key]['#title_display'] = 'invisible';
- $row[] = array('data' => drupal_render($form['checkboxes'][$rid][$key]), 'class' => array('checkbox'));
- }
- }
- $rows[] = $row;
- }
- $header[] = (t('Permission'));
- foreach (element_children($form['role_names']) as $rid) {
- $header[] = array('data' => drupal_render($form['role_names'][$rid]), 'class' => array('checkbox'));
- }
- $output = theme('system_compact_link');
- $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'permissions')));
- $output .= drupal_render_children($form);
- return $output;
-}
-
-/**
- * Returns HTML for an individual permission description.
- *
- * @param $variables
- * An associative array containing:
- * - permission_item: An associative array representing the permission whose
- * description is being themed. Useful keys include:
- * - description: The text of the permission description.
- * - warning: A security-related warning message about the permission (if
- * there is one).
- * - hide: A boolean indicating whether or not the permission description was
- * requested to be hidden rather than shown.
- *
- * @ingroup themeable
- */
-function theme_user_permission_description($variables) {
- if (!$variables['hide']) {
- $description = array();
- $permission_item = $variables['permission_item'];
- if (!empty($permission_item['description'])) {
- $description[] = $permission_item['description'];
- }
- if (!empty($permission_item['warning'])) {
- $description[] = '
' . $permission_item['warning'] . ' ';
- }
- if (!empty($description)) {
- return implode(' ', $description);
- }
- }
-}
-
-/**
- * Form to re-order roles or add a new one.
- *
- * @ingroup forms
- * @see theme_user_admin_roles()
- */
-function user_admin_roles($form, $form_state) {
- $roles = user_roles();
-
- $form['roles'] = array(
- '#tree' => TRUE,
- );
- $order = 0;
- foreach ($roles as $rid => $name) {
- $form['roles'][$rid]['#role'] = (object) array(
- 'rid' => $rid,
- 'name' => $name,
- 'weight' => $order,
- );
- $form['roles'][$rid]['#weight'] = $order;
- $form['roles'][$rid]['weight'] = array(
- '#type' => 'textfield',
- '#title' => t('Weight for @title', array('@title' => $name)),
- '#title_display' => 'invisible',
- '#size' => 4,
- '#default_value' => $order,
- '#attributes' => array('class' => array('role-weight')),
- );
- $order++;
- }
-
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Name'),
- '#title_display' => 'invisible',
- '#size' => 32,
- '#maxlength' => 64,
- );
- $form['add'] = array(
- '#type' => 'submit',
- '#value' => t('Add role'),
- '#validate' => array('user_admin_role_validate'),
- '#submit' => array('user_admin_role_submit'),
- );
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save order'),
- '#submit' => array('user_admin_roles_order_submit'),
- );
-
- return $form;
-}
-
-/**
- * Form submit function. Update the role weights.
- */
-function user_admin_roles_order_submit($form, &$form_state) {
- foreach ($form_state['values']['roles'] as $rid => $role_values) {
- $role = $form['roles'][$rid]['#role'];
- $role->weight = $role_values['weight'];
- user_role_save($role);
- }
- drupal_set_message(t('The role settings have been updated.'));
-}
-
-/**
- * Returns HTML for the role order and new role form.
- *
- * @param $variables
- * An associative array containing:
- * - form: A render element representing the form.
- *
- * @ingroup themeable
- */
-function theme_user_admin_roles($variables) {
- $form = $variables['form'];
-
- $header = array(t('Name'), t('Weight'), array('data' => t('Operations'), 'colspan' => 2));
- foreach (element_children($form['roles']) as $rid) {
- $name = $form['roles'][$rid]['#role']->name;
- $row = array();
- if (in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
- $row[] = t('@name
(locked) ', array('@name' => $name));
- $row[] = drupal_render($form['roles'][$rid]['weight']);
- $row[] = '';
- $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
- }
- else {
- $row[] = check_plain($name);
- $row[] = drupal_render($form['roles'][$rid]['weight']);
- $row[] = l(t('edit role'), 'admin/people/permissions/roles/edit/' . $rid);
- $row[] = l(t('edit permissions'), 'admin/people/permissions/' . $rid);
- }
- $rows[] = array('data' => $row, 'class' => array('draggable'));
- }
- $rows[] = array(array('data' => drupal_render($form['name']) . drupal_render($form['add']), 'colspan' => 4, 'class' => 'edit-name'));
-
- drupal_add_tabledrag('user-roles', 'order', 'sibling', 'role-weight');
-
- $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'user-roles')));
- $output .= drupal_render_children($form);
-
- return $output;
-}
-
-/**
- * Form to configure a single role.
- *
- * @ingroup forms
- * @see user_admin_role_validate()
- * @see user_admin_role_submit()
- */
-function user_admin_role($form, $form_state, $role) {
- if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) {
- drupal_goto('admin/people/permissions/roles');
- }
-
- // Display the edit role form.
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Role name'),
- '#default_value' => $role->name,
- '#size' => 30,
- '#required' => TRUE,
- '#maxlength' => 64,
- '#description' => t('The name for this role. Example: "moderator", "editorial board", "site architect".'),
- );
- $form['rid'] = array(
- '#type' => 'value',
- '#value' => $role->rid,
- );
- $form['weight'] = array(
- '#type' => 'value',
- '#value' => $role->weight,
- );
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save role'),
- );
- $form['actions']['delete'] = array(
- '#type' => 'submit',
- '#value' => t('Delete role'),
- '#submit' => array('user_admin_role_delete_submit'),
- );
-
- return $form;
-}
-
-/**
- * Form validation handler for the user_admin_role() form.
- */
-function user_admin_role_validate($form, &$form_state) {
- if (!empty($form_state['values']['name'])) {
- if ($form_state['values']['op'] == t('Save role')) {
- $role = user_role_load_by_name($form_state['values']['name']);
- if ($role && $role->rid != $form_state['values']['rid']) {
- form_set_error('name', t('The role name %name already exists. Choose another role name.', array('%name' => $form_state['values']['name'])));
- }
- }
- elseif ($form_state['values']['op'] == t('Add role')) {
- if (user_role_load_by_name($form_state['values']['name'])) {
- form_set_error('name', t('The role name %name already exists. Choose another role name.', array('%name' => $form_state['values']['name'])));
- }
- }
- }
- else {
- form_set_error('name', t('You must specify a valid role name.'));
- }
-}
-
-/**
- * Form submit handler for the user_admin_role() form.
- */
-function user_admin_role_submit($form, &$form_state) {
- $role = (object) $form_state['values'];
- if ($form_state['values']['op'] == t('Save role')) {
- user_role_save($role);
- drupal_set_message(t('The role has been renamed.'));
- }
- elseif ($form_state['values']['op'] == t('Add role')) {
- user_role_save($role);
- drupal_set_message(t('The role has been added.'));
- }
- $form_state['redirect'] = 'admin/people/permissions/roles';
- return;
-}
-
-/**
- * Form submit handler for the user_admin_role() form.
- */
-function user_admin_role_delete_submit($form, &$form_state) {
- $form_state['redirect'] = 'admin/people/permissions/roles/delete/' . $form_state['values']['rid'];
-}
-
-/**
- * Form to confirm role delete operation.
- */
-function user_admin_role_delete_confirm($form, &$form_state, $role) {
- $form['rid'] = array(
- '#type' => 'value',
- '#value' => $role->rid,
- );
- return confirm_form($form, t('Are you sure you want to delete the role %name ?', array('%name' => $role->name)), 'admin/people/permissions/roles', t('This action cannot be undone.'), t('Delete'));
-}
-
-/**
- * Form submit handler for user_admin_role_delete_confirm().
- */
-function user_admin_role_delete_confirm_submit($form, &$form_state) {
- user_role_delete((int) $form_state['values']['rid']);
- drupal_set_message(t('The role has been deleted.'));
- $form_state['redirect'] = 'admin/people/permissions/roles';
-}
-
diff --git a/modules/user/user.api.php b/modules/user/user.api.php
deleted file mode 100644
index 3afc88ab..00000000
--- a/modules/user/user.api.php
+++ /dev/null
@@ -1,469 +0,0 @@
- array_keys($users)));
- foreach ($result as $record) {
- $users[$record->uid]->foo = $record->foo;
- }
-}
-
-/**
- * Respond to user deletion.
- *
- * This hook is invoked from user_delete_multiple() before field_attach_delete()
- * is called and before users are actually removed from the database.
- *
- * Modules should additionally implement hook_user_cancel() to process stored
- * user data for other account cancellation methods.
- *
- * @param $account
- * The account that is being deleted.
- *
- * @see user_delete_multiple()
- */
-function hook_user_delete($account) {
- db_delete('mytable')
- ->condition('uid', $account->uid)
- ->execute();
-}
-
-/**
- * Act on user account cancellations.
- *
- * This hook is invoked from user_cancel() before a user account is canceled.
- * Depending on the account cancellation method, the module should either do
- * nothing, unpublish content, or anonymize content. See user_cancel_methods()
- * for the list of default account cancellation methods provided by User module.
- * Modules may add further methods via hook_user_cancel_methods_alter().
- *
- * This hook is NOT invoked for the 'user_cancel_delete' account cancellation
- * method. To react on this method, implement hook_user_delete() instead.
- *
- * Expensive operations should be added to the global account cancellation batch
- * by using batch_set().
- *
- * @param $edit
- * The array of form values submitted by the user.
- * @param $account
- * The user object on which the operation is being performed.
- * @param $method
- * The account cancellation method.
- *
- * @see user_cancel_methods()
- * @see hook_user_cancel_methods_alter()
- */
-function hook_user_cancel($edit, $account, $method) {
- switch ($method) {
- case 'user_cancel_block_unpublish':
- // Unpublish nodes (current revisions).
- module_load_include('inc', 'node', 'node.admin');
- $nodes = db_select('node', 'n')
- ->fields('n', array('nid'))
- ->condition('uid', $account->uid)
- ->execute()
- ->fetchCol();
- node_mass_update($nodes, array('status' => 0));
- break;
-
- case 'user_cancel_reassign':
- // Anonymize nodes (current revisions).
- module_load_include('inc', 'node', 'node.admin');
- $nodes = db_select('node', 'n')
- ->fields('n', array('nid'))
- ->condition('uid', $account->uid)
- ->execute()
- ->fetchCol();
- node_mass_update($nodes, array('uid' => 0));
- // Anonymize old revisions.
- db_update('node_revision')
- ->fields(array('uid' => 0))
- ->condition('uid', $account->uid)
- ->execute();
- // Clean history.
- db_delete('history')
- ->condition('uid', $account->uid)
- ->execute();
- break;
- }
-}
-
-/**
- * Modify account cancellation methods.
- *
- * By implementing this hook, modules are able to add, customize, or remove
- * account cancellation methods. All defined methods are turned into radio
- * button form elements by user_cancel_methods() after this hook is invoked.
- * The following properties can be defined for each method:
- * - title: The radio button's title.
- * - description: (optional) A description to display on the confirmation form
- * if the user is not allowed to select the account cancellation method. The
- * description is NOT used for the radio button, but instead should provide
- * additional explanation to the user seeking to cancel their account.
- * - access: (optional) A boolean value indicating whether the user can access
- * a method. If #access is defined, the method cannot be configured as default
- * method.
- *
- * @param $methods
- * An array containing user account cancellation methods, keyed by method id.
- *
- * @see user_cancel_methods()
- * @see user_cancel_confirm_form()
- */
-function hook_user_cancel_methods_alter(&$methods) {
- // Limit access to disable account and unpublish content method.
- $methods['user_cancel_block_unpublish']['access'] = user_access('administer site configuration');
-
- // Remove the content re-assigning method.
- unset($methods['user_cancel_reassign']);
-
- // Add a custom zero-out method.
- $methods['mymodule_zero_out'] = array(
- 'title' => t('Delete the account and remove all content.'),
- 'description' => t('All your content will be replaced by empty strings.'),
- // access should be used for administrative methods only.
- 'access' => user_access('access zero-out account cancellation method'),
- );
-}
-
-/**
- * Add mass user operations.
- *
- * This hook enables modules to inject custom operations into the mass operations
- * dropdown found at admin/people, by associating a callback function with
- * the operation, which is called when the form is submitted. The callback function
- * receives one initial argument, which is an array of the checked users.
- *
- * @return
- * An array of operations. Each operation is an associative array that may
- * contain the following key-value pairs:
- * - "label": Required. The label for the operation, displayed in the dropdown menu.
- * - "callback": Required. The function to call for the operation.
- * - "callback arguments": Optional. An array of additional arguments to pass to
- * the callback function.
- *
- */
-function hook_user_operations() {
- $operations = array(
- 'unblock' => array(
- 'label' => t('Unblock the selected users'),
- 'callback' => 'user_user_operations_unblock',
- ),
- 'block' => array(
- 'label' => t('Block the selected users'),
- 'callback' => 'user_user_operations_block',
- ),
- 'cancel' => array(
- 'label' => t('Cancel the selected user accounts'),
- ),
- );
- return $operations;
-}
-
-/**
- * Retrieve a list of user setting or profile information categories.
- *
- * @return
- * An array of associative arrays. Each inner array has elements:
- * - "name": The internal name of the category.
- * - "title": The human-readable, localized name of the category.
- * - "weight": An integer specifying the category's sort ordering.
- * - "access callback": Name of the access callback function to use to
- * determine whether the user can edit the category. Defaults to using
- * user_edit_access(). See hook_menu() for more information on access
- * callbacks.
- * - "access arguments": Arguments for the access callback function. Defaults
- * to array(1).
- */
-function hook_user_categories() {
- return array(array(
- 'name' => 'account',
- 'title' => t('Account settings'),
- 'weight' => 1,
- ));
-}
-
-/**
- * A user account is about to be created or updated.
- *
- * This hook is primarily intended for modules that want to store properties in
- * the serialized {users}.data column, which is automatically loaded whenever a
- * user account object is loaded, modules may add to $edit['data'] in order
- * to have their data serialized on save.
- *
- * @param $edit
- * The array of form values submitted by the user. Assign values to this
- * array to save changes in the database.
- * @param $account
- * The user object on which the operation is performed. Values assigned in
- * this object will not be saved in the database.
- * @param $category
- * The active category of user information being edited.
- *
- * @see hook_user_insert()
- * @see hook_user_update()
- */
-function hook_user_presave(&$edit, $account, $category) {
- // Make sure that our form value 'mymodule_foo' is stored as
- // 'mymodule_bar' in the 'data' (serialized) column.
- if (isset($edit['mymodule_foo'])) {
- $edit['data']['mymodule_bar'] = $edit['mymodule_foo'];
- }
-}
-
-/**
- * A user account was created.
- *
- * The module should save its custom additions to the user object into the
- * database.
- *
- * @param $edit
- * The array of form values submitted by the user.
- * @param $account
- * The user object on which the operation is being performed.
- * @param $category
- * The active category of user information being edited.
- *
- * @see hook_user_presave()
- * @see hook_user_update()
- */
-function hook_user_insert(&$edit, $account, $category) {
- db_insert('mytable')
- ->fields(array(
- 'myfield' => $edit['myfield'],
- 'uid' => $account->uid,
- ))
- ->execute();
-}
-
-/**
- * A user account was updated.
- *
- * Modules may use this hook to update their user data in a custom storage
- * after a user account has been updated.
- *
- * @param $edit
- * The array of form values submitted by the user.
- * @param $account
- * The user object on which the operation is performed.
- * @param $category
- * The active category of user information being edited.
- *
- * @see hook_user_presave()
- * @see hook_user_insert()
- */
-function hook_user_update(&$edit, $account, $category) {
- db_insert('user_changes')
- ->fields(array(
- 'uid' => $account->uid,
- 'changed' => time(),
- ))
- ->execute();
-}
-
-/**
- * The user just logged in.
- *
- * @param $edit
- * The array of form values submitted by the user.
- * @param $account
- * The user object on which the operation was just performed.
- */
-function hook_user_login(&$edit, $account) {
- // If the user has a NULL time zone, notify them to set a time zone.
- if (!$account->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', 0)) {
- drupal_set_message(t('Configure your
account time zone setting .', array('@user-edit' => url("user/$account->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone')))));
- }
-}
-
-/**
- * The user just logged out.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the save operation is entirely completed
- * and user_save() goes out of scope. You should not rely on data in the
- * database at this time as it is not updated yet. You should also note that any
- * write/update database queries executed from this hook are also not committed
- * immediately. Check user_save() and db_transaction() for more info.
- *
- * @param $account
- * The user object on which the operation was just performed.
- */
-function hook_user_logout($account) {
- db_insert('logouts')
- ->fields(array(
- 'uid' => $account->uid,
- 'time' => time(),
- ))
- ->execute();
-}
-
-/**
- * The user's account information is being displayed.
- *
- * The module should format its custom additions for display and add them to the
- * $account->content array.
- *
- * Note that when this hook is invoked, the changes have not yet been written to
- * the database, because a database transaction is still in progress. The
- * transaction is not finalized until the save operation is entirely completed
- * and user_save() goes out of scope. You should not rely on data in the
- * database at this time as it is not updated yet. You should also note that any
- * write/update database queries executed from this hook are also not committed
- * immediately. Check user_save() and db_transaction() for more info.
- *
- * @param $account
- * The user object on which the operation is being performed.
- * @param $view_mode
- * View mode, e.g. 'full'.
- * @param $langcode
- * The language code used for rendering.
- *
- * @see hook_user_view_alter()
- * @see hook_entity_view()
- */
-function hook_user_view($account, $view_mode, $langcode) {
- if (user_access('create blog content', $account)) {
- $account->content['summary']['blog'] = array(
- '#type' => 'user_profile_item',
- '#title' => t('Blog'),
- '#markup' => l(t('View recent blog entries'), "blog/$account->uid", array('attributes' => array('title' => t("Read !username's latest blog entries.", array('!username' => format_username($account)))))),
- '#attributes' => array('class' => array('blog')),
- );
- }
-}
-
-/**
- * The user was built; the module may modify the structured content.
- *
- * This hook is called after the content has been assembled in a structured array
- * and may be used for doing processing which requires that the complete user
- * content structure has been built.
- *
- * If the module wishes to act on the rendered HTML of the user rather than the
- * structured content array, it may use this hook to add a #post_render callback.
- * Alternatively, it could also implement hook_preprocess_user_profile(). See
- * drupal_render() and theme() documentation respectively for details.
- *
- * @param $build
- * A renderable array representing the user.
- *
- * @see user_view()
- * @see hook_entity_view_alter()
- */
-function hook_user_view_alter(&$build) {
- // Check for the existence of a field added by another module.
- if (isset($build['an_additional_field'])) {
- // Change its weight.
- $build['an_additional_field']['#weight'] = -10;
- }
-
- // Add a #post_render callback to act on the rendered HTML of the user.
- $build['#post_render'][] = 'my_module_user_post_render';
-}
-
-/**
- * Inform other modules that a user role is about to be saved.
- *
- * Modules implementing this hook can act on the user role object before
- * it has been saved to the database.
- *
- * @param $role
- * A user role object.
- *
- * @see hook_user_role_insert()
- * @see hook_user_role_update()
- */
-function hook_user_role_presave($role) {
- // Set a UUID for the user role if it doesn't already exist
- if (empty($role->uuid)) {
- $role->uuid = uuid_uuid();
- }
-}
-
-/**
- * Inform other modules that a user role has been added.
- *
- * Modules implementing this hook can act on the user role object when saved to
- * the database. It's recommended that you implement this hook if your module
- * adds additional data to user roles object. The module should save its custom
- * additions to the database.
- *
- * @param $role
- * A user role object.
- */
-function hook_user_role_insert($role) {
- // Save extra fields provided by the module to user roles.
- db_insert('my_module_table')
- ->fields(array(
- 'rid' => $role->rid,
- 'role_description' => $role->description,
- ))
- ->execute();
-}
-
-/**
- * Inform other modules that a user role has been updated.
- *
- * Modules implementing this hook can act on the user role object when updated.
- * It's recommended that you implement this hook if your module adds additional
- * data to user roles object. The module should save its custom additions to
- * the database.
- *
- * @param $role
- * A user role object.
- */
-function hook_user_role_update($role) {
- // Save extra fields provided by the module to user roles.
- db_merge('my_module_table')
- ->key(array('rid' => $role->rid))
- ->fields(array(
- 'role_description' => $role->description
- ))
- ->execute();
-}
-
-/**
- * Inform other modules that a user role has been deleted.
- *
- * This hook allows you act when a user role has been deleted.
- * If your module stores references to roles, it's recommended that you
- * implement this hook and delete existing instances of the deleted role
- * in your module database tables.
- *
- * @param $role
- * The $role object being deleted.
- */
-function hook_user_role_delete($role) {
- // Delete existing instances of the deleted role.
- db_delete('my_module_table')
- ->condition('rid', $role->rid)
- ->execute();
-}
-
-/**
- * @} End of "addtogroup hooks".
- */
diff --git a/modules/user/user.css b/modules/user/user.css
deleted file mode 100644
index 079ec38a..00000000
--- a/modules/user/user.css
+++ /dev/null
@@ -1,102 +0,0 @@
-
-#permissions td.module {
- font-weight: bold;
-}
-#permissions td.permission {
- padding-left: 1.5em; /* LTR */
-}
-#permissions tr.odd .form-item,
-#permissions tr.even .form-item {
- white-space: normal;
-}
-#user-admin-settings fieldset .fieldset-description {
- font-size: 0.85em;
- padding-bottom: .5em;
-}
-
-/**
- * Override default textfield float to put the "Add role" button next to
- * the input textfield.
- */
-#user-admin-roles td.edit-name {
- clear: both;
-}
-#user-admin-roles .form-item-name {
- float: left; /* LTR */
- margin-right: 1em; /* LTR */
-}
-
-/**
- * Password strength indicator.
- */
-.password-strength {
- width: 17em;
- float: right; /* LTR */
- margin-top: 1.4em;
-}
-.password-strength-title {
- display: inline;
-}
-.password-strength-text {
- float: right; /* LTR */
- font-weight: bold;
-}
-.password-indicator {
- background-color: #C4C4C4;
- height: 0.3em;
- width: 100%;
-}
-.password-indicator div {
- height: 100%;
- width: 0%;
- background-color: #47C965;
-}
-input.password-confirm,
-input.password-field {
- width: 16em;
- margin-bottom: 0.4em;
-}
-div.password-confirm {
- float: right; /* LTR */
- margin-top: 1.5em;
- visibility: hidden;
- width: 17em;
-}
-div.form-item div.password-suggestions {
- padding: 0.2em 0.5em;
- margin: 0.7em 0;
- width: 38.5em;
- border: 1px solid #B4B4B4;
-}
-div.password-suggestions ul {
- margin-bottom: 0;
-}
-.confirm-parent,
-.password-parent {
- clear: left; /* LTR */
- margin: 0;
- width: 36.3em;
-}
-
-/* Generated by user.module but used by profile.module: */
-.profile {
- clear: both;
- margin: 1em 0;
-}
-.profile .user-picture {
- float: right; /* LTR */
- margin: 0 1em 1em 0; /* LTR */
-}
-.profile h3 {
- border-bottom: 1px solid #ccc;
-}
-.profile dl {
- margin: 0 0 1.5em 0;
-}
-.profile dt {
- margin: 0 0 0.2em 0;
- font-weight: bold;
-}
-.profile dd {
- margin: 0 0 1em 0;
-}
diff --git a/modules/user/user.info b/modules/user/user.info
deleted file mode 100644
index 786a092d..00000000
--- a/modules/user/user.info
+++ /dev/null
@@ -1,16 +0,0 @@
-name = User
-description = Manages the user registration and login system.
-package = Core
-version = VERSION
-core = 7.x
-files[] = user.module
-files[] = user.test
-required = TRUE
-configure = admin/config/people
-stylesheets[all][] = user.css
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/modules/user/user.install b/modules/user/user.install
deleted file mode 100644
index 4e1a3c22..00000000
--- a/modules/user/user.install
+++ /dev/null
@@ -1,913 +0,0 @@
- 'Stores distributed authentication mapping.',
- 'fields' => array(
- 'aid' => array(
- 'description' => 'Primary Key: Unique authmap ID.',
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- ),
- 'uid' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => "User's {users}.uid.",
- ),
- 'authname' => array(
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Unique authentication name.',
- ),
- 'module' => array(
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Module which is controlling the authentication.',
- ),
- ),
- 'unique keys' => array(
- 'authname' => array('authname'),
- ),
- 'primary key' => array('aid'),
- 'foreign keys' => array(
- 'user' => array(
- 'table' => 'users',
- 'columns' => array('uid' => 'uid'),
- ),
- ),
- );
-
- $schema['role_permission'] = array(
- 'description' => 'Stores the permissions assigned to user roles.',
- 'fields' => array(
- 'rid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'description' => 'Foreign Key: {role}.rid.',
- ),
- 'permission' => array(
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'A single permission granted to the role identified by rid.',
- ),
- 'module' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "The module declaring the permission.",
- ),
- ),
- 'primary key' => array('rid', 'permission'),
- 'indexes' => array(
- 'permission' => array('permission'),
- ),
- 'foreign keys' => array(
- 'role' => array(
- 'table' => 'roles',
- 'columns' => array('rid' => 'rid'),
- ),
- ),
- );
-
- $schema['role'] = array(
- 'description' => 'Stores user roles.',
- 'fields' => array(
- 'rid' => array(
- 'type' => 'serial',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'description' => 'Primary Key: Unique role ID.',
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Unique role name.',
- 'translatable' => TRUE,
- ),
- 'weight' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The weight of this role in listings and the user interface.',
- ),
- ),
- 'unique keys' => array(
- 'name' => array('name'),
- ),
- 'primary key' => array('rid'),
- 'indexes' => array(
- 'name_weight' => array('name', 'weight'),
- ),
- );
-
- // The table name here is plural, despite Drupal table naming standards,
- // because "user" is a reserved word in many databases.
- $schema['users'] = array(
- 'description' => 'Stores user data.',
- 'fields' => array(
- 'uid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'description' => 'Primary Key: Unique user ID.',
- 'default' => 0,
- ),
- 'name' => array(
- 'type' => 'varchar',
- 'length' => 60,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'Unique user name.',
- ),
- 'pass' => array(
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "User's password (hashed).",
- ),
- 'mail' => array(
- 'type' => 'varchar',
- 'length' => 254,
- 'not null' => FALSE,
- 'default' => '',
- 'description' => "User's e-mail address.",
- ),
- 'theme' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "User's default theme.",
- ),
- 'signature' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "User's signature.",
- ),
- 'signature_format' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the signature.',
- ),
- 'created' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Timestamp for when user was created.',
- ),
- 'access' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Timestamp for previous time user accessed the site.',
- ),
- 'login' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => "Timestamp for user's last login.",
- ),
- 'status' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'size' => 'tiny',
- 'description' => 'Whether the user is active(1) or blocked(0).',
- ),
- 'timezone' => array(
- 'type' => 'varchar',
- 'length' => 32,
- 'not null' => FALSE,
- 'description' => "User's time zone.",
- ),
- 'language' => array(
- 'type' => 'varchar',
- 'length' => 12,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "User's default language.",
- ),
- 'picture' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => "Foreign key: {file_managed}.fid of user's picture.",
- ),
- 'init' => array(
- 'type' => 'varchar',
- 'length' => 254,
- 'not null' => FALSE,
- 'default' => '',
- 'description' => 'E-mail address used for initial account creation.',
- ),
- 'data' => array(
- 'type' => 'blob',
- 'not null' => FALSE,
- 'size' => 'big',
- 'serialize' => TRUE,
- 'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.',
- ),
- ),
- 'indexes' => array(
- 'access' => array('access'),
- 'created' => array('created'),
- 'mail' => array('mail'),
- 'picture' => array('picture'),
- ),
- 'unique keys' => array(
- 'name' => array('name'),
- ),
- 'primary key' => array('uid'),
- 'foreign keys' => array(
- 'signature_format' => array(
- 'table' => 'filter_format',
- 'columns' => array('signature_format' => 'format'),
- ),
- ),
- );
-
- $schema['users_roles'] = array(
- 'description' => 'Maps users to roles.',
- 'fields' => array(
- 'uid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: {users}.uid for user.',
- ),
- 'rid' => array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'Primary Key: {role}.rid for role.',
- ),
- ),
- 'primary key' => array('uid', 'rid'),
- 'indexes' => array(
- 'rid' => array('rid'),
- ),
- 'foreign keys' => array(
- 'user' => array(
- 'table' => 'users',
- 'columns' => array('uid' => 'uid'),
- ),
- 'role' => array(
- 'table' => 'roles',
- 'columns' => array('rid' => 'rid'),
- ),
- ),
- );
-
- return $schema;
-}
-
-/**
- * Implements hook_install().
- */
-function user_install() {
- // Insert a row for the anonymous user.
- db_insert('users')
- ->fields(array(
- 'uid' => 0,
- 'name' => '',
- 'mail' => '',
- ))
- ->execute();
-
- // We need some placeholders here as name and mail are uniques and data is
- // presumed to be a serialized array. This will be changed by the settings
- // form in the installer.
- db_insert('users')
- ->fields(array(
- 'uid' => 1,
- 'name' => 'placeholder-for-uid-1',
- 'mail' => 'placeholder-for-uid-1',
- 'created' => REQUEST_TIME,
- 'status' => 1,
- 'data' => NULL,
- ))
- ->execute();
-
- // Built-in roles.
- $rid_anonymous = db_insert('role')
- ->fields(array('name' => 'anonymous user', 'weight' => 0))
- ->execute();
- $rid_authenticated = db_insert('role')
- ->fields(array('name' => 'authenticated user', 'weight' => 1))
- ->execute();
-
- // Sanity check to ensure the anonymous and authenticated role IDs are the
- // same as the drupal defined constants. In certain situations, this will
- // not be true.
- if ($rid_anonymous != DRUPAL_ANONYMOUS_RID) {
- db_update('role')
- ->fields(array('rid' => DRUPAL_ANONYMOUS_RID))
- ->condition('rid', $rid_anonymous)
- ->execute();
- }
- if ($rid_authenticated != DRUPAL_AUTHENTICATED_RID) {
- db_update('role')
- ->fields(array('rid' => DRUPAL_AUTHENTICATED_RID))
- ->condition('rid', $rid_authenticated)
- ->execute();
- }
-}
-
-/**
- * Implements hook_update_dependencies().
- */
-function user_update_dependencies() {
- // user_update_7006() updates data in the {role_permission} table, so it must
- // run after system_update_7007(), which populates that table.
- $dependencies['user'][7006] = array(
- 'system' => 7007,
- );
-
- // user_update_7010() needs to query the {filter_format} table to get a list
- // of existing text formats, so it must run after filter_update_7000(), which
- // creates that table.
- $dependencies['user'][7010] = array(
- 'filter' => 7000,
- );
-
- // user_update_7012() uses the file API, which relies on the {file_managed}
- // table, so it must run after system_update_7034(), which creates that
- // table.
- $dependencies['user'][7012] = array(
- 'system' => 7034,
- );
-
- // user_update_7013() uses the file usage API, which relies on the
- // {file_usage} table, so it must run after system_update_7059(), which
- // creates that table.
- $dependencies['user'][7013] = array(
- 'system' => 7059,
- );
-
- return $dependencies;
-}
-
-/**
- * Utility function: grant a set of permissions to a role during update.
- *
- * This function is valid for a database schema version 7000.
- *
- * @param $rid
- * The role ID.
- * @param $permissions
- * An array of permissions names.
- * @param $module
- * The name of the module defining the permissions.
- * @ingroup update_api
- */
-function _update_7000_user_role_grant_permissions($rid, array $permissions, $module) {
- // Grant new permissions for the role.
- foreach ($permissions as $name) {
- db_merge('role_permission')
- ->key(array(
- 'rid' => $rid,
- 'permission' => $name,
- ))
- ->fields(array(
- 'module' => $module,
- ))
- ->execute();
- }
-}
-
-/**
- * @addtogroup updates-6.x-to-7.x
- * @{
- */
-
-/**
- * Increase the length of the password field to accommodate better hashes.
- *
- * Also re-hashes all current passwords to improve security. This may be a
- * lengthy process, and is performed batch-wise.
- */
-function user_update_7000(&$sandbox) {
- $sandbox['#finished'] = 0;
- // Lower than DRUPAL_HASH_COUNT to make the update run at a reasonable speed.
- $hash_count_log2 = 11;
- // Multi-part update.
- if (!isset($sandbox['user_from'])) {
- db_change_field('users', 'pass', 'pass', array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''));
- $sandbox['user_from'] = 0;
- $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
- }
- else {
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- // Hash again all current hashed passwords.
- $has_rows = FALSE;
- // Update this many per page load.
- $count = 1000;
- $result = db_query_range("SELECT uid, pass FROM {users} WHERE uid > 0 ORDER BY uid", $sandbox['user_from'], $count);
- foreach ($result as $account) {
- $has_rows = TRUE;
-
- // If the $account->pass value is not a MD5 hash (a 32 character
- // hexadecimal string) then skip it.
- if (!preg_match('/^[0-9a-f]{32}$/', $account->pass)) {
- continue;
- }
-
- $new_hash = user_hash_password($account->pass, $hash_count_log2);
- if ($new_hash) {
- // Indicate an updated password.
- $new_hash = 'U' . $new_hash;
- db_update('users')
- ->fields(array('pass' => $new_hash))
- ->condition('uid', $account->uid)
- ->execute();
- }
- }
- $sandbox['#finished'] = $sandbox['user_from']/$sandbox['user_count'];
- $sandbox['user_from'] += $count;
- if (!$has_rows) {
- $sandbox['#finished'] = 1;
- return t('User passwords rehashed to improve security');
- }
- }
-}
-
-/**
- * Remove the 'threshold', 'mode' and 'sort' columns from the {users} table.
- *
- * These fields were previously used to store per-user comment settings.
- */
-
-function user_update_7001() {
- db_drop_field('users', 'threshold');
- db_drop_field('users', 'mode');
- db_drop_field('users', 'sort');
-}
-
-/**
- * Convert user time zones from time zone offsets to time zone names.
- */
-function user_update_7002(&$sandbox) {
- $sandbox['#finished'] = 0;
-
- // Multi-part update.
- if (!isset($sandbox['user_from'])) {
- db_change_field('users', 'timezone', 'timezone', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE));
- $sandbox['user_from'] = 0;
- $sandbox['user_count'] = db_query("SELECT COUNT(uid) FROM {users}")->fetchField();
- $sandbox['user_not_migrated'] = 0;
- }
- else {
- $timezones = system_time_zones();
- // Update this many per page load.
- $count = 10000;
- $contributed_date_module = db_field_exists('users', 'timezone_name');
- $contributed_event_module = db_field_exists('users', 'timezone_id');
-
- $results = db_query_range("SELECT uid FROM {users} ORDER BY uid", $sandbox['user_from'], $count);
- foreach ($results as $account) {
- $timezone = NULL;
- // If the contributed Date module has created a users.timezone_name
- // column, use this data to set each user's time zone.
- if ($contributed_date_module) {
- $date_timezone = db_query("SELECT timezone_name FROM {users} WHERE uid = :uid", array(':uid' => $account->uid))->fetchField();
- if (isset($timezones[$date_timezone])) {
- $timezone = $date_timezone;
- }
- }
- // If the contributed Event module has stored user time zone information
- // use that information to update the user accounts.
- if (!$timezone && $contributed_event_module) {
- try {
- $event_timezone = db_query("SELECT t.name FROM {users} u LEFT JOIN {event_timezones} t ON u.timezone_id = t.timezone WHERE u.uid = :uid", array(':uid' => $account->uid))->fetchField();
- $event_timezone = str_replace(' ', '_', $event_timezone);
- if (isset($timezones[$event_timezone])) {
- $timezone = $event_timezone;
- }
- }
- catch (PDOException $e) {
- // Ignore error if event_timezones table does not exist or unexpected
- // schema found.
- }
- }
- if ($timezone) {
- db_update('users')
- ->fields(array('timezone' => $timezone))
- ->condition('uid', $account->uid)
- ->execute();
- }
- else {
- $sandbox['user_not_migrated']++;
- db_update('users')
- ->fields(array('timezone' => NULL))
- ->condition('uid', $account->uid)
- ->execute();
- }
- $sandbox['user_from']++;
- }
-
- $sandbox['#finished'] = $sandbox['user_from'] / $sandbox['user_count'];
- if ($sandbox['user_from'] == $sandbox['user_count']) {
- if ($sandbox['user_not_migrated'] > 0) {
- variable_set('empty_timezone_message', 1);
- drupal_set_message(format_string('Some user time zones have been emptied and need to be set to the correct values. Use the new
time zone options to choose whether to remind users at login to set the correct time zone.', array('@config-url' => url('admin/config/regional/settings'))), 'warning');
- }
- return t('Migrated user time zones');
- }
- }
-}
-
-/**
- * Update user settings for cancelling user accounts.
- *
- * Prior to 7.x, users were not able to cancel their accounts. When
- * administrators deleted an account, all contents were assigned to uid 0,
- * which is the same as the 'user_cancel_reassign' method now.
- */
-function user_update_7003() {
- // Set the default account cancellation method.
- variable_set('user_cancel_method', 'user_cancel_reassign');
- // Re-assign notification setting.
- if ($setting = variable_get('user_mail_status_deleted_notify', FALSE)) {
- variable_set('user_mail_status_canceled_notify', $setting);
- variable_del('user_mail_status_deleted_notify');
- }
- // Re-assign "Account deleted" mail strings to "Account canceled" mail.
- if ($setting = variable_get('user_mail_status_deleted_subject', FALSE)) {
- variable_set('user_mail_status_canceled_subject', $setting);
- variable_del('user_mail_status_deleted_subject');
- }
- if ($setting = variable_get('user_mail_status_deleted_body', FALSE)) {
- variable_set('user_mail_status_canceled_body', $setting);
- variable_del('user_mail_status_deleted_body');
- }
-}
-
-/**
- * Changes the users table to allow longer e-mail addresses.
- */
-function user_update_7005(&$sandbox) {
- $mail_field = array(
- 'type' => 'varchar',
- 'length' => 254,
- 'not null' => FALSE,
- 'default' => '',
- 'description' => "User's e-mail address.",
- );
- $init_field = array(
- 'type' => 'varchar',
- 'length' => 254,
- 'not null' => FALSE,
- 'default' => '',
- 'description' => 'E-mail address used for initial account creation.',
- );
- db_drop_index('users', 'mail');
- db_change_field('users', 'mail', 'mail', $mail_field, array('indexes' => array('mail' => array('mail'))));
- db_change_field('users', 'init', 'init', $init_field);
-}
-
-/**
- * Add module data to {role_permission}.
- */
-function user_update_7006(&$sandbox) {
- $module_field = array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => "The module declaring the permission.",
- );
- // Check that the field hasn't been updated in an aborted run of this
- // update.
- if (!db_field_exists('role_permission', 'module')) {
- // Add a new field for the fid.
- db_add_field('role_permission', 'module', $module_field);
- }
-}
-
-/**
- * Add a weight column to user roles.
- */
-function user_update_7007() {
- db_add_field('role', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
- db_add_index('role', 'name_weight', array('name', 'weight'));
-}
-
-/**
- * If 'user_register' variable was unset in Drupal 6, set it to be the same as
- * the Drupal 6 default setting.
- */
-function user_update_7008() {
- if (!isset($GLOBALS['conf']['user_register'])) {
- // Set to the Drupal 6 default, "visitors can create accounts".
- variable_set('user_register', USER_REGISTER_VISITORS);
- }
-}
-
-/**
- * Converts fields that store serialized variables from text to blob.
- */
-function user_update_7009() {
- $spec = array(
- 'type' => 'blob',
- 'not null' => FALSE,
- 'size' => 'big',
- 'serialize' => TRUE,
- 'description' => 'A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.',
- );
- db_change_field('users', 'data', 'data', $spec);
-}
-
-/**
- * Update the {user}.signature_format column.
- */
-function user_update_7010() {
- // Update the database column to allow NULL values.
- db_change_field('users', 'signature_format', 'signature_format', array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the signature.',
- ));
-
- // Replace the signature format with NULL if the signature is empty and does
- // not already have a stored text format.
- //
- // In Drupal 6, "0" (the former FILTER_FORMAT_DEFAULT constant) could be used
- // to indicate this situation, but in Drupal 7, only NULL is supported. This
- // update therefore preserves the ability of user accounts which were never
- // given a signature (for example, if the site did not have user signatures
- // enabled, or if the user never edited their account information) to not
- // have a particular text format assumed for them the first time the
- // signature is edited.
- db_update('users')
- ->fields(array('signature_format' => NULL))
- ->condition('signature', '')
- ->condition('signature_format', 0)
- ->execute();
-
- // There are a number of situations in which a Drupal 6 site could store
- // content with a nonexistent text format. This includes text formats that
- // had later been deleted, or non-empty content stored with a value of "0"
- // (the former FILTER_FORMAT_DEFAULT constant). Drupal 6 would filter this
- // content using whatever the site-wide default text format was at the moment
- // the text was being displayed.
- //
- // In Drupal 7, this behavior is no longer supported, and all content must be
- // stored with an explicit text format (or it will not be displayed when it
- // is filtered). Therefore, to preserve the behavior of the site after the
- // upgrade, we must replace all instances described above with the current
- // value of the (old) site-wide default format at the moment of the upgrade.
- $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol();
- $default_format = variable_get('filter_default_format', 1);
- db_update('users')
- ->fields(array('signature_format' => $default_format))
- ->isNotNull('signature_format')
- ->condition('signature_format', $existing_formats, 'NOT IN')
- ->execute();
-}
-
-/**
- * Placeholder function.
- *
- * As a fix for user_update_7011() not updating email templates to use the new
- * tokens, user_update_7017() now targets email templates of Drupal 6 sites and
- * already upgraded sites.
- */
-function user_update_7011() {
-}
-
-/**
- * Add the user's pictures to the {file_managed} table and make them managed
- * files.
- */
-function user_update_7012(&$sandbox) {
-
- $picture_field = array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => "Foreign key: {file_managed}.fid of user's picture.",
- );
-
- if (!isset($sandbox['progress'])) {
- // Check that the field hasn't been updated in an aborted run of this
- // update.
- if (!db_field_exists('users', 'picture_fid')) {
- // Add a new field for the fid.
- db_add_field('users', 'picture_fid', $picture_field);
- }
-
- // Initialize batch update information.
- $sandbox['progress'] = 0;
- $sandbox['last_user_processed'] = -1;
- $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} WHERE picture <> ''")->fetchField();
- }
-
- // As a batch operation move the photos into the {file_managed} table and
- // update the {users} records.
- $limit = 500;
- $result = db_query_range("SELECT uid, picture FROM {users} WHERE picture <> '' AND uid > :uid ORDER BY uid", 0, $limit, array(':uid' => $sandbox['last_user_processed']));
- foreach ($result as $user) {
- // Don't bother adding files that don't exist.
- if (file_exists($user->picture)) {
-
- // Check if the file already exists.
- $files = file_load_multiple(array(), array('uri' => $user->picture));
- if (count($files)) {
- $file = reset($files);
- }
- else {
- // Create a file object.
- $file = new stdClass();
- $file->uri = $user->picture;
- $file->filename = drupal_basename($file->uri);
- $file->filemime = file_get_mimetype($file->uri);
- $file->uid = $user->uid;
- $file->status = FILE_STATUS_PERMANENT;
- $file = file_save($file);
- }
-
- db_update('users')
- ->fields(array('picture_fid' => $file->fid))
- ->condition('uid', $user->uid)
- ->execute();
- }
-
- // Update our progress information for the batch update.
- $sandbox['progress']++;
- $sandbox['last_user_processed'] = $user->uid;
- }
-
- // Indicate our current progress to the batch update system. If there's no
- // max value then there's nothing to update and we're finished.
- $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
-
- // When we're finished, drop the old picture field and rename the new one to
- // replace it.
- if (isset($sandbox['#finished']) && $sandbox['#finished'] == 1) {
- db_drop_field('users', 'picture');
- db_change_field('users', 'picture_fid', 'picture', $picture_field);
- }
-}
-
-/**
- * Add user module file usage entries.
- */
-function user_update_7013(&$sandbox) {
- if (!isset($sandbox['progress'])) {
- // Initialize batch update information.
- $sandbox['progress'] = 0;
- $sandbox['last_uid_processed'] = -1;
- $sandbox['max'] = db_query("SELECT COUNT(*) FROM {users} u WHERE u.picture <> 0")->fetchField();
- }
-
- // Add usage entries for the user picture files.
- $limit = 500;
- $result = db_query_range('SELECT f.*, u.uid as user_uid FROM {users} u INNER JOIN {file_managed} f ON u.picture = f.fid WHERE u.picture <> 0 AND u.uid > :uid ORDER BY u.uid', 0, $limit, array(':uid' => $sandbox['last_uid_processed']))->fetchAllAssoc('fid', PDO::FETCH_ASSOC);
- foreach ($result as $row) {
- $uid = $row['user_uid'];
- $file = (object) $row;
- file_usage_add($file, 'user', 'user', $uid);
-
- // Update our progress information for the batch update.
- $sandbox['progress']++;
- $sandbox['last_uid_processed'] = $uid;
- }
-
- // Indicate our current progress to the batch update system.
- $sandbox['#finished'] = empty($sandbox['max']) || ($sandbox['progress'] / $sandbox['max']);
-}
-
-/**
- * Rename the 'post comments without approval' permission.
- *
- * In Drupal 7, this permission has been renamed to 'skip comment approval'.
- */
-function user_update_7014() {
- db_update('role_permission')
- ->fields(array('permission' => 'skip comment approval'))
- ->condition('permission', 'post comments without approval')
- ->execute();
-
- return t("Renamed the 'post comments without approval' permission to 'skip comment approval'.");
-}
-
-/**
- * Change {users}.signature_format into varchar.
- */
-function user_update_7015() {
- db_change_field('users', 'signature_format', 'signature_format', array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the signature.',
- ));
-}
-
-/**
- * @} End of "addtogroup updates-6.x-to-7.x".
- */
-
-/**
- * @addtogroup updates-7.x-extra
- * @{
- */
-
-/**
- * Update the database to match the schema.
- */
-function user_update_7016() {
- // Add field default.
- db_change_field('users', 'uid', 'uid', array(
- 'type' => 'int',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0,
- ));
-}
-
-/**
- * Update email templates to use new tokens.
- *
- * This function upgrades customized email templates from the old !token format
- * to the new core tokens format. Additionally, in Drupal 7 we no longer e-mail
- * plain text passwords to users, and there is no token for a plain text
- * password in the new token system. Therefore, it also modifies any saved
- * templates using the old '!password' token such that the token is removed, and
- * displays a warning to users that they may need to go and modify the wording
- * of their templates.
- */
-function user_update_7017() {
- $message = '';
-
- $tokens = array(
- '!site' => '[site:name]',
- '!username' => '[user:name]',
- '!mailto' => '[user:mail]',
- '!login_uri' => '[site:login-url]',
- '!uri_brief' => '[site:url-brief]',
- '!edit_uri' => '[user:edit-url]',
- '!login_url' => '[user:one-time-login-url]',
- '!uri' => '[site:url]',
- '!date' => '[date:medium]',
- '!password' => '',
- );
-
- $result = db_select('variable', 'v')
- ->fields('v', array('name'))
- ->condition('name', db_like('user_mail_') . '%', 'LIKE')
- ->execute();
-
- foreach ($result as $row) {
- // Use variable_get() to get the unserialized value for free.
- if ($value = variable_get($row->name, FALSE)) {
-
- if (empty($message) && (strpos($value, '!password') !== FALSE)) {
- $message = t('The ability to send users their passwords in plain text has been removed in Drupal 7. Your existing email templates have been modified to remove it. You should
review these templates to make sure they read properly.', array('@template-url' => url('admin/config/people/accounts')));
- }
-
- variable_set($row->name, str_replace(array_keys($tokens), $tokens, $value));
- }
- }
-
- return $message;
-}
-
-/**
- * Ensure there is an index on {users}.picture.
- */
-function user_update_7018() {
- if (!db_index_exists('users', 'picture')) {
- db_add_index('users', 'picture', array('picture'));
- }
-}
-
-/**
- * @} End of "addtogroup updates-7.x-extra".
- */
diff --git a/modules/user/user.js b/modules/user/user.js
deleted file mode 100644
index d182066a..00000000
--- a/modules/user/user.js
+++ /dev/null
@@ -1,196 +0,0 @@
-(function ($) {
-
-/**
- * Attach handlers to evaluate the strength of any password fields and to check
- * that its confirmation is correct.
- */
-Drupal.behaviors.password = {
- attach: function (context, settings) {
- var translate = settings.password;
- $('input.password-field', context).once('password', function () {
- var passwordInput = $(this);
- var innerWrapper = $(this).parent();
- var outerWrapper = $(this).parent().parent();
-
- // Add identifying class to password element parent.
- innerWrapper.addClass('password-parent');
-
- // Add the password confirmation layer.
- $('input.password-confirm', outerWrapper).parent().prepend('
' + translate['confirmTitle'] + '
').addClass('confirm-parent');
- var confirmInput = $('input.password-confirm', outerWrapper);
- var confirmResult = $('div.password-confirm', outerWrapper);
- var confirmChild = $('span', confirmResult);
-
- // Add the description box.
- var passwordMeter = '
' + translate['strengthTitle'] + '
';
- $(confirmInput).parent().after('
');
- $(innerWrapper).prepend(passwordMeter);
- var passwordDescription = $('div.password-suggestions', outerWrapper).hide();
-
- // Check the password strength.
- var passwordCheck = function () {
-
- // Evaluate the password strength.
- var result = Drupal.evaluatePasswordStrength(passwordInput.val(), settings.password);
-
- // Update the suggestions for how to improve the password.
- if (passwordDescription.html() != result.message) {
- passwordDescription.html(result.message);
- }
-
- // Only show the description box if there is a weakness in the password.
- if (result.strength == 100) {
- passwordDescription.hide();
- }
- else {
- passwordDescription.show();
- }
-
- // Adjust the length of the strength indicator.
- $(innerWrapper).find('.indicator').css('width', result.strength + '%');
-
- // Update the strength indication text.
- $(innerWrapper).find('.password-strength-text').html(result.indicatorText);
-
- passwordCheckMatch();
- };
-
- // Check that password and confirmation inputs match.
- var passwordCheckMatch = function () {
-
- if (confirmInput.val()) {
- var success = passwordInput.val() === confirmInput.val();
-
- // Show the confirm result.
- confirmResult.css({ visibility: 'visible' });
-
- // Remove the previous styling if any exists.
- if (this.confirmClass) {
- confirmChild.removeClass(this.confirmClass);
- }
-
- // Fill in the success message and set the class accordingly.
- var confirmClass = success ? 'ok' : 'error';
- confirmChild.html(translate['confirm' + (success ? 'Success' : 'Failure')]).addClass(confirmClass);
- this.confirmClass = confirmClass;
- }
- else {
- confirmResult.css({ visibility: 'hidden' });
- }
- };
-
- // Monitor keyup and blur events.
- // Blur must be used because a mouse paste does not trigger keyup.
- passwordInput.keyup(passwordCheck).focus(passwordCheck).blur(passwordCheck);
- confirmInput.keyup(passwordCheckMatch).blur(passwordCheckMatch);
- });
- }
-};
-
-/**
- * Evaluate the strength of a user's password.
- *
- * Returns the estimated strength and the relevant output message.
- */
-Drupal.evaluatePasswordStrength = function (password, translate) {
- var weaknesses = 0, strength = 100, msg = [];
-
- var hasLowercase = /[a-z]+/.test(password);
- var hasUppercase = /[A-Z]+/.test(password);
- var hasNumbers = /[0-9]+/.test(password);
- var hasPunctuation = /[^a-zA-Z0-9]+/.test(password);
-
- // If there is a username edit box on the page, compare password to that, otherwise
- // use value from the database.
- var usernameBox = $('input.username');
- var username = (usernameBox.length > 0) ? usernameBox.val() : translate.username;
-
- // Lose 5 points for every character less than 6, plus a 30 point penalty.
- if (password.length < 6) {
- msg.push(translate.tooShort);
- strength -= ((6 - password.length) * 5) + 30;
- }
-
- // Count weaknesses.
- if (!hasLowercase) {
- msg.push(translate.addLowerCase);
- weaknesses++;
- }
- if (!hasUppercase) {
- msg.push(translate.addUpperCase);
- weaknesses++;
- }
- if (!hasNumbers) {
- msg.push(translate.addNumbers);
- weaknesses++;
- }
- if (!hasPunctuation) {
- msg.push(translate.addPunctuation);
- weaknesses++;
- }
-
- // Apply penalty for each weakness (balanced against length penalty).
- switch (weaknesses) {
- case 1:
- strength -= 12.5;
- break;
-
- case 2:
- strength -= 25;
- break;
-
- case 3:
- strength -= 40;
- break;
-
- case 4:
- strength -= 40;
- break;
- }
-
- // Check if password is the same as the username.
- if (password !== '' && password.toLowerCase() === username.toLowerCase()) {
- msg.push(translate.sameAsUsername);
- // Passwords the same as username are always very weak.
- strength = 5;
- }
-
- // Based on the strength, work out what text should be shown by the password strength meter.
- if (strength < 60) {
- indicatorText = translate.weak;
- } else if (strength < 70) {
- indicatorText = translate.fair;
- } else if (strength < 80) {
- indicatorText = translate.good;
- } else if (strength <= 100) {
- indicatorText = translate.strong;
- }
-
- // Assemble the final message.
- msg = translate.hasWeaknesses + '
';
- return { strength: strength, message: msg, indicatorText: indicatorText };
-
-};
-
-/**
- * Field instance settings screen: force the 'Display on registration form'
- * checkbox checked whenever 'Required' is checked.
- */
-Drupal.behaviors.fieldUserRegistration = {
- attach: function (context, settings) {
- var $checkbox = $('form#field-ui-field-edit-form input#edit-instance-settings-user-register-form');
-
- if ($checkbox.length) {
- $('input#edit-instance-required', context).once('user-register-form-checkbox', function () {
- $(this).bind('change', function (e) {
- if ($(this).attr('checked')) {
- $checkbox.attr('checked', true);
- }
- });
- });
-
- }
- }
-};
-
-})(jQuery);
diff --git a/modules/user/user.module b/modules/user/user.module
deleted file mode 100644
index 9668d3b0..00000000
--- a/modules/user/user.module
+++ /dev/null
@@ -1,4028 +0,0 @@
-' . t('About') . '';
- $output .= '
' . t('The User module allows users to register, log in, and log out. It also allows users with proper permissions to manage user roles (used to classify users) and permissions associated with those roles. For more information, see the online handbook entry for User module .', array('@user' => 'http://drupal.org/documentation/modules/user')) . '
';
- $output .= '
' . t('Uses') . ' ';
- $output .= '
';
- $output .= '' . t('Creating and managing users') . ' ';
- $output .= '' . t('The User module allows users with the appropriate permissions to create user accounts through the People administration page , where they can also assign users to one or more roles, and block or delete user accounts. If allowed, users without accounts (anonymous users) can create their own accounts on the Create new account page.', array('@permissions' => url('admin/people/permissions', array('fragment' => 'module-user')), '@people' => url('admin/people'), '@register' => url('user/register'))) . ' ';
- $output .= '' . t('User roles and permissions') . ' ';
- $output .= '' . t('Roles are used to group and classify users; each user can be assigned one or more roles. By default there are two roles: anonymous user (users that are not logged in) and authenticated user (users that are registered and logged in). Depending on choices you made when you installed Drupal, the installation process may have defined more roles, and you can create additional custom roles on the Roles page . After creating roles, you can set permissions for each role on the Permissions page . Granting a permission allows users who have been assigned a particular role to perform an action on the site, such as viewing a particular type of content, editing or creating content, administering settings for a particular module, or using a particular function of the site (such as search).', array('@permissions_user' => url('admin/people/permissions'), '@roles' => url('admin/people/permissions/roles'))) . ' ';
- $output .= '' . t('Account settings') . ' ';
- $output .= '' . t('The Account settings page allows you to manage settings for the displayed name of the anonymous user role, personal contact forms, user registration, and account cancellation. On this page you can also manage settings for account personalization (including signatures and user pictures), and adapt the text for the e-mail messages that are sent automatically during the user registration process.', array('@accounts' => url('admin/config/people/accounts'))) . ' ';
- $output .= ' ';
- return $output;
- case 'admin/people/create':
- return '
' . t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") . '
';
- case 'admin/people/permissions':
- return '
' . t('Permissions let you control what users can do and see on your site. You can define a specific set of permissions for each role. (See the Roles page to create a role). Two important roles to consider are Authenticated Users and Administrators. Any permissions granted to the Authenticated Users role will be given to any user who can log into your site. You can make any role the Administrator role for the site, meaning this will be granted all new permissions automatically. You can do this on the User Settings page. You should be careful to ensure that only trusted users are given this access and level of control of your site.', array('@role' => url('admin/people/permissions/roles'), '@settings' => url('admin/config/people/accounts'))) . '
';
- case 'admin/people/permissions/roles':
- $output = '
' . t('Roles allow you to fine tune the security and administration of Drupal. A role defines a group of users that have certain privileges as defined on the permissions page . Examples of roles include: anonymous user, authenticated user, moderator, administrator and so on. In this area you will define the names and order of the roles on your site. It is recommended to order your roles from least permissive (anonymous user) to most permissive (administrator). To delete a role choose "edit role".', array('@permissions' => url('admin/people/permissions'))) . '
';
- $output .= '
' . t('By default, Drupal comes with two user roles:') . '
';
- $output .= '
';
- $output .= '' . t("Anonymous user: this role is used for users that don't have a user account or that are not authenticated.") . ' ';
- $output .= '' . t('Authenticated user: this role is automatically granted to all logged in users.') . ' ';
- $output .= ' ';
- return $output;
- case 'admin/config/people/accounts/fields':
- return '
' . t('This form lets administrators add, edit, and arrange fields for storing user data.') . '
';
- case 'admin/config/people/accounts/display':
- return '
' . t('This form lets administrators configure how fields should be displayed when rendering a user profile page.') . '
';
- case 'admin/people/search':
- return '
' . t('Enter a simple pattern ("*" may be used as a wildcard match) to search for a username or e-mail address. For example, one may search for "br" and Drupal might return "brian", "brad", and "brenda@example.com".') . '
';
- }
-}
-
-/**
- * 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) {
- $function = $module . '_user_' . $type;
- $function($edit, $account, $category);
- }
-}
-
-/**
- * Implements hook_theme().
- */
-function user_theme() {
- return array(
- 'user_picture' => array(
- 'variables' => array('account' => NULL),
- 'template' => 'user-picture',
- ),
- 'user_profile' => array(
- 'render element' => 'elements',
- 'template' => 'user-profile',
- 'file' => 'user.pages.inc',
- ),
- 'user_profile_category' => array(
- 'render element' => 'element',
- 'template' => 'user-profile-category',
- 'file' => 'user.pages.inc',
- ),
- 'user_profile_item' => array(
- 'render element' => 'element',
- 'template' => 'user-profile-item',
- 'file' => 'user.pages.inc',
- ),
- 'user_list' => array(
- 'variables' => array('users' => NULL, 'title' => NULL),
- ),
- 'user_admin_permissions' => array(
- 'render element' => 'form',
- 'file' => 'user.admin.inc',
- ),
- 'user_admin_roles' => array(
- 'render element' => 'form',
- 'file' => 'user.admin.inc',
- ),
- 'user_permission_description' => array(
- 'variables' => array('permission_item' => NULL, 'hide' => NULL),
- 'file' => 'user.admin.inc',
- ),
- 'user_signature' => array(
- 'variables' => array('signature' => NULL),
- ),
- );
-}
-
-/**
- * Implements hook_entity_info().
- */
-function user_entity_info() {
- $return = array(
- 'user' => array(
- 'label' => t('User'),
- 'controller class' => 'UserController',
- 'base table' => 'users',
- 'uri callback' => 'user_uri',
- 'label callback' => 'format_username',
- 'fieldable' => TRUE,
- // $user->language is only the preferred user language for the user
- // interface textual elements. As it is not necessarily related to the
- // language assigned to fields, we do not define it as the entity language
- // key.
- 'entity keys' => array(
- 'id' => 'uid',
- ),
- 'bundles' => array(
- 'user' => array(
- 'label' => t('User'),
- 'admin' => array(
- 'path' => 'admin/config/people/accounts',
- 'access arguments' => array('administer users'),
- ),
- ),
- ),
- 'view modes' => array(
- 'full' => array(
- 'label' => t('User account'),
- 'custom settings' => FALSE,
- ),
- ),
- ),
- );
- return $return;
-}
-
-/**
- * Implements callback_entity_info_uri().
- */
-function user_uri($user) {
- return array(
- 'path' => 'user/' . $user->uid,
- );
-}
-
-/**
- * Implements hook_field_info_alter().
- */
-function user_field_info_alter(&$info) {
- // Add the 'user_register_form' instance setting to all field types.
- foreach ($info as $field_type => &$field_type_info) {
- $field_type_info += array('instance_settings' => array());
- $field_type_info['instance_settings'] += array(
- 'user_register_form' => FALSE,
- );
- }
-}
-
-/**
- * Implements hook_field_extra_fields().
- */
-function user_field_extra_fields() {
- $return['user']['user'] = array(
- 'form' => array(
- 'account' => array(
- 'label' => t('User name and password'),
- 'description' => t('User module account form elements.'),
- 'weight' => -10,
- ),
- 'timezone' => array(
- 'label' => t('Timezone'),
- 'description' => t('User module timezone form element.'),
- 'weight' => 6,
- ),
- ),
- 'display' => array(
- 'summary' => array(
- 'label' => t('History'),
- 'description' => t('User module history view element.'),
- 'weight' => 5,
- ),
- ),
- );
-
- return $return;
-}
-
-/**
- * Fetches a user object based on an external authentication source.
- *
- * @param string $authname
- * The external authentication username.
- *
- * @return
- * A fully-loaded user object if the user is found or FALSE if not found.
- */
-function user_external_load($authname) {
- $uid = db_query("SELECT uid FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchField();
-
- if ($uid) {
- return user_load($uid);
- }
- else {
- return FALSE;
- }
-}
-
-/**
- * Load multiple users based on certain conditions.
- *
- * This function should be used whenever you need to load more than one user
- * from the database. Users are loaded into memory and will not require
- * database access if loaded again during the same page request.
- *
- * @param $uids
- * An array of user IDs.
- * @param $conditions
- * (deprecated) An associative array of conditions on the {users}
- * table, where the keys are the database fields and the values are the
- * values those fields must have. Instead, it is preferable to use
- * EntityFieldQuery to retrieve a list of entity IDs loadable by
- * this function.
- * @param $reset
- * A boolean indicating that the internal cache should be reset. Use this if
- * loading a user object which has been altered during the page request.
- *
- * @return
- * An array of user objects, indexed by uid.
- *
- * @see entity_load()
- * @see user_load()
- * @see user_load_by_mail()
- * @see user_load_by_name()
- * @see EntityFieldQuery
- *
- * @todo Remove $conditions in Drupal 8.
- */
-function user_load_multiple($uids = array(), $conditions = array(), $reset = FALSE) {
- return entity_load('user', $uids, $conditions, $reset);
-}
-
-/**
- * Controller class for users.
- *
- * This extends the DrupalDefaultEntityController class, adding required
- * special handling for user objects.
- */
-class UserController extends DrupalDefaultEntityController {
-
- function attachLoad(&$queried_users, $revision_id = FALSE) {
- // Build an array of user picture IDs so that these can be fetched later.
- $picture_fids = array();
- foreach ($queried_users as $key => $record) {
- $picture_fids[] = $record->picture;
- $queried_users[$key]->data = unserialize($record->data);
- $queried_users[$key]->roles = array();
- if ($record->uid) {
- $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
- }
- else {
- $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
- }
- }
-
- // Add any additional roles from the database.
- $result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
- foreach ($result as $record) {
- $queried_users[$record->uid]->roles[$record->rid] = $record->name;
- }
-
- // Add the full file objects for user pictures if enabled.
- if (!empty($picture_fids) && variable_get('user_pictures', 0)) {
- $pictures = file_load_multiple($picture_fids);
- foreach ($queried_users as $account) {
- if (!empty($account->picture) && isset($pictures[$account->picture])) {
- $account->picture = $pictures[$account->picture];
- }
- else {
- $account->picture = NULL;
- }
- }
- }
- // Call the default attachLoad() method. This will add fields and call
- // hook_user_load().
- parent::attachLoad($queried_users, $revision_id);
- }
-}
-
-/**
- * Loads a user object.
- *
- * Drupal has a global $user object, which represents the currently-logged-in
- * user. So to avoid confusion and to avoid clobbering the global $user object,
- * it is a good idea to assign the result of this function to a different local
- * variable, generally $account. If you actually do want to act as the user you
- * are loading, it is essential to call drupal_save_session(FALSE); first.
- * See
- * @link http://drupal.org/node/218104 Safely impersonating another user @endlink
- * for more information.
- *
- * @param $uid
- * Integer specifying the user ID to load.
- * @param $reset
- * TRUE to reset the internal cache and load from the database; FALSE
- * (default) to load from the internal cache, if set.
- *
- * @return
- * A fully-loaded user object upon successful user load, or FALSE if the user
- * cannot be loaded.
- *
- * @see user_load_multiple()
- */
-function user_load($uid, $reset = FALSE) {
- $users = user_load_multiple(array($uid), array(), $reset);
- return reset($users);
-}
-
-/**
- * Fetch a user object by email address.
- *
- * @param $mail
- * String with the account's e-mail address.
- * @return
- * A fully-loaded $user object upon successful user load or FALSE if user
- * cannot be loaded.
- *
- * @see user_load_multiple()
- */
-function user_load_by_mail($mail) {
- $users = user_load_multiple(array(), array('mail' => $mail));
- return reset($users);
-}
-
-/**
- * Fetch a user object by account name.
- *
- * @param $name
- * String with the account's user name.
- * @return
- * A fully-loaded $user object upon successful user load or FALSE if user
- * cannot be loaded.
- *
- * @see user_load_multiple()
- */
-function user_load_by_name($name) {
- $users = user_load_multiple(array(), array('name' => $name));
- return reset($users);
-}
-
-/**
- * Save changes to a user account or add a new user.
- *
- * @param $account
- * (optional) The user object to modify or add. If you want to modify
- * an existing user account, you will need to ensure that (a) $account
- * is an object, and (b) you have set $account->uid to the numeric
- * user ID of the user account you wish to modify. If you
- * want to create a new user account, you can set $account->is_new to
- * TRUE or omit the $account->uid field.
- * @param $edit
- * An array of fields and values to save. For example array('name'
- * => 'My name'). Key / value pairs added to the $edit['data'] will be
- * serialized and saved in the {users.data} column.
- * @param $category
- * (optional) The category for storing profile information in.
- *
- * @return
- * A fully-loaded $user object upon successful save or FALSE if the save failed.
- *
- * @todo D8: Drop $edit and fix user_save() to be consistent with others.
- */
-function user_save($account, $edit = array(), $category = 'account') {
- $transaction = db_transaction();
- try {
- if (!empty($edit['pass'])) {
- // Allow alternate password hashing schemes.
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- $edit['pass'] = user_hash_password(trim($edit['pass']));
- // Abort if the hashing failed and returned FALSE.
- if (!$edit['pass']) {
- return FALSE;
- }
- }
- else {
- // Avoid overwriting an existing password with a blank password.
- unset($edit['pass']);
- }
- if (isset($edit['mail'])) {
- $edit['mail'] = trim($edit['mail']);
- }
-
- // Load the stored entity, if any.
- if (!empty($account->uid) && !isset($account->original)) {
- $account->original = entity_load_unchanged('user', $account->uid);
- }
-
- if (empty($account)) {
- $account = new stdClass();
- }
- if (!isset($account->is_new)) {
- $account->is_new = empty($account->uid);
- }
- // Prepopulate $edit['data'] with the current value of $account->data.
- // Modules can add to or remove from this array in hook_user_presave().
- if (!empty($account->data)) {
- $edit['data'] = !empty($edit['data']) ? array_merge($account->data, $edit['data']) : $account->data;
- }
-
- // Invoke hook_user_presave() for all modules.
- user_module_invoke('presave', $edit, $account, $category);
-
- // Invoke presave operations of Field Attach API and Entity API. Those APIs
- // require a fully-fledged and updated entity object. Therefore, we need to
- // copy any new property values of $edit into it.
- foreach ($edit as $key => $value) {
- $account->$key = $value;
- }
- field_attach_presave('user', $account);
- module_invoke_all('entity_presave', $account, 'user');
-
- if (is_object($account) && !$account->is_new) {
- // Process picture uploads.
- if (!empty($account->picture->fid) && (!isset($account->original->picture->fid) || $account->picture->fid != $account->original->picture->fid)) {
- $picture = $account->picture;
- // If the picture is a temporary file move it to its final location and
- // make it permanent.
- if (!$picture->status) {
- $info = image_get_info($picture->uri);
- $picture_directory = file_default_scheme() . '://' . variable_get('user_picture_path', 'pictures');
-
- // Prepare the pictures directory.
- file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY);
- $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '-' . REQUEST_TIME . '.' . $info['extension']);
-
- // Move the temporary file into the final location.
- if ($picture = file_move($picture, $destination, FILE_EXISTS_RENAME)) {
- $picture->status = FILE_STATUS_PERMANENT;
- $account->picture = file_save($picture);
- file_usage_add($picture, 'user', 'user', $account->uid);
- }
- }
- // Delete the previous picture if it was deleted or replaced.
- if (!empty($account->original->picture->fid)) {
- file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
- file_delete($account->original->picture);
- }
- }
- elseif (isset($edit['picture_delete']) && $edit['picture_delete']) {
- file_usage_delete($account->original->picture, 'user', 'user', $account->uid);
- file_delete($account->original->picture);
- }
- $account->picture = empty($account->picture->fid) ? 0 : $account->picture->fid;
-
- // Do not allow 'uid' to be changed.
- $account->uid = $account->original->uid;
- // Save changes to the user table.
- $success = drupal_write_record('users', $account, 'uid');
- if ($success === FALSE) {
- // The query failed - better to abort the save than risk further
- // data loss.
- return FALSE;
- }
-
- // Reload user roles if provided.
- if ($account->roles != $account->original->roles) {
- db_delete('users_roles')
- ->condition('uid', $account->uid)
- ->execute();
-
- $query = db_insert('users_roles')->fields(array('uid', 'rid'));
- foreach (array_keys($account->roles) as $rid) {
- if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
- $query->values(array(
- 'uid' => $account->uid,
- 'rid' => $rid,
- ));
- }
- }
- $query->execute();
- }
-
- // Delete a blocked user's sessions to kick them if they are online.
- if ($account->original->status != $account->status && $account->status == 0) {
- drupal_session_destroy_uid($account->uid);
- }
-
- // If the password changed, delete all open sessions and recreate
- // the current one.
- if ($account->pass != $account->original->pass) {
- drupal_session_destroy_uid($account->uid);
- if ($account->uid == $GLOBALS['user']->uid) {
- drupal_session_regenerate();
- }
- }
-
- // Save Field data.
- field_attach_update('user', $account);
-
- // Send emails after we have the new user object.
- if ($account->status != $account->original->status) {
- // The user's status is changing; conditionally send notification email.
- $op = $account->status == 1 ? 'status_activated' : 'status_blocked';
- _user_mail_notify($op, $account);
- }
-
- // Update $edit with any interim changes to $account.
- foreach ($account as $key => $value) {
- if (!property_exists($account->original, $key) || $value !== $account->original->$key) {
- $edit[$key] = $value;
- }
- }
- user_module_invoke('update', $edit, $account, $category);
- module_invoke_all('entity_update', $account, 'user');
- }
- else {
- // Allow 'uid' to be set by the caller. There is no danger of writing an
- // existing user as drupal_write_record will do an INSERT.
- if (empty($account->uid)) {
- $account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
- }
- // Allow 'created' to be set by the caller.
- if (!isset($account->created)) {
- $account->created = REQUEST_TIME;
- }
- $success = drupal_write_record('users', $account);
- if ($success === FALSE) {
- // On a failed INSERT some other existing user's uid may be returned.
- // We must abort to avoid overwriting their account.
- return FALSE;
- }
-
- // Make sure $account is properly initialized.
- $account->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
-
- field_attach_insert('user', $account);
- $edit = (array) $account;
- user_module_invoke('insert', $edit, $account, $category);
- module_invoke_all('entity_insert', $account, 'user');
-
- // Save user roles.
- if (count($account->roles) > 1) {
- $query = db_insert('users_roles')->fields(array('uid', 'rid'));
- foreach (array_keys($account->roles) as $rid) {
- if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
- $query->values(array(
- 'uid' => $account->uid,
- 'rid' => $rid,
- ));
- }
- }
- $query->execute();
- }
- }
- // Clear internal properties.
- unset($account->is_new);
- unset($account->original);
- // Clear the static loading cache.
- entity_get_controller('user')->resetCache(array($account->uid));
-
- return $account;
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception('user', $e);
- throw $e;
- }
-}
-
-/**
- * Verify the syntax of the given name.
- */
-function user_validate_name($name) {
- if (!$name) {
- return t('You must enter a username.');
- }
- if (substr($name, 0, 1) == ' ') {
- return t('The username cannot begin with a space.');
- }
- if (substr($name, -1) == ' ') {
- return t('The username cannot end with a space.');
- }
- if (strpos($name, ' ') !== FALSE) {
- return t('The username cannot contain multiple spaces in a row.');
- }
- if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)) {
- return t('The username contains an illegal character.');
- }
- if (preg_match('/[\x{80}-\x{A0}' . // Non-printable ISO-8859-1 + NBSP
- '\x{AD}' . // Soft-hyphen
- '\x{2000}-\x{200F}' . // Various space characters
- '\x{2028}-\x{202F}' . // Bidirectional text overrides
- '\x{205F}-\x{206F}' . // Various text hinting characters
- '\x{FEFF}' . // Byte order mark
- '\x{FF01}-\x{FF60}' . // Full-width latin
- '\x{FFF9}-\x{FFFD}' . // Replacement characters
- '\x{0}-\x{1F}]/u', // NULL byte and control characters
- $name)) {
- return t('The username contains an illegal character.');
- }
- if (drupal_strlen($name) > USERNAME_MAX_LENGTH) {
- return t('The username %name is too long: it must be %max characters or less.', array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
- }
-}
-
-/**
- * Validates a user's email address.
- *
- * Checks that a user's email address exists and follows all standard
- * validation rules. Returns error messages when the address is invalid.
- *
- * @param $mail
- * A user's email address.
- *
- * @return
- * If the address is invalid, a human-readable error message is returned.
- * If the address is valid, nothing is returned.
- */
-function user_validate_mail($mail) {
- if (!$mail) {
- return t('You must enter an e-mail address.');
- }
- if (!valid_email_address($mail)) {
- return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
- }
-}
-
-/**
- * Validates an image uploaded by a user.
- *
- * @see user_account_form()
- */
-function user_validate_picture(&$form, &$form_state) {
- // If required, validate the uploaded picture.
- $validators = array(
- 'file_validate_is_image' => array(),
- 'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
- 'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
- );
-
- // Save the file as a temporary file.
- $file = file_save_upload('picture_upload', $validators);
- if ($file === FALSE) {
- form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
- }
- elseif ($file !== NULL) {
- $form_state['values']['picture_upload'] = $file;
- }
-}
-
-/**
- * Generate a random alphanumeric password.
- */
-function user_password($length = 10) {
- // This variable contains the list of allowable characters for the
- // password. Note that the number 0 and the letter 'O' have been
- // removed to avoid confusion between the two. The same is true
- // of 'I', 1, and 'l'.
- $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
-
- // Zero-based count of characters in the allowable list:
- $len = strlen($allowable_characters) - 1;
-
- // Declare the password as a blank string.
- $pass = '';
-
- // Loop the number of times specified by $length.
- for ($i = 0; $i < $length; $i++) {
- do {
- // Find a secure random number within the range needed.
- $index = ord(drupal_random_bytes(1));
- } while ($index > $len);
-
- // Each iteration, pick a random character from the
- // allowable string and append it to the password:
- $pass .= $allowable_characters[$index];
- }
-
- return $pass;
-}
-
-/**
- * Determine the permissions for one or more roles.
- *
- * @param $roles
- * An array whose keys are the role IDs of interest, such as $user->roles.
- *
- * @return
- * An array indexed by role ID. Each value is an array whose keys are the
- * permission strings for the given role ID.
- */
-function user_role_permissions($roles = array()) {
- $cache = &drupal_static(__FUNCTION__, array());
-
- $role_permissions = $fetch = array();
-
- if ($roles) {
- foreach ($roles as $rid => $name) {
- if (isset($cache[$rid])) {
- $role_permissions[$rid] = $cache[$rid];
- }
- else {
- // Add this rid to the list of those needing to be fetched.
- $fetch[] = $rid;
- // Prepare in case no permissions are returned.
- $cache[$rid] = array();
- }
- }
-
- if ($fetch) {
- // Get from the database permissions that were not in the static variable.
- // Only role IDs with at least one permission assigned will return rows.
- $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
-
- foreach ($result as $row) {
- $cache[$row->rid][$row->permission] = TRUE;
- }
- foreach ($fetch as $rid) {
- // For every rid, we know we at least assigned an empty array.
- $role_permissions[$rid] = $cache[$rid];
- }
- }
- }
-
- return $role_permissions;
-}
-
-/**
- * Determine whether the user has a given privilege.
- *
- * @param $string
- * The permission, such as "administer nodes", being checked for.
- * @param $account
- * (optional) The account to check, if not given use currently logged in user.
- *
- * @return
- * Boolean TRUE if the current user has the requested permission.
- *
- * All permission checks in Drupal should go through this function. This
- * way, we guarantee consistent behavior, and ensure that the superuser
- * can perform all actions.
- */
-function user_access($string, $account = NULL) {
- global $user;
-
- if (!isset($account)) {
- $account = $user;
- }
-
- // User #1 has all privileges:
- if ($account->uid == 1) {
- return TRUE;
- }
-
- // To reduce the number of SQL queries, we cache the user's permissions
- // in a static variable.
- // Use the advanced drupal_static() pattern, since this is called very often.
- static $drupal_static_fast;
- if (!isset($drupal_static_fast)) {
- $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
- }
- $perm = &$drupal_static_fast['perm'];
- if (!isset($perm[$account->uid])) {
- $role_permissions = user_role_permissions($account->roles);
-
- $perms = array();
- foreach ($role_permissions as $one_role) {
- $perms += $one_role;
- }
- $perm[$account->uid] = $perms;
- }
-
- return isset($perm[$account->uid][$string]);
-}
-
-/**
- * Checks for usernames blocked by user administration.
- *
- * @param $name
- * A string containing a name of the user.
- *
- * @return
- * Object with property 'name' (the user name), if the user is blocked;
- * FALSE if the user is not blocked.
- */
-function user_is_blocked($name) {
- return db_select('users')
- ->fields('users', array('name'))
- ->condition('name', db_like($name), 'LIKE')
- ->condition('status', 0)
- ->execute()->fetchObject();
-}
-
-/**
- * Implements hook_permission().
- */
-function user_permission() {
- return array(
- 'administer permissions' => array(
- 'title' => t('Administer permissions'),
- 'restrict access' => TRUE,
- ),
- 'administer users' => array(
- 'title' => t('Administer users'),
- 'restrict access' => TRUE,
- ),
- 'access user profiles' => array(
- 'title' => t('View user profiles'),
- ),
- 'change own username' => array(
- 'title' => t('Change own username'),
- ),
- 'cancel account' => array(
- 'title' => t('Cancel own user account'),
- 'description' => t('Note: content may be kept, unpublished, deleted or transferred to the %anonymous-name user depending on the configured
user settings .', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')), '@user-settings-url' => url('admin/config/people/accounts'))),
- ),
- 'select account cancellation method' => array(
- 'title' => t('Select method for cancelling own account'),
- 'restrict access' => TRUE,
- ),
- );
-}
-
-/**
- * Implements hook_file_download().
- *
- * Ensure that user pictures (avatars) are always downloadable.
- */
-function user_file_download($uri) {
- if (strpos(file_uri_target($uri), variable_get('user_picture_path', 'pictures') . '/picture-') === 0) {
- $info = image_get_info($uri);
- return array('Content-Type' => $info['mime_type']);
- }
-}
-
-/**
- * Implements hook_file_move().
- */
-function user_file_move($file, $source) {
- // If a user's picture is replaced with a new one, update the record in
- // the users table.
- if (isset($file->fid) && isset($source->fid) && $file->fid != $source->fid) {
- db_update('users')
- ->fields(array(
- 'picture' => $file->fid,
- ))
- ->condition('picture', $source->fid)
- ->execute();
- }
-}
-
-/**
- * Implements hook_file_delete().
- */
-function user_file_delete($file) {
- // Remove any references to the file.
- db_update('users')
- ->fields(array('picture' => 0))
- ->condition('picture', $file->fid)
- ->execute();
-}
-
-/**
- * Implements hook_search_info().
- */
-function user_search_info() {
- return array(
- 'title' => 'Users',
- );
-}
-
-/**
- * Implements hook_search_access().
- */
-function user_search_access() {
- return user_access('access user profiles');
-}
-
-/**
- * Implements hook_search_execute().
- */
-function user_search_execute($keys = NULL, $conditions = NULL) {
- $find = array();
- // Replace wildcards with MySQL/PostgreSQL wildcards.
- $keys = preg_replace('!\*+!', '%', $keys);
- $query = db_select('users')->extend('PagerDefault');
- $query->fields('users', array('uid'));
- if (user_access('administer users')) {
- // Administrators can also search in the otherwise private email field,
- // and they don't need to be restricted to only active users.
- $query->fields('users', array('mail'));
- $query->condition(db_or()->
- condition('name', '%' . db_like($keys) . '%', 'LIKE')->
- condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
- }
- else {
- // Regular users can only search via usernames, and we do not show them
- // blocked accounts.
- $query->condition('name', '%' . db_like($keys) . '%', 'LIKE')
- ->condition('status', 1);
- }
- $uids = $query
- ->limit(15)
- ->execute()
- ->fetchCol();
- $accounts = user_load_multiple($uids);
-
- $results = array();
- foreach ($accounts as $account) {
- $result = array(
- 'title' => format_username($account),
- 'link' => url('user/' . $account->uid, array('absolute' => TRUE)),
- );
- if (user_access('administer users')) {
- $result['title'] .= ' (' . $account->mail . ')';
- }
- $results[] = $result;
- }
-
- return $results;
-}
-
-/**
- * Implements hook_element_info().
- */
-function user_element_info() {
- $types['user_profile_category'] = array(
- '#theme_wrappers' => array('user_profile_category'),
- );
- $types['user_profile_item'] = array(
- '#theme' => 'user_profile_item',
- );
- return $types;
-}
-
-/**
- * Implements hook_user_view().
- */
-function user_user_view($account) {
- $account->content['user_picture'] = array(
- '#markup' => theme('user_picture', array('account' => $account)),
- '#weight' => -10,
- );
- if (!isset($account->content['summary'])) {
- $account->content['summary'] = array();
- }
- $account->content['summary'] += array(
- '#type' => 'user_profile_category',
- '#attributes' => array('class' => array('user-member')),
- '#weight' => 5,
- '#title' => t('History'),
- );
- $account->content['summary']['member_for'] = array(
- '#type' => 'user_profile_item',
- '#title' => t('Member for'),
- '#markup' => format_interval(REQUEST_TIME - $account->created),
- );
-}
-
-/**
- * Helper function to add default user account fields to user registration and edit form.
- *
- * @see user_account_form_validate()
- * @see user_validate_current_pass()
- * @see user_validate_picture()
- * @see user_validate_mail()
- */
-function user_account_form(&$form, &$form_state) {
- global $user;
-
- $account = $form['#user'];
- $register = ($form['#user']->uid > 0 ? FALSE : TRUE);
-
- $admin = user_access('administer users');
-
- $form['#validate'][] = 'user_account_form_validate';
-
- // Account information.
- $form['account'] = array(
- '#type' => 'container',
- '#weight' => -10,
- );
- // Only show name field on registration form or user can change own username.
- $form['account']['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Username'),
- '#maxlength' => USERNAME_MAX_LENGTH,
- '#description' => t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
- '#required' => TRUE,
- '#attributes' => array('class' => array('username')),
- '#default_value' => (!$register ? $account->name : ''),
- '#access' => ($register || ($user->uid == $account->uid && user_access('change own username')) || $admin),
- '#weight' => -10,
- );
-
- $form['account']['mail'] = array(
- '#type' => 'textfield',
- '#title' => t('E-mail address'),
- '#maxlength' => EMAIL_MAX_LENGTH,
- '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
- '#required' => TRUE,
- '#default_value' => (!$register ? $account->mail : ''),
- );
-
- // Display password field only for existing users or when user is allowed to
- // assign a password during registration.
- if (!$register) {
- $form['account']['pass'] = array(
- '#type' => 'password_confirm',
- '#size' => 25,
- '#description' => t('To change the current user password, enter the new password in both fields.'),
- );
- // To skip the current password field, the user must have logged in via a
- // one-time link and have the token in the URL.
- $pass_reset = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]);
- $protected_values = array();
- $current_pass_description = '';
- // The user may only change their own password without their current
- // password if they logged in via a one-time login link.
- if (!$pass_reset) {
- $protected_values['mail'] = $form['account']['mail']['#title'];
- $protected_values['pass'] = t('Password');
- $request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
- $current_pass_description = t('Enter your current password to change the %mail or %pass. !request_new.', array('%mail' => $protected_values['mail'], '%pass' => $protected_values['pass'], '!request_new' => $request_new));
- }
- // The user must enter their current password to change to a new one.
- if ($user->uid == $account->uid) {
- $form['account']['current_pass_required_values'] = array(
- '#type' => 'value',
- '#value' => $protected_values,
- );
- $form['account']['current_pass'] = array(
- '#type' => 'password',
- '#title' => t('Current password'),
- '#size' => 25,
- '#access' => !empty($protected_values),
- '#description' => $current_pass_description,
- '#weight' => -5,
- // Do not let web browsers remember this password, since we are trying
- // to confirm that the person submitting the form actually knows the
- // current one.
- '#attributes' => array('autocomplete' => 'off'),
- );
- $form['#validate'][] = 'user_validate_current_pass';
- }
- }
- elseif (!variable_get('user_email_verification', TRUE) || $admin) {
- $form['account']['pass'] = array(
- '#type' => 'password_confirm',
- '#size' => 25,
- '#description' => t('Provide a password for the new account in both fields.'),
- '#required' => TRUE,
- );
- }
-
- if ($admin) {
- $status = isset($account->status) ? $account->status : 1;
- }
- else {
- $status = $register ? variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS : $account->status;
- }
- $form['account']['status'] = array(
- '#type' => 'radios',
- '#title' => t('Status'),
- '#default_value' => $status,
- '#options' => array(t('Blocked'), t('Active')),
- '#access' => $admin,
- );
-
- $roles = array_map('check_plain', user_roles(TRUE));
- // The disabled checkbox subelement for the 'authenticated user' role
- // must be generated separately and added to the checkboxes element,
- // because of a limitation in Form API not supporting a single disabled
- // checkbox within a set of checkboxes.
- // @todo This should be solved more elegantly. See issue #119038.
- $checkbox_authenticated = array(
- '#type' => 'checkbox',
- '#title' => $roles[DRUPAL_AUTHENTICATED_RID],
- '#default_value' => TRUE,
- '#disabled' => TRUE,
- );
- unset($roles[DRUPAL_AUTHENTICATED_RID]);
- $form['account']['roles'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Roles'),
- '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
- '#options' => $roles,
- '#access' => $roles && user_access('administer permissions'),
- DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
- );
-
- $form['account']['notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user of new account'),
- '#access' => $register && $admin,
- );
-
- // Signature.
- $form['signature_settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Signature settings'),
- '#weight' => 1,
- '#access' => (!$register && variable_get('user_signatures', 0)),
- );
-
- $form['signature_settings']['signature'] = array(
- '#type' => 'text_format',
- '#title' => t('Signature'),
- '#default_value' => isset($account->signature) ? $account->signature : '',
- '#description' => t('Your signature will be publicly displayed at the end of your comments.'),
- '#format' => isset($account->signature_format) ? $account->signature_format : NULL,
- );
-
- // Picture/avatar.
- $form['picture'] = array(
- '#type' => 'fieldset',
- '#title' => t('Picture'),
- '#weight' => 1,
- '#access' => (!$register && variable_get('user_pictures', 0)),
- );
- $form['picture']['picture'] = array(
- '#type' => 'value',
- '#value' => isset($account->picture) ? $account->picture : NULL,
- );
- $form['picture']['picture_current'] = array(
- '#markup' => theme('user_picture', array('account' => $account)),
- );
- $form['picture']['picture_delete'] = array(
- '#type' => 'checkbox',
- '#title' => t('Delete picture'),
- '#access' => !empty($account->picture->fid),
- '#description' => t('Check this box to delete your current picture.'),
- );
- $form['picture']['picture_upload'] = array(
- '#type' => 'file',
- '#title' => t('Upload picture'),
- '#size' => 48,
- '#description' => t('Your virtual face or picture. Pictures larger than @dimensions pixels will be scaled down.', array('@dimensions' => variable_get('user_picture_dimensions', '85x85'))) . ' ' . filter_xss_admin(variable_get('user_picture_guidelines', '')),
- );
- $form['#validate'][] = 'user_validate_picture';
-}
-
-/**
- * Form validation handler for the current password on the user_account_form().
- *
- * @see user_account_form()
- */
-function user_validate_current_pass(&$form, &$form_state) {
- $account = $form['#user'];
- foreach ($form_state['values']['current_pass_required_values'] as $key => $name) {
- // This validation only works for required textfields (like mail) or
- // form values like password_confirm that have their own validation
- // that prevent them from being empty if they are changed.
- if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
- if ($current_pass_failed) {
- form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
- form_set_error($key);
- }
- // We only need to check the password once.
- break;
- }
- }
-}
-
-/**
- * Form validation handler for user_account_form().
- *
- * @see user_account_form()
- */
-function user_account_form_validate($form, &$form_state) {
- if ($form['#user_category'] == 'account' || $form['#user_category'] == 'register') {
- $account = $form['#user'];
- // Validate new or changing username.
- if (isset($form_state['values']['name'])) {
- if ($error = user_validate_name($form_state['values']['name'])) {
- form_set_error('name', $error);
- }
- elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('name', db_like($form_state['values']['name']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
- form_set_error('name', t('The name %name is already taken.', array('%name' => $form_state['values']['name'])));
- }
- }
-
- // Trim whitespace from mail, to prevent confusing 'e-mail not valid'
- // warnings often caused by cutting and pasting.
- $mail = trim($form_state['values']['mail']);
- form_set_value($form['account']['mail'], $mail, $form_state);
-
- // Validate the e-mail address, and check if it is taken by an existing user.
- if ($error = user_validate_mail($form_state['values']['mail'])) {
- form_set_error('mail', $error);
- }
- elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($form_state['values']['mail']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
- // Format error message dependent on whether the user is logged in or not.
- if ($GLOBALS['user']->uid) {
- form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail'])));
- }
- else {
- form_set_error('mail', t('The e-mail address %email is already registered.
Have you forgotten your password? ', array('%email' => $form_state['values']['mail'], '@password' => url('user/password'))));
- }
- }
-
- // Make sure the signature isn't longer than the size of the database field.
- // Signatures are disabled by default, so make sure it exists first.
- if (isset($form_state['values']['signature'])) {
- // Move text format for user signature into 'signature_format'.
- $form_state['values']['signature_format'] = $form_state['values']['signature']['format'];
- // Move text value for user signature into 'signature'.
- $form_state['values']['signature'] = $form_state['values']['signature']['value'];
-
- $user_schema = drupal_get_schema('users');
- if (drupal_strlen($form_state['values']['signature']) > $user_schema['fields']['signature']['length']) {
- form_set_error('signature', t('The signature is too long: it must be %max characters or less.', array('%max' => $user_schema['fields']['signature']['length'])));
- }
- }
- }
-}
-
-/**
- * Implements hook_user_presave().
- */
-function user_user_presave(&$edit, $account, $category) {
- if ($category == 'account' || $category == 'register') {
- if (!empty($edit['picture_upload'])) {
- $edit['picture'] = $edit['picture_upload'];
- }
- // Delete picture if requested, and if no replacement picture was given.
- elseif (!empty($edit['picture_delete'])) {
- $edit['picture'] = NULL;
- }
- // Prepare user roles.
- if (isset($edit['roles'])) {
- $edit['roles'] = array_filter($edit['roles']);
- }
- }
-
- // Move account cancellation information into $user->data.
- foreach (array('user_cancel_method', 'user_cancel_notify') as $key) {
- if (isset($edit[$key])) {
- $edit['data'][$key] = $edit[$key];
- }
- }
-}
-
-/**
- * Implements hook_user_categories().
- */
-function user_user_categories() {
- return array(array(
- 'name' => 'account',
- 'title' => t('Account settings'),
- 'weight' => 1,
- ));
-}
-
-function user_login_block($form) {
- $form['#action'] = url(current_path(), array('query' => drupal_get_destination(), 'external' => FALSE));
- $form['#id'] = 'user-login-form';
- $form['#validate'] = user_login_default_validators();
- $form['#submit'][] = 'user_login_submit';
- $form['name'] = array('#type' => 'textfield',
- '#title' => t('Username'),
- '#maxlength' => USERNAME_MAX_LENGTH,
- '#size' => 15,
- '#required' => TRUE,
- );
- $form['pass'] = array('#type' => 'password',
- '#title' => t('Password'),
- '#size' => 15,
- '#required' => TRUE,
- );
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit',
- '#value' => t('Log in'),
- );
- $items = array();
- if (variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)) {
- $items[] = l(t('Create new account'), 'user/register', array('attributes' => array('title' => t('Create a new user account.'))));
- }
- $items[] = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
- $form['links'] = array('#markup' => theme('item_list', array('items' => $items)));
- return $form;
-}
-
-/**
- * Implements hook_block_info().
- */
-function user_block_info() {
- global $user;
-
- $blocks['login']['info'] = t('User login');
- // Not worth caching.
- $blocks['login']['cache'] = DRUPAL_NO_CACHE;
-
- $blocks['new']['info'] = t('Who\'s new');
- $blocks['new']['properties']['administrative'] = TRUE;
-
- // Too dynamic to cache.
- $blocks['online']['info'] = t('Who\'s online');
- $blocks['online']['cache'] = DRUPAL_NO_CACHE;
- $blocks['online']['properties']['administrative'] = TRUE;
-
- return $blocks;
-}
-
-/**
- * Implements hook_block_configure().
- */
-function user_block_configure($delta = '') {
- global $user;
-
- switch ($delta) {
- case 'new':
- $form['user_block_whois_new_count'] = array(
- '#type' => 'select',
- '#title' => t('Number of users to display'),
- '#default_value' => variable_get('user_block_whois_new_count', 5),
- '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
- );
- return $form;
-
- case 'online':
- $period = drupal_map_assoc(array(30, 60, 120, 180, 300, 600, 900, 1800, 2700, 3600, 5400, 7200, 10800, 21600, 43200, 86400), 'format_interval');
- $form['user_block_seconds_online'] = array('#type' => 'select', '#title' => t('User activity'), '#default_value' => variable_get('user_block_seconds_online', 900), '#options' => $period, '#description' => t('A user is considered online for this long after they have last viewed a page.'));
- $form['user_block_max_list_count'] = array('#type' => 'select', '#title' => t('User list length'), '#default_value' => variable_get('user_block_max_list_count', 10), '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100)), '#description' => t('Maximum number of currently online users to display.'));
- return $form;
- }
-}
-
-/**
- * Implements hook_block_save().
- */
-function user_block_save($delta = '', $edit = array()) {
- global $user;
-
- switch ($delta) {
- case 'new':
- variable_set('user_block_whois_new_count', $edit['user_block_whois_new_count']);
- break;
-
- case 'online':
- variable_set('user_block_seconds_online', $edit['user_block_seconds_online']);
- variable_set('user_block_max_list_count', $edit['user_block_max_list_count']);
- break;
- }
-}
-
-/**
- * Implements hook_block_view().
- */
-function user_block_view($delta = '') {
- global $user;
-
- $block = array();
-
- switch ($delta) {
- case 'login':
- // For usability's sake, avoid showing two login forms on one page.
- if (!$user->uid && !(arg(0) == 'user' && !is_numeric(arg(1)))) {
-
- $block['subject'] = t('User login');
- $block['content'] = drupal_get_form('user_login_block');
- }
- return $block;
-
- case 'new':
- if (user_access('access content')) {
- // Retrieve a list of new users who have subsequently accessed the site successfully.
- $items = db_query_range('SELECT uid, name FROM {users} WHERE status <> 0 AND access <> 0 ORDER BY created DESC', 0, variable_get('user_block_whois_new_count', 5))->fetchAll();
- $output = theme('user_list', array('users' => $items));
-
- $block['subject'] = t('Who\'s new');
- $block['content'] = $output;
- }
- return $block;
-
- case 'online':
- if (user_access('access content')) {
- // Count users active within the defined period.
- $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
-
- // Perform database queries to gather online user lists. We use s.timestamp
- // rather than u.access because it is much faster.
- $authenticated_count = db_query("SELECT COUNT(DISTINCT s.uid) FROM {sessions} s WHERE s.timestamp >= :timestamp AND s.uid > 0", array(':timestamp' => $interval))->fetchField();
-
- $output = '
' . format_plural($authenticated_count, 'There is currently 1 user online.', 'There are currently @count users online.') . '
';
-
- // Display a list of currently online users.
- $max_users = variable_get('user_block_max_list_count', 10);
- if ($authenticated_count && $max_users) {
- $items = db_query_range('SELECT u.uid, u.name, MAX(s.timestamp) AS max_timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= :interval AND s.uid > 0 GROUP BY u.uid, u.name ORDER BY max_timestamp DESC', 0, $max_users, array(':interval' => $interval))->fetchAll();
- $output .= theme('user_list', array('users' => $items));
- }
-
- $block['subject'] = t('Who\'s online');
- $block['content'] = $output;
- }
- return $block;
- }
-}
-
-/**
- * Process variables for user-picture.tpl.php.
- *
- * The $variables array contains the following arguments:
- * - $account: A user, node or comment object with 'name', 'uid' and 'picture'
- * fields.
- *
- * @see user-picture.tpl.php
- */
-function template_preprocess_user_picture(&$variables) {
- $variables['user_picture'] = '';
- if (variable_get('user_pictures', 0)) {
- $account = $variables['account'];
- if (!empty($account->picture)) {
- // @TODO: Ideally this function would only be passed file objects, but
- // since there's a lot of legacy code that JOINs the {users} table to
- // {node} or {comments} and passes the results into this function if we
- // a numeric value in the picture field we'll assume it's a file id
- // and load it for them. Once we've got user_load_multiple() and
- // comment_load_multiple() functions the user module will be able to load
- // the picture files in mass during the object's load process.
- if (is_numeric($account->picture)) {
- $account->picture = file_load($account->picture);
- }
- if (!empty($account->picture->uri)) {
- $filepath = $account->picture->uri;
- }
- }
- elseif (variable_get('user_picture_default', '')) {
- $filepath = variable_get('user_picture_default', '');
- }
- if (isset($filepath)) {
- $alt = t("@user's picture", array('@user' => format_username($account)));
- // If the image does not have a valid Drupal scheme (for eg. HTTP),
- // don't load image styles.
- if (module_exists('image') && file_valid_uri($filepath) && $style = variable_get('user_picture_style', '')) {
- $variables['user_picture'] = theme('image_style', array('style_name' => $style, 'path' => $filepath, 'alt' => $alt, 'title' => $alt));
- }
- else {
- $variables['user_picture'] = theme('image', array('path' => $filepath, 'alt' => $alt, 'title' => $alt));
- }
- if (!empty($account->uid) && user_access('access user profiles')) {
- $attributes = array('attributes' => array('title' => t('View user profile.')), 'html' => TRUE);
- $variables['user_picture'] = l($variables['user_picture'], "user/$account->uid", $attributes);
- }
- }
- }
-}
-
-/**
- * Returns HTML for a list of users.
- *
- * @param $variables
- * An associative array containing:
- * - users: An array with user objects. Should contain at least the name and
- * uid.
- * - title: (optional) Title to pass on to theme_item_list().
- *
- * @ingroup themeable
- */
-function theme_user_list($variables) {
- $users = $variables['users'];
- $title = $variables['title'];
- $items = array();
-
- if (!empty($users)) {
- foreach ($users as $user) {
- $items[] = theme('username', array('account' => $user));
- }
- }
- return theme('item_list', array('items' => $items, 'title' => $title));
-}
-
-/**
- * Determines if the current user is anonymous.
- *
- * @return bool
- * TRUE if the user is anonymous, FALSE if the user is authenticated.
- */
-function user_is_anonymous() {
- // Menu administrators can see items for anonymous when administering.
- return !$GLOBALS['user']->uid || !empty($GLOBALS['menu_admin']);
-}
-
-/**
- * Determines if the current user is logged in.
- *
- * @return bool
- * TRUE if the user is logged in, FALSE if the user is anonymous.
- */
-function user_is_logged_in() {
- return (bool) $GLOBALS['user']->uid;
-}
-
-/**
- * Determines if the current user has access to the user registration page.
- *
- * @return bool
- * TRUE if the user is not already logged in and can register for an account.
- */
-function user_register_access() {
- return user_is_anonymous() && variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
-}
-
-/**
- * User view access callback.
- *
- * @param $account
- * Can either be a full user object or a $uid.
- */
-function user_view_access($account) {
- $uid = is_object($account) ? $account->uid : (int) $account;
-
- // Never allow access to view the anonymous user account.
- if ($uid) {
- // Admins can view all, users can view own profiles at all times.
- if ($GLOBALS['user']->uid == $uid || user_access('administer users')) {
- return TRUE;
- }
- elseif (user_access('access user profiles')) {
- // At this point, load the complete account object.
- if (!is_object($account)) {
- $account = user_load($uid);
- }
- return (is_object($account) && $account->status);
- }
- }
- return FALSE;
-}
-
-/**
- * Access callback for user account editing.
- */
-function user_edit_access($account) {
- return (($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0;
-}
-
-/**
- * Menu access callback; limit access to account cancellation pages.
- *
- * Limit access to users with the 'cancel account' permission or administrative
- * users, and prevent the anonymous user from cancelling the account.
- */
-function user_cancel_access($account) {
- return ((($GLOBALS['user']->uid == $account->uid) && user_access('cancel account')) || user_access('administer users')) && $account->uid > 0;
-}
-
-/**
- * Implements hook_menu().
- */
-function user_menu() {
- $items['user/autocomplete'] = array(
- 'title' => 'User autocomplete',
- 'page callback' => 'user_autocomplete',
- 'access callback' => 'user_access',
- 'access arguments' => array('access user profiles'),
- 'type' => MENU_CALLBACK,
- 'file' => 'user.pages.inc',
- );
-
- // Registration and login pages.
- $items['user'] = array(
- 'title' => 'User account',
- 'title callback' => 'user_menu_title',
- 'page callback' => 'user_page',
- 'access callback' => TRUE,
- 'file' => 'user.pages.inc',
- 'weight' => -10,
- 'menu_name' => 'user-menu',
- );
-
- $items['user/login'] = array(
- 'title' => 'Log in',
- 'access callback' => 'user_is_anonymous',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
-
- $items['user/register'] = array(
- 'title' => 'Create new account',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_register_form'),
- 'access callback' => 'user_register_access',
- 'type' => MENU_LOCAL_TASK,
- );
-
- $items['user/password'] = array(
- 'title' => 'Request new password',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_pass'),
- 'access callback' => TRUE,
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'user.pages.inc',
- );
- $items['user/reset/%/%/%'] = array(
- 'title' => 'Reset password',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_pass_reset', 2, 3, 4),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- 'file' => 'user.pages.inc',
- );
-
- $items['user/logout'] = array(
- 'title' => 'Log out',
- 'access callback' => 'user_is_logged_in',
- 'page callback' => 'user_logout',
- 'weight' => 10,
- 'menu_name' => 'user-menu',
- 'file' => 'user.pages.inc',
- );
-
- // User listing pages.
- $items['admin/people'] = array(
- 'title' => 'People',
- 'description' => 'Manage user accounts, roles, and permissions.',
- 'page callback' => 'user_admin',
- 'page arguments' => array('list'),
- 'access arguments' => array('administer users'),
- 'position' => 'left',
- 'weight' => -4,
- 'file' => 'user.admin.inc',
- );
- $items['admin/people/people'] = array(
- 'title' => 'List',
- 'description' => 'Find and manage people interacting with your site.',
- 'access arguments' => array('administer users'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- 'file' => 'user.admin.inc',
- );
-
- // Permissions and role forms.
- $items['admin/people/permissions'] = array(
- 'title' => 'Permissions',
- 'description' => 'Determine access to features by selecting permissions for roles.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_admin_permissions'),
- 'access arguments' => array('administer permissions'),
- 'file' => 'user.admin.inc',
- 'type' => MENU_LOCAL_TASK,
- );
- $items['admin/people/permissions/list'] = array(
- 'title' => 'Permissions',
- 'description' => 'Determine access to features by selecting permissions for roles.',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -8,
- );
- $items['admin/people/permissions/roles'] = array(
- 'title' => 'Roles',
- 'description' => 'List, edit, or add user roles.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_admin_roles'),
- 'access arguments' => array('administer permissions'),
- 'file' => 'user.admin.inc',
- 'type' => MENU_LOCAL_TASK,
- 'weight' => -5,
- );
- $items['admin/people/permissions/roles/edit/%user_role'] = array(
- 'title' => 'Edit role',
- 'page arguments' => array('user_admin_role', 5),
- 'access callback' => 'user_role_edit_access',
- 'access arguments' => array(5),
- );
- $items['admin/people/permissions/roles/delete/%user_role'] = array(
- 'title' => 'Delete role',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_admin_role_delete_confirm', 5),
- 'access callback' => 'user_role_edit_access',
- 'access arguments' => array(5),
- 'file' => 'user.admin.inc',
- );
-
- $items['admin/people/create'] = array(
- 'title' => 'Add user',
- 'page arguments' => array('create'),
- 'access arguments' => array('administer users'),
- 'type' => MENU_LOCAL_ACTION,
- );
-
- // Administration pages.
- $items['admin/config/people'] = array(
- 'title' => 'People',
- 'description' => 'Configure user accounts.',
- 'position' => 'left',
- 'weight' => -20,
- 'page callback' => 'system_admin_menu_block_page',
- 'access arguments' => array('access administration pages'),
- 'file' => 'system.admin.inc',
- 'file path' => drupal_get_path('module', 'system'),
- );
- $items['admin/config/people/accounts'] = array(
- 'title' => 'Account settings',
- 'description' => 'Configure default behavior of users, including registration requirements, e-mails, fields, and user pictures.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_admin_settings'),
- 'access arguments' => array('administer users'),
- 'file' => 'user.admin.inc',
- 'weight' => -10,
- );
- $items['admin/config/people/accounts/settings'] = array(
- 'title' => 'Settings',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
-
- $items['user/%user'] = array(
- 'title' => 'My account',
- 'title callback' => 'user_page_title',
- 'title arguments' => array(1),
- 'page callback' => 'user_view_page',
- 'page arguments' => array(1),
- 'access callback' => 'user_view_access',
- 'access arguments' => array(1),
- // By assigning a different menu name, this item (and all registered child
- // paths) are no longer considered as children of 'user'. When accessing the
- // user account pages, the preferred menu link that is used to build the
- // active trail (breadcrumb) will be found in this menu (unless there is
- // more specific link), so the link to 'user' will not be in the breadcrumb.
- 'menu_name' => 'navigation',
- );
-
- $items['user/%user/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
-
- $items['user/%user/cancel'] = array(
- 'title' => 'Cancel account',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_cancel_confirm_form', 1),
- 'access callback' => 'user_cancel_access',
- 'access arguments' => array(1),
- 'file' => 'user.pages.inc',
- );
-
- $items['user/%user/cancel/confirm/%/%'] = array(
- 'title' => 'Confirm account cancellation',
- 'page callback' => 'user_cancel_confirm',
- 'page arguments' => array(1, 4, 5),
- 'access callback' => 'user_cancel_access',
- 'access arguments' => array(1),
- 'file' => 'user.pages.inc',
- );
-
- $items['user/%user/edit'] = array(
- 'title' => 'Edit',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_profile_form', 1),
- 'access callback' => 'user_edit_access',
- 'access arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'user.pages.inc',
- );
-
- $items['user/%user_category/edit/account'] = array(
- 'title' => 'Account',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'load arguments' => array('%map', '%index'),
- );
-
- if (($categories = _user_categories()) && (count($categories) > 1)) {
- foreach ($categories as $key => $category) {
- // 'account' is already handled by the MENU_DEFAULT_LOCAL_TASK.
- if ($category['name'] != 'account') {
- $items['user/%user_category/edit/' . $category['name']] = array(
- 'title callback' => 'check_plain',
- 'title arguments' => array($category['title']),
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('user_profile_form', 1, 3),
- 'access callback' => isset($category['access callback']) ? $category['access callback'] : 'user_edit_access',
- 'access arguments' => isset($category['access arguments']) ? $category['access arguments'] : array(1),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => $category['weight'],
- 'load arguments' => array('%map', '%index'),
- 'tab_parent' => 'user/%/edit',
- 'file' => 'user.pages.inc',
- );
- }
- }
- }
- return $items;
-}
-
-/**
- * Implements hook_menu_site_status_alter().
- */
-function user_menu_site_status_alter(&$menu_site_status, $path) {
- if ($menu_site_status == MENU_SITE_OFFLINE) {
- // If the site is offline, log out unprivileged users.
- if (user_is_logged_in() && !user_access('access site in maintenance mode')) {
- module_load_include('pages.inc', 'user', 'user');
- user_logout();
- }
-
- if (user_is_anonymous()) {
- switch ($path) {
- case 'user':
- // Forward anonymous user to login page.
- drupal_goto('user/login');
- case 'user/login':
- case 'user/password':
- // Disable offline mode.
- $menu_site_status = MENU_SITE_ONLINE;
- break;
- default:
- if (strpos($path, 'user/reset/') === 0) {
- // Disable offline mode.
- $menu_site_status = MENU_SITE_ONLINE;
- }
- break;
- }
- }
- }
- if (user_is_logged_in()) {
- if ($path == 'user/login') {
- // If user is logged in, redirect to 'user' instead of giving 403.
- drupal_goto('user');
- }
- if ($path == 'user/register') {
- // Authenticated user should be redirected to user edit page.
- drupal_goto('user/' . $GLOBALS['user']->uid . '/edit');
- }
- }
-}
-
-/**
- * Implements hook_menu_link_alter().
- */
-function user_menu_link_alter(&$link) {
- // The path 'user' must be accessible for anonymous users, but only visible
- // for authenticated users. Authenticated users should see "My account", but
- // anonymous users should not see it at all. Therefore, invoke
- // user_translated_menu_link_alter() to conditionally hide the link.
- if ($link['link_path'] == 'user' && $link['module'] == 'system') {
- $link['options']['alter'] = TRUE;
- }
-
- // Force the Logout link to appear on the top-level of 'user-menu' menu by
- // default (i.e., unless it has been customized).
- if ($link['link_path'] == 'user/logout' && $link['module'] == 'system' && empty($link['customized'])) {
- $link['plid'] = 0;
- }
-}
-
-/**
- * Implements hook_translated_menu_link_alter().
- */
-function user_translated_menu_link_alter(&$link) {
- // Hide the "User account" link for anonymous users.
- if ($link['link_path'] == 'user' && $link['module'] == 'system' && !$GLOBALS['user']->uid) {
- $link['hidden'] = 1;
- }
-}
-
-/**
- * Implements hook_admin_paths().
- */
-function user_admin_paths() {
- $paths = array(
- 'user/*/cancel' => TRUE,
- 'user/*/edit' => TRUE,
- 'user/*/edit/*' => TRUE,
- );
- return $paths;
-}
-
-/**
- * Returns $arg or the user ID of the current user if $arg is '%' or empty.
- *
- * Deprecated. Use %user_uid_optional instead.
- *
- * @todo D8: Remove.
- */
-function user_uid_only_optional_to_arg($arg) {
- return user_uid_optional_to_arg($arg);
-}
-
-/**
- * Load either a specified or the current user account.
- *
- * @param $uid
- * An optional user ID of the user to load. If not provided, the current
- * user's ID will be used.
- * @return
- * A fully-loaded $user object upon successful user load, FALSE if user
- * cannot be loaded.
- *
- * @see user_load()
- * @todo rethink the naming of this in Drupal 8.
- */
-function user_uid_optional_load($uid = NULL) {
- if (!isset($uid)) {
- $uid = $GLOBALS['user']->uid;
- }
- return user_load($uid);
-}
-
-/**
- * Return a user object after checking if any profile category in the path exists.
- */
-function user_category_load($uid, &$map, $index) {
- static $user_categories, $accounts;
-
- // Cache $account - this load function will get called for each profile tab.
- if (!isset($accounts[$uid])) {
- $accounts[$uid] = user_load($uid);
- }
- $valid = TRUE;
- if ($account = $accounts[$uid]) {
- // Since the path is like user/%/edit/category_name, the category name will
- // be at a position 2 beyond the index corresponding to the % wildcard.
- $category_index = $index + 2;
- // Valid categories may contain slashes, and hence need to be imploded.
- $category_path = implode('/', array_slice($map, $category_index));
- if ($category_path) {
- // Check that the requested category exists.
- $valid = FALSE;
- if (!isset($user_categories)) {
- $user_categories = _user_categories();
- }
- foreach ($user_categories as $category) {
- if ($category['name'] == $category_path) {
- $valid = TRUE;
- // Truncate the map array in case the category name had slashes.
- $map = array_slice($map, 0, $category_index);
- // Assign the imploded category name to the last map element.
- $map[$category_index] = $category_path;
- break;
- }
- }
- }
- }
- return $valid ? $account : FALSE;
-}
-
-/**
- * Returns $arg or the user ID of the current user if $arg is '%' or empty.
- *
- * @todo rethink the naming of this in Drupal 8.
- */
-function user_uid_optional_to_arg($arg) {
- // Give back the current user uid when called from eg. tracker, aka.
- // with an empty arg. Also use the current user uid when called from
- // the menu with a % for the current account link.
- return empty($arg) || $arg == '%' ? $GLOBALS['user']->uid : $arg;
-}
-
-/**
- * Menu item title callback for the 'user' path.
- *
- * Anonymous users should see "User account", but authenticated users are
- * expected to see "My account".
- */
-function user_menu_title() {
- return user_is_logged_in() ? t('My account') : t('User account');
-}
-
-/**
- * Menu item title callback - use the user name.
- */
-function user_page_title($account) {
- return is_object($account) ? format_username($account) : '';
-}
-
-/**
- * Discover which external authentication module(s) authenticated a username.
- *
- * @param $authname
- * A username used by an external authentication module.
- * @return
- * An associative array with module as key and username as value.
- */
-function user_get_authmaps($authname = NULL) {
- $authmaps = db_query("SELECT module, authname FROM {authmap} WHERE authname = :authname", array(':authname' => $authname))->fetchAllKeyed();
- return count($authmaps) ? $authmaps : 0;
-}
-
-/**
- * Save mappings of which external authentication module(s) authenticated
- * a user. Maps external usernames to user ids in the users table.
- *
- * @param $account
- * A user object.
- * @param $authmaps
- * An associative array with a compound key and the username as the value.
- * The key is made up of 'authname_' plus the name of the external authentication
- * module.
- * @see user_external_login_register()
- */
-function user_set_authmaps($account, $authmaps) {
- foreach ($authmaps as $key => $value) {
- $module = explode('_', $key, 2);
- if ($value) {
- db_merge('authmap')
- ->key(array(
- 'uid' => $account->uid,
- 'module' => $module[1],
- ))
- ->fields(array('authname' => $value))
- ->execute();
- }
- else {
- db_delete('authmap')
- ->condition('uid', $account->uid)
- ->condition('module', $module[1])
- ->execute();
- }
- }
-}
-
-/**
- * Form builder; the main user login form.
- *
- * @ingroup forms
- */
-function user_login($form, &$form_state) {
- global $user;
-
- // If we are already logged on, go to the user page instead.
- if ($user->uid) {
- drupal_goto('user/' . $user->uid);
- }
-
- // Display login form:
- $form['name'] = array('#type' => 'textfield',
- '#title' => t('Username'),
- '#size' => 60,
- '#maxlength' => USERNAME_MAX_LENGTH,
- '#required' => TRUE,
- );
-
- $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
- $form['pass'] = array('#type' => 'password',
- '#title' => t('Password'),
- '#description' => t('Enter the password that accompanies your username.'),
- '#required' => TRUE,
- );
- $form['#validate'] = user_login_default_validators();
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
-
- return $form;
-}
-
-/**
- * Set up a series for validators which check for blocked users,
- * then authenticate against local database, then return an error if
- * authentication fails. Distributed authentication modules are welcome
- * to use hook_form_alter() to change this series in order to
- * authenticate against their user database instead of the local users
- * table. If a distributed authentication module is successful, it
- * should set $form_state['uid'] to a user ID.
- *
- * We use three validators instead of one since external authentication
- * modules usually only need to alter the second validator.
- *
- * @see user_login_name_validate()
- * @see user_login_authenticate_validate()
- * @see user_login_final_validate()
- * @return array
- * A simple list of validate functions.
- */
-function user_login_default_validators() {
- return array('user_login_name_validate', 'user_login_authenticate_validate', 'user_login_final_validate');
-}
-
-/**
- * A FAPI validate handler. Sets an error if supplied username has been blocked.
- */
-function user_login_name_validate($form, &$form_state) {
- if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
- // Blocked in user administration.
- form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
- }
-}
-
-/**
- * A validate handler on the login form. Check supplied username/password
- * against local users table. If successful, $form_state['uid']
- * is set to the matching user ID.
- */
-function user_login_authenticate_validate($form, &$form_state) {
- $password = trim($form_state['values']['pass']);
- if (!empty($form_state['values']['name']) && !empty($password)) {
- // Do not allow any login from the current user's IP if the limit has been
- // reached. Default is 50 failed attempts allowed in one hour. This is
- // independent of the per-user limit to catch attempts from one IP to log
- // in to many different user accounts. We have a reasonably high limit
- // since there may be only one apparent IP for all users at an institution.
- if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {
- $form_state['flood_control_triggered'] = 'ip';
- return;
- }
- $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
- if ($account) {
- if (variable_get('user_failed_login_identifier_uid_only', FALSE)) {
- // Register flood events based on the uid only, so they apply for any
- // IP address. This is the most secure option.
- $identifier = $account->uid;
- }
- else {
- // The default identifier is a combination of uid and IP address. This
- // is less secure but more resistant to denial-of-service attacks that
- // could lock out all users with public user names.
- $identifier = $account->uid . '-' . ip_address();
- }
- $form_state['flood_control_user_identifier'] = $identifier;
-
- // Don't allow login if the limit for this user has been reached.
- // Default is to allow 5 failed attempts every 6 hours.
- if (!flood_is_allowed('failed_login_attempt_user', variable_get('user_failed_login_user_limit', 5), variable_get('user_failed_login_user_window', 21600), $identifier)) {
- $form_state['flood_control_triggered'] = 'user';
- return;
- }
- }
- // We are not limited by flood control, so try to authenticate.
- // Set $form_state['uid'] as a flag for user_login_final_validate().
- $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
- }
-}
-
-/**
- * The final validation handler on the login form.
- *
- * Sets a form error if user has not been authenticated, or if too many
- * logins have been attempted. This validation function should always
- * be the last one.
- */
-function user_login_final_validate($form, &$form_state) {
- if (empty($form_state['uid'])) {
- // Always register an IP-based failed login event.
- flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
- // Register a per-user failed login event.
- if (isset($form_state['flood_control_user_identifier'])) {
- flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $form_state['flood_control_user_identifier']);
- }
-
- if (isset($form_state['flood_control_triggered'])) {
- if ($form_state['flood_control_triggered'] == 'user') {
- form_set_error('name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or
request a new password .', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or
request a new password .', array('@url' => url('user/password'))));
- }
- else {
- // We did not find a uid, so the limit is IP-based.
- form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or
request a new password .', array('@url' => url('user/password'))));
- }
- }
- else {
- form_set_error('name', t('Sorry, unrecognized username or password.
Have you forgotten your password? ', array('@password' => url('user/password', array('query' => array('name' => $form_state['values']['name']))))));
- watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
- }
- }
- elseif (isset($form_state['flood_control_user_identifier'])) {
- // Clear past failures for this user so as not to block a user who might
- // log in and out more than once in an hour.
- flood_clear_event('failed_login_attempt_user', $form_state['flood_control_user_identifier']);
- }
-}
-
-/**
- * Try to validate the user's login credentials locally.
- *
- * @param $name
- * User name to authenticate.
- * @param $password
- * A plain-text password, such as trimmed text from form values.
- * @return
- * The user's uid on success, or FALSE on failure to authenticate.
- */
-function user_authenticate($name, $password) {
- $uid = FALSE;
- if (!empty($name) && !empty($password)) {
- $account = user_load_by_name($name);
- if ($account) {
- // Allow alternate password hashing schemes.
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- if (user_check_password($password, $account)) {
- // Successful authentication.
- $uid = $account->uid;
-
- // Update user to new password scheme if needed.
- if (user_needs_new_hash($account)) {
- user_save($account, array('pass' => $password));
- }
- }
- }
- }
- return $uid;
-}
-
-/**
- * Finalize the login process. Must be called when logging in a user.
- *
- * The function records a watchdog message about the new session, saves the
- * login timestamp, calls hook_user_login(), and generates a new session.
- *
- * @param array $edit
- * The array of form values submitted by the user.
- *
- * @see hook_user_login()
- */
-function user_login_finalize(&$edit = array()) {
- global $user;
- watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
- // Update the user table timestamp noting user has logged in.
- // This is also used to invalidate one-time login links.
- $user->login = REQUEST_TIME;
- db_update('users')
- ->fields(array('login' => $user->login))
- ->condition('uid', $user->uid)
- ->execute();
-
- // Regenerate the session ID to prevent against session fixation attacks.
- // This is called before hook_user in case one of those functions fails
- // or incorrectly does a redirect which would leave the old session in place.
- drupal_session_regenerate();
-
- user_module_invoke('login', $edit, $user);
-}
-
-/**
- * Submit handler for the login form. Load $user object and perform standard login
- * tasks. The user is then redirected to the My Account page. Setting the
- * destination in the query string overrides the redirect.
- */
-function user_login_submit($form, &$form_state) {
- global $user;
- $user = user_load($form_state['uid']);
- $form_state['redirect'] = 'user/' . $user->uid;
-
- user_login_finalize($form_state);
-}
-
-/**
- * Helper function for authentication modules. Either logs in or registers
- * the current user, based on username. Either way, the global $user object is
- * populated and login tasks are performed.
- */
-function user_external_login_register($name, $module) {
- $account = user_external_load($name);
- if (!$account) {
- // Register this new user.
- $userinfo = array(
- 'name' => $name,
- 'pass' => user_password(),
- 'init' => $name,
- 'status' => 1,
- 'access' => REQUEST_TIME
- );
- $account = user_save(drupal_anonymous_user(), $userinfo);
- // Terminate if an error occurred during user_save().
- if (!$account) {
- drupal_set_message(t("Error saving user account."), 'error');
- return;
- }
- user_set_authmaps($account, array("authname_$module" => $name));
- }
-
- // Log user in.
- $form_state['uid'] = $account->uid;
- user_login_submit(array(), $form_state);
-}
-
-/**
- * Generates a unique URL for a user to login and reset their password.
- *
- * @param object $account
- * An object containing the user account, which must contain at least the
- * following properties:
- * - uid: The user ID number.
- * - login: The UNIX timestamp of the user's last login.
- *
- * @return
- * A unique URL that provides a one-time log in for the user, from which
- * they can change their password.
- */
-function user_pass_reset_url($account) {
- $timestamp = REQUEST_TIME;
- return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE));
-}
-
-/**
- * Generates a URL to confirm an account cancellation request.
- *
- * @param object $account
- * The user account object, which must contain at least the following
- * properties:
- * - uid: The user ID number.
- * - pass: The hashed user password string.
- * - login: The UNIX timestamp of the user's last login.
- *
- * @return
- * A unique URL that may be used to confirm the cancellation of the user
- * account.
- *
- * @see user_mail_tokens()
- * @see user_cancel_confirm()
- */
-function user_cancel_url($account) {
- $timestamp = REQUEST_TIME;
- 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
- * timestamp and hashed password are retrieved from the database as necessary.
- * For a usage example, see user_cancel_url() and user_cancel_confirm().
- *
- * @param string $password
- * The hashed user account password value.
- * @param int $timestamp
- * A UNIX timestamp, typically REQUEST_TIME.
- * @param int $login
- * The UNIX timestamp of the user's last login.
- *
- * @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);
-}
-
-/**
- * Cancel a user account.
- *
- * Since the user cancellation process needs to be run in a batch, either
- * Form API will invoke it, or batch_process() needs to be invoked after calling
- * this function and should define the path to redirect to.
- *
- * @param $edit
- * An array of submitted form values.
- * @param $uid
- * The user ID of the user account to cancel.
- * @param $method
- * The account cancellation method to use.
- *
- * @see _user_cancel()
- */
-function user_cancel($edit, $uid, $method) {
- global $user;
-
- $account = user_load($uid);
-
- if (!$account) {
- drupal_set_message(t('The user account %id does not exist.', array('%id' => $uid)), 'error');
- watchdog('user', 'Attempted to cancel non-existing user account: %id.', array('%id' => $uid), WATCHDOG_ERROR);
- return;
- }
-
- // Initialize batch (to set title).
- $batch = array(
- 'title' => t('Cancelling account'),
- 'operations' => array(),
- );
- batch_set($batch);
-
- // Modules use hook_user_delete() to respond to deletion.
- if ($method != 'user_cancel_delete') {
- // Allow modules to add further sets to this batch.
- module_invoke_all('user_cancel', $edit, $account, $method);
- }
-
- // Finish the batch and actually cancel the account.
- $batch = array(
- 'title' => t('Cancelling user account'),
- 'operations' => array(
- array('_user_cancel', array($edit, $account, $method)),
- ),
- );
-
- // After cancelling account, ensure that user is logged out.
- if ($account->uid == $user->uid) {
- // Batch API stores data in the session, so use the finished operation to
- // manipulate the current user's session id.
- $batch['finished'] = '_user_cancel_session_regenerate';
- }
-
- batch_set($batch);
-
- // Batch processing is either handled via Form API or has to be invoked
- // manually.
-}
-
-/**
- * Last batch processing step for cancelling a user account.
- *
- * Since batch and session API require a valid user account, the actual
- * cancellation of a user account needs to happen last.
- *
- * @see user_cancel()
- */
-function _user_cancel($edit, $account, $method) {
- global $user;
-
- switch ($method) {
- case 'user_cancel_block':
- case 'user_cancel_block_unpublish':
- default:
- // Send account blocked notification if option was checked.
- if (!empty($edit['user_cancel_notify'])) {
- _user_mail_notify('status_blocked', $account);
- }
- user_save($account, array('status' => 0));
- drupal_set_message(t('%name has been disabled.', array('%name' => $account->name)));
- watchdog('user', 'Blocked user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
- break;
-
- case 'user_cancel_reassign':
- case 'user_cancel_delete':
- // Send account canceled notification if option was checked.
- if (!empty($edit['user_cancel_notify'])) {
- _user_mail_notify('status_canceled', $account);
- }
- user_delete($account->uid);
- drupal_set_message(t('%name has been deleted.', array('%name' => $account->name)));
- watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
- break;
- }
-
- // After cancelling account, ensure that user is logged out. We can't destroy
- // their session though, as we might have information in it, and we can't
- // regenerate it because batch API uses the session ID, we will regenerate it
- // in _user_cancel_session_regenerate().
- if ($account->uid == $user->uid) {
- $user = drupal_anonymous_user();
- }
-
- // Clear the cache for anonymous users.
- cache_clear_all();
-}
-
-/**
- * Finished batch processing callback for cancelling a user account.
- *
- * @see user_cancel()
- */
-function _user_cancel_session_regenerate() {
- // Regenerate the users session instead of calling session_destroy() as we
- // want to preserve any messages that might have been set.
- drupal_session_regenerate();
-}
-
-/**
- * Delete a user.
- *
- * @param $uid
- * A user ID.
- */
-function user_delete($uid) {
- user_delete_multiple(array($uid));
-}
-
-/**
- * Delete multiple user accounts.
- *
- * @param $uids
- * An array of user IDs.
- */
-function user_delete_multiple(array $uids) {
- if (!empty($uids)) {
- $accounts = user_load_multiple($uids, array());
-
- $transaction = db_transaction();
- try {
- foreach ($accounts as $uid => $account) {
- module_invoke_all('user_delete', $account);
- module_invoke_all('entity_delete', $account, 'user');
- field_attach_delete('user', $account);
- drupal_session_destroy_uid($account->uid);
- }
-
- db_delete('users')
- ->condition('uid', $uids, 'IN')
- ->execute();
- db_delete('users_roles')
- ->condition('uid', $uids, 'IN')
- ->execute();
- db_delete('authmap')
- ->condition('uid', $uids, 'IN')
- ->execute();
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception('user', $e);
- throw $e;
- }
- entity_get_controller('user')->resetCache();
- }
-}
-
-/**
- * Page callback wrapper for user_view().
- */
-function user_view_page($account) {
- // An administrator may try to view a non-existent account,
- // so we give them a 404 (versus a 403 for non-admins).
- return is_object($account) ? user_view($account) : MENU_NOT_FOUND;
-}
-
-/**
- * Generate an array for rendering the given user.
- *
- * When viewing a user profile, the $page array contains:
- *
- * - $page['content']['Profile Category']:
- * Profile categories keyed by their human-readable names.
- * - $page['content']['Profile Category']['profile_machine_name']:
- * Profile fields keyed by their machine-readable names.
- * - $page['content']['user_picture']:
- * User's rendered picture.
- * - $page['content']['summary']:
- * Contains the default "History" profile data for a user.
- * - $page['content']['#account']:
- * The user account of the profile being viewed.
- *
- * To theme user profiles, copy modules/user/user-profile.tpl.php
- * to your theme directory, and edit it as instructed in that file's comments.
- *
- * @param $account
- * A user object.
- * @param $view_mode
- * View mode, e.g. 'full'.
- * @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
- *
- * @return
- * An array as expected by drupal_render().
- */
-function user_view($account, $view_mode = 'full', $langcode = NULL) {
- if (!isset($langcode)) {
- $langcode = $GLOBALS['language_content']->language;
- }
-
- // Retrieve all profile fields and attach to $account->content.
- user_build_content($account, $view_mode, $langcode);
-
- $build = $account->content;
- // We don't need duplicate rendering info in account->content.
- unset($account->content);
-
- $build += array(
- '#theme' => 'user_profile',
- '#account' => $account,
- '#view_mode' => $view_mode,
- '#language' => $langcode,
- );
-
- // Allow modules to modify the structured user.
- $type = 'user';
- drupal_alter(array('user_view', 'entity_view'), $build, $type);
-
- return $build;
-}
-
-/**
- * Builds a structured array representing the profile content.
- *
- * @param $account
- * A user object.
- * @param $view_mode
- * View mode, e.g. 'full'.
- * @param $langcode
- * (optional) A language code to use for rendering. Defaults to the global
- * content language of the current request.
- */
-function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
- if (!isset($langcode)) {
- $langcode = $GLOBALS['language_content']->language;
- }
-
- // Remove previously built content, if exists.
- $account->content = array();
-
- // Allow modules to change the view mode.
- $context = array(
- 'entity_type' => 'user',
- 'entity' => $account,
- 'langcode' => $langcode,
- );
- drupal_alter('entity_view_mode', $view_mode, $context);
-
- // Build fields content.
- field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode);
- entity_prepare_view('user', array($account->uid => $account), $langcode);
- $account->content += field_attach_view('user', $account, $view_mode, $langcode);
-
- // Populate $account->content with a render() array.
- module_invoke_all('user_view', $account, $view_mode, $langcode);
- module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode);
-
- // Make sure the current view mode is stored if no module has already
- // populated the related key.
- $account->content += array('#view_mode' => $view_mode);
-}
-
-/**
- * Implements hook_mail().
- */
-function user_mail($key, &$message, $params) {
- $language = $message['language'];
- $variables = array('user' => $params['account']);
- $message['subject'] .= _user_mail_text($key . '_subject', $language, $variables);
- $message['body'][] = _user_mail_text($key . '_body', $language, $variables);
-}
-
-/**
- * Returns a mail string for a variable name.
- *
- * Used by user_mail() and the settings forms to retrieve strings.
- */
-function _user_mail_text($key, $language = NULL, $variables = array(), $replace = TRUE) {
- $langcode = isset($language) ? $language->language : NULL;
-
- if ($admin_setting = variable_get('user_mail_' . $key, FALSE)) {
- // An admin setting overrides the default string.
- $text = $admin_setting;
- }
- else {
- // No override, return default string.
- switch ($key) {
- case 'register_no_approval_required_subject':
- $text = t('Account details for [user:name] at [site:name]', array(), array('langcode' => $langcode));
- break;
- case 'register_no_approval_required_body':
- $text = t("[user:name],
-
-Thank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:
-
-[user:one-time-login-url]
-
-This link can only be used once to log in and will lead you to a page where you can set your password.
-
-After setting your password, you will be able to log in at [site:login-url] in the future using:
-
-username: [user:name]
-password: Your password
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'register_admin_created_subject':
- $text = t('An administrator created an account for you at [site:name]', array(), array('langcode' => $langcode));
- break;
- case 'register_admin_created_body':
- $text = t("[user:name],
-
-A site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:
-
-[user:one-time-login-url]
-
-This link can only be used once to log in and will lead you to a page where you can set your password.
-
-After setting your password, you will be able to log in at [site:login-url] in the future using:
-
-username: [user:name]
-password: Your password
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'register_pending_approval_subject':
- case 'register_pending_approval_admin_subject':
- $text = t('Account details for [user:name] at [site:name] (pending admin approval)', array(), array('langcode' => $langcode));
- break;
- case 'register_pending_approval_body':
- $text = t("[user:name],
-
-Thank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another e-mail containing information about how to log in, set your password, and other details.
-
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
- case 'register_pending_approval_admin_body':
- $text = t("[user:name] has applied for an account.
-
-[user:edit-url]", array(), array('langcode' => $langcode));
- break;
-
- case 'password_reset_subject':
- $text = t('Replacement login information for [user:name] at [site:name]', array(), array('langcode' => $langcode));
- break;
- case 'password_reset_body':
- $text = t("[user:name],
-
-A request to reset the password for your account has been made at [site:name].
-
-You may now log in by clicking this link or copying and pasting it to your browser:
-
-[user:one-time-login-url]
-
-This link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'status_activated_subject':
- $text = t('Account details for [user:name] at [site:name] (approved)', array(), array('langcode' => $langcode));
- break;
- case 'status_activated_body':
- $text = t("[user:name],
-
-Your account at [site:name] has been activated.
-
-You may now log in by clicking this link or copying and pasting it into your browser:
-
-[user:one-time-login-url]
-
-This link can only be used once to log in and will lead you to a page where you can set your password.
-
-After setting your password, you will be able to log in at [site:login-url] in the future using:
-
-username: [user:name]
-password: Your password
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'status_blocked_subject':
- $text = t('Account details for [user:name] at [site:name] (blocked)', array(), array('langcode' => $langcode));
- break;
- case 'status_blocked_body':
- $text = t("[user:name],
-
-Your account on [site:name] has been blocked.
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'cancel_confirm_subject':
- $text = t('Account cancellation request for [user:name] at [site:name]', array(), array('langcode' => $langcode));
- break;
- case 'cancel_confirm_body':
- $text = t("[user:name],
-
-A request to cancel your account has been made at [site:name].
-
-You may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:
-
-[user:cancel-url]
-
-NOTE: The cancellation of your account is not reversible.
-
-This link expires in one day and nothing will happen if it is not used.
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
-
- case 'status_canceled_subject':
- $text = t('Account details for [user:name] at [site:name] (canceled)', array(), array('langcode' => $langcode));
- break;
- case 'status_canceled_body':
- $text = t("[user:name],
-
-Your account on [site:name] has been canceled.
-
--- [site:name] team", array(), array('langcode' => $langcode));
- break;
- }
- }
-
- if ($replace) {
- // We do not sanitize the token replacement, since the output of this
- // replacement is intended for an e-mail message, not a web browser.
- return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
- }
-
- return $text;
-}
-
-/**
- * Token callback to add unsafe tokens for user mails.
- *
- * This function is used by the token_replace() call at the end of
- * _user_mail_text() to set up some additional tokens that can be
- * used in email messages generated by user_mail().
- *
- * @param $replacements
- * An associative array variable containing mappings from token names to
- * values (for use with strtr()).
- * @param $data
- * An associative array of token replacement values. If the 'user' element
- * exists, it must contain a user account object with the following
- * properties:
- * - login: The UNIX timestamp of the user's last login.
- * - pass: The hashed account login password.
- * @param $options
- * Unused parameter required by the token_replace() function.
- */
-function user_mail_tokens(&$replacements, $data, $options) {
- if (isset($data['user'])) {
- $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']);
- $replacements['[user:cancel-url]'] = user_cancel_url($data['user']);
- }
-}
-
-/*** Administrative features ***********************************************/
-
-/**
- * Retrieve an array of roles matching specified conditions.
- *
- * @param $membersonly
- * Set this to TRUE to exclude the 'anonymous' role.
- * @param $permission
- * A string containing a permission. If set, only roles containing that
- * permission are returned.
- *
- * @return
- * An associative array with the role id as the key and the role name as
- * value.
- */
-function user_roles($membersonly = FALSE, $permission = NULL) {
- $query = db_select('role', 'r');
- $query->addTag('translatable');
- $query->fields('r', array('rid', 'name'));
- $query->orderBy('weight');
- $query->orderBy('name');
- if (!empty($permission)) {
- $query->innerJoin('role_permission', 'p', 'r.rid = p.rid');
- $query->condition('p.permission', $permission);
- }
- $result = $query->execute();
-
- $roles = array();
- foreach ($result as $role) {
- switch ($role->rid) {
- // We only translate the built in role names
- case DRUPAL_ANONYMOUS_RID:
- if (!$membersonly) {
- $roles[$role->rid] = t($role->name);
- }
- break;
- case DRUPAL_AUTHENTICATED_RID:
- $roles[$role->rid] = t($role->name);
- break;
- default:
- $roles[$role->rid] = $role->name;
- }
- }
-
- return $roles;
-}
-
-/**
- * Fetches a user role by role ID.
- *
- * @param $rid
- * An integer representing the role ID.
- *
- * @return
- * A fully-loaded role object if a role with the given ID exists, or FALSE
- * otherwise.
- *
- * @see user_role_load_by_name()
- */
-function user_role_load($rid) {
- return db_select('role', 'r')
- ->fields('r')
- ->condition('rid', $rid)
- ->execute()
- ->fetchObject();
-}
-
-/**
- * Fetches a user role by role name.
- *
- * @param $role_name
- * A string representing the role name.
- *
- * @return
- * A fully-loaded role object if a role with the given name exists, or FALSE
- * otherwise.
- *
- * @see user_role_load()
- */
-function user_role_load_by_name($role_name) {
- return db_select('role', 'r')
- ->fields('r')
- ->condition('name', $role_name)
- ->execute()
- ->fetchObject();
-}
-
-/**
- * Save a user role to the database.
- *
- * @param $role
- * A role object to modify or add. If $role->rid is not specified, a new
- * role will be created.
- * @return
- * Status constant indicating if role was created or updated.
- * Failure to write the user role record will return FALSE. Otherwise.
- * SAVED_NEW or SAVED_UPDATED is returned depending on the operation
- * performed.
- */
-function user_role_save($role) {
- if ($role->name) {
- // Prevent leading and trailing spaces in role names.
- $role->name = trim($role->name);
- }
- if (!isset($role->weight)) {
- // Set a role weight to make this new role last.
- $query = db_select('role');
- $query->addExpression('MAX(weight)');
- $role->weight = $query->execute()->fetchField() + 1;
- }
-
- // Let modules modify the user role before it is saved to the database.
- module_invoke_all('user_role_presave', $role);
-
- if (!empty($role->rid) && $role->name) {
- $status = drupal_write_record('role', $role, 'rid');
- module_invoke_all('user_role_update', $role);
- }
- else {
- $status = drupal_write_record('role', $role);
- module_invoke_all('user_role_insert', $role);
- }
-
- // Clear the user access cache.
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
-
- return $status;
-}
-
-/**
- * Delete a user role from database.
- *
- * @param $role
- * A string with the role name, or an integer with the role ID.
- */
-function user_role_delete($role) {
- if (is_int($role)) {
- $role = user_role_load($role);
- }
- else {
- $role = user_role_load_by_name($role);
- }
-
- db_delete('role')
- ->condition('rid', $role->rid)
- ->execute();
- db_delete('role_permission')
- ->condition('rid', $role->rid)
- ->execute();
- // Update the users who have this role set:
- db_delete('users_roles')
- ->condition('rid', $role->rid)
- ->execute();
-
- module_invoke_all('user_role_delete', $role);
-
- // Clear the user access cache.
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
-}
-
-/**
- * Menu access callback for user role editing.
- */
-function user_role_edit_access($role) {
- // Prevent the system-defined roles from being altered or removed.
- if ($role->rid == DRUPAL_ANONYMOUS_RID || $role->rid == DRUPAL_AUTHENTICATED_RID) {
- return FALSE;
- }
-
- return user_access('administer permissions');
-}
-
-/**
- * Determine the modules that permissions belong to.
- *
- * @return
- * An associative array in the format $permission => $module.
- */
-function user_permission_get_modules() {
- $permissions = array();
- foreach (module_implements('permission') as $module) {
- $perms = module_invoke($module, 'permission');
- foreach ($perms as $key => $value) {
- $permissions[$key] = $module;
- }
- }
- return $permissions;
-}
-
-/**
- * Change permissions for a user role.
- *
- * This function may be used to grant and revoke multiple permissions at once.
- * For example, when a form exposes checkboxes to configure permissions for a
- * role, the form submit handler may directly pass the submitted values for the
- * checkboxes form element to this function.
- *
- * @param $rid
- * The ID of a user role to alter.
- * @param $permissions
- * An associative array, where the key holds the permission name and the value
- * determines whether to grant or revoke that permission. Any value that
- * evaluates to TRUE will cause the permission to be granted. Any value that
- * evaluates to FALSE will cause the permission to be revoked.
- * @code
- * array(
- * 'administer nodes' => 0, // Revoke 'administer nodes'
- * 'administer blocks' => FALSE, // Revoke 'administer blocks'
- * 'access user profiles' => 1, // Grant 'access user profiles'
- * 'access content' => TRUE, // Grant 'access content'
- * 'access comments' => 'access comments', // Grant 'access comments'
- * )
- * @endcode
- * Existing permissions are not changed, unless specified in $permissions.
- *
- * @see user_role_grant_permissions()
- * @see user_role_revoke_permissions()
- */
-function user_role_change_permissions($rid, array $permissions = array()) {
- // Grant new permissions for the role.
- $grant = array_filter($permissions);
- if (!empty($grant)) {
- user_role_grant_permissions($rid, array_keys($grant));
- }
- // Revoke permissions for the role.
- $revoke = array_diff_assoc($permissions, $grant);
- if (!empty($revoke)) {
- user_role_revoke_permissions($rid, array_keys($revoke));
- }
-}
-
-/**
- * Grant permissions to a user role.
- *
- * @param $rid
- * The ID of a user role to alter.
- * @param $permissions
- * A list of permission names to grant.
- *
- * @see user_role_change_permissions()
- * @see user_role_revoke_permissions()
- */
-function user_role_grant_permissions($rid, array $permissions = array()) {
- $modules = user_permission_get_modules();
- // Grant new permissions for the role.
- foreach ($permissions as $name) {
- db_merge('role_permission')
- ->key(array(
- 'rid' => $rid,
- 'permission' => $name,
- ))
- ->fields(array(
- 'module' => $modules[$name],
- ))
- ->execute();
- }
-
- // Clear the user access cache.
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
-}
-
-/**
- * Revoke permissions from a user role.
- *
- * @param $rid
- * The ID of a user role to alter.
- * @param $permissions
- * A list of permission names to revoke.
- *
- * @see user_role_change_permissions()
- * @see user_role_grant_permissions()
- */
-function user_role_revoke_permissions($rid, array $permissions = array()) {
- // Revoke permissions for the role.
- db_delete('role_permission')
- ->condition('rid', $rid)
- ->condition('permission', $permissions, 'IN')
- ->execute();
-
- // Clear the user access cache.
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
-}
-
-/**
- * Implements hook_user_operations().
- */
-function user_user_operations($form = array(), $form_state = array()) {
- $operations = array(
- 'unblock' => array(
- 'label' => t('Unblock the selected users'),
- 'callback' => 'user_user_operations_unblock',
- ),
- 'block' => array(
- 'label' => t('Block the selected users'),
- 'callback' => 'user_user_operations_block',
- ),
- 'cancel' => array(
- 'label' => t('Cancel the selected user accounts'),
- ),
- );
-
- if (user_access('administer permissions')) {
- $roles = user_roles(TRUE);
- unset($roles[DRUPAL_AUTHENTICATED_RID]); // Can't edit authenticated role.
-
- $add_roles = array();
- foreach ($roles as $key => $value) {
- $add_roles['add_role-' . $key] = $value;
- }
-
- $remove_roles = array();
- foreach ($roles as $key => $value) {
- $remove_roles['remove_role-' . $key] = $value;
- }
-
- if (count($roles)) {
- $role_operations = array(
- t('Add a role to the selected users') => array(
- 'label' => $add_roles,
- ),
- t('Remove a role from the selected users') => array(
- 'label' => $remove_roles,
- ),
- );
-
- $operations += $role_operations;
- }
- }
-
- // If the form has been posted, we need to insert the proper data for
- // role editing if necessary.
- if (!empty($form_state['submitted'])) {
- $operation_rid = explode('-', $form_state['values']['operation']);
- $operation = $operation_rid[0];
- if ($operation == 'add_role' || $operation == 'remove_role') {
- $rid = $operation_rid[1];
- if (user_access('administer permissions')) {
- $operations[$form_state['values']['operation']] = array(
- 'callback' => 'user_multiple_role_edit',
- 'callback arguments' => array($operation, $rid),
- );
- }
- else {
- watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
- return;
- }
- }
- }
-
- return $operations;
-}
-
-/**
- * Callback function for admin mass unblocking users.
- */
-function user_user_operations_unblock($accounts) {
- $accounts = user_load_multiple($accounts);
- foreach ($accounts as $account) {
- // Skip unblocking user if they are already unblocked.
- if ($account !== FALSE && $account->status == 0) {
- user_save($account, array('status' => 1));
- }
- }
-}
-
-/**
- * Callback function for admin mass blocking users.
- */
-function user_user_operations_block($accounts) {
- $accounts = user_load_multiple($accounts);
- foreach ($accounts as $account) {
- // Skip blocking user if they are already blocked.
- if ($account !== FALSE && $account->status == 1) {
- // For efficiency manually save the original account before applying any
- // changes.
- $account->original = clone $account;
- user_save($account, array('status' => 0));
- }
- }
-}
-
-/**
- * Callback function for admin mass adding/deleting a user role.
- */
-function user_multiple_role_edit($accounts, $operation, $rid) {
- // The role name is not necessary as user_save() will reload the user
- // object, but some modules' hook_user() may look at this first.
- $role_name = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => $rid))->fetchField();
-
- switch ($operation) {
- case 'add_role':
- $accounts = user_load_multiple($accounts);
- foreach ($accounts as $account) {
- // Skip adding the role to the user if they already have it.
- if ($account !== FALSE && !isset($account->roles[$rid])) {
- $roles = $account->roles + array($rid => $role_name);
- // For efficiency manually save the original account before applying
- // any changes.
- $account->original = clone $account;
- user_save($account, array('roles' => $roles));
- }
- }
- break;
- case 'remove_role':
- $accounts = user_load_multiple($accounts);
- foreach ($accounts as $account) {
- // Skip removing the role from the user if they already don't have it.
- if ($account !== FALSE && isset($account->roles[$rid])) {
- $roles = array_diff($account->roles, array($rid => $role_name));
- // For efficiency manually save the original account before applying
- // any changes.
- $account->original = clone $account;
- user_save($account, array('roles' => $roles));
- }
- }
- break;
- }
-}
-
-function user_multiple_cancel_confirm($form, &$form_state) {
- $edit = $form_state['input'];
-
- $form['accounts'] = array('#prefix' => '
', '#tree' => TRUE);
- $accounts = user_load_multiple(array_keys(array_filter($edit['accounts'])));
- foreach ($accounts as $uid => $account) {
- // Prevent user 1 from being canceled.
- if ($uid <= 1) {
- continue;
- }
- $form['accounts'][$uid] = array(
- '#type' => 'hidden',
- '#value' => $uid,
- '#prefix' => '
',
- '#suffix' => check_plain($account->name) . " \n",
- );
- }
-
- // Output a notice that user 1 cannot be canceled.
- if (isset($accounts[1])) {
- $redirect = (count($accounts) == 1);
- $message = t('The user account %name cannot be cancelled.', array('%name' => $accounts[1]->name));
- drupal_set_message($message, $redirect ? 'error' : 'warning');
- // If only user 1 was selected, redirect to the overview.
- if ($redirect) {
- drupal_goto('admin/people');
- }
- }
-
- $form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
-
- module_load_include('inc', 'user', 'user.pages');
- $form['user_cancel_method'] = array(
- '#type' => 'item',
- '#title' => t('When cancelling these accounts'),
- );
- $form['user_cancel_method'] += user_cancel_methods();
- // Remove method descriptions.
- foreach (element_children($form['user_cancel_method']) as $element) {
- unset($form['user_cancel_method'][$element]['#description']);
- }
-
- // Allow to send the account cancellation confirmation mail.
- $form['user_cancel_confirm'] = array(
- '#type' => 'checkbox',
- '#title' => t('Require e-mail confirmation to cancel account.'),
- '#default_value' => FALSE,
- '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
- );
- // Also allow to send account canceled notification mail, if enabled.
- $form['user_cancel_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is canceled.'),
- '#default_value' => FALSE,
- '#access' => variable_get('user_mail_status_canceled_notify', FALSE),
- '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
- );
-
- return confirm_form($form,
- t('Are you sure you want to cancel these user accounts?'),
- 'admin/people', t('This action cannot be undone.'),
- t('Cancel accounts'), t('Cancel'));
-}
-
-/**
- * Submit handler for mass-account cancellation form.
- *
- * @see user_multiple_cancel_confirm()
- * @see user_cancel_confirm_form_submit()
- */
-function user_multiple_cancel_confirm_submit($form, &$form_state) {
- global $user;
-
- if ($form_state['values']['confirm']) {
- foreach ($form_state['values']['accounts'] as $uid => $value) {
- // Prevent programmatic form submissions from cancelling user 1.
- if ($uid <= 1) {
- continue;
- }
- // Prevent user administrators from deleting themselves without confirmation.
- if ($uid == $user->uid) {
- $admin_form_state = $form_state;
- unset($admin_form_state['values']['user_cancel_confirm']);
- $admin_form_state['values']['_account'] = $user;
- user_cancel_confirm_form_submit(array(), $admin_form_state);
- }
- else {
- user_cancel($form_state['values'], $uid, $form_state['values']['user_cancel_method']);
- }
- }
- }
- $form_state['redirect'] = 'admin/people';
-}
-
-/**
- * Retrieve a list of all user setting/information categories and sort them by weight.
- */
-function _user_categories() {
- $categories = module_invoke_all('user_categories');
- usort($categories, '_user_sort');
-
- return $categories;
-}
-
-function _user_sort($a, $b) {
- $a = (array) $a + array('weight' => 0, 'title' => '');
- $b = (array) $b + array('weight' => 0, 'title' => '');
- return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
-}
-
-/**
- * List user administration filters that can be applied.
- */
-function user_filters() {
- // Regular filters
- $filters = array();
- $roles = user_roles(TRUE);
- unset($roles[DRUPAL_AUTHENTICATED_RID]); // Don't list authorized role.
- if (count($roles)) {
- $filters['role'] = array(
- 'title' => t('role'),
- 'field' => 'ur.rid',
- 'options' => array(
- '[any]' => t('any'),
- ) + $roles,
- );
- }
-
- $options = array();
- foreach (module_implements('permission') as $module) {
- $function = $module . '_permission';
- if ($permissions = $function()) {
- asort($permissions);
- foreach ($permissions as $permission => $description) {
- $options[t('@module module', array('@module' => $module))][$permission] = t($permission);
- }
- }
- }
- ksort($options);
- $filters['permission'] = array(
- 'title' => t('permission'),
- 'options' => array(
- '[any]' => t('any'),
- ) + $options,
- );
-
- $filters['status'] = array(
- 'title' => t('status'),
- 'field' => 'u.status',
- 'options' => array(
- '[any]' => t('any'),
- 1 => t('active'),
- 0 => t('blocked'),
- ),
- );
- return $filters;
-}
-
-/**
- * Extends a query object for user administration filters based on session.
- *
- * @param $query
- * Query object that should be filtered.
- */
-function user_build_filter_query(SelectQuery $query) {
- $filters = user_filters();
- // Extend Query with filter conditions.
- foreach (isset($_SESSION['user_overview_filter']) ? $_SESSION['user_overview_filter'] : array() as $filter) {
- list($key, $value) = $filter;
- // This checks to see if this permission filter is an enabled permission for
- // the authenticated role. If so, then all users would be listed, and we can
- // skip adding it to the filter query.
- if ($key == 'permission') {
- $account = new stdClass();
- $account->uid = 'user_filter';
- $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
- if (user_access($value, $account)) {
- continue;
- }
- $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
- $permission_alias = $query->join('role_permission', 'p', $users_roles_alias . '.rid = %alias.rid');
- $query->condition($permission_alias . '.permission', $value);
- }
- elseif ($key == 'role') {
- $users_roles_alias = $query->join('users_roles', 'ur', '%alias.uid = u.uid');
- $query->condition($users_roles_alias . '.rid' , $value);
- }
- else {
- $query->condition($filters[$key]['field'], $value);
- }
- }
-}
-
-/**
- * Implements hook_comment_view().
- */
-function user_comment_view($comment) {
- if (variable_get('user_signatures', 0) && !empty($comment->signature)) {
- // @todo This alters and replaces the original object value, so a
- // hypothetical process of loading, viewing, and saving will hijack the
- // stored data. Consider renaming to $comment->signature_safe or similar
- // here and elsewhere in Drupal 8.
- $comment->signature = check_markup($comment->signature, $comment->signature_format, '', TRUE);
- }
- else {
- $comment->signature = '';
- }
-}
-
-/**
- * Returns HTML for a user signature.
- *
- * @param $variables
- * An associative array containing:
- * - signature: The user's signature.
- *
- * @ingroup themeable
- */
-function theme_user_signature($variables) {
- $signature = $variables['signature'];
- $output = '';
-
- if ($signature) {
- $output .= '
';
- $output .= '
—
';
- $output .= $signature;
- $output .= '
';
- }
-
- return $output;
-}
-
-/**
- * Get the language object preferred by the user. This user preference can
- * be set on the user account editing page, and is only available if there
- * are more than one languages enabled on the site. If the user did not
- * choose a preferred language, or is the anonymous user, the $default
- * value, or if it is not set, the site default language will be returned.
- *
- * @param $account
- * User account to look up language for.
- * @param $default
- * Optional default language object to return if the account
- * has no valid language.
- */
-function user_preferred_language($account, $default = NULL) {
- $language_list = language_list();
- if (!empty($account->language) && isset($language_list[$account->language])) {
- return $language_list[$account->language];
- }
- else {
- return $default ? $default : language_default();
- }
-}
-
-/**
- * Conditionally create and send a notification email when a certain
- * operation happens on the given user account.
- *
- * @see user_mail_tokens()
- * @see drupal_mail()
- *
- * @param $op
- * The operation being performed on the account. Possible values:
- * - 'register_admin_created': Welcome message for user created by the admin.
- * - 'register_no_approval_required': Welcome message when user
- * self-registers.
- * - 'register_pending_approval': Welcome message, user pending admin
- * approval.
- * - 'password_reset': Password recovery request.
- * - 'status_activated': Account activated.
- * - 'status_blocked': Account blocked.
- * - 'cancel_confirm': Account cancellation request.
- * - 'status_canceled': Account canceled.
- *
- * @param $account
- * The user object of the account being notified. Must contain at
- * least the fields 'uid', 'name', and 'mail'.
- * @param $language
- * Optional language to use for the notification, overriding account language.
- *
- * @return
- * The return value from drupal_mail_system()->mail(), if ends up being
- * called.
- */
-function _user_mail_notify($op, $account, $language = NULL) {
- // By default, we always notify except for canceled and blocked.
- $default_notify = ($op != 'status_canceled' && $op != 'status_blocked');
- $notify = variable_get('user_mail_' . $op . '_notify', $default_notify);
- if ($notify) {
- $params['account'] = $account;
- $language = $language ? $language : user_preferred_language($account);
- $mail = drupal_mail('user', $op, $account->mail, $language, $params);
- if ($op == 'register_pending_approval') {
- // If a user registered requiring admin approval, notify the admin, too.
- // We use the site default language for this.
- drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params);
- }
- }
- return empty($mail) ? NULL : $mail['result'];
-}
-
-/**
- * Form element process handler for client-side password validation.
- *
- * This #process handler is automatically invoked for 'password_confirm' form
- * elements to add the JavaScript and string translations for dynamic password
- * validation.
- *
- * @see system_element_info()
- */
-function user_form_process_password_confirm($element) {
- global $user;
-
- $js_settings = array(
- 'password' => array(
- 'strengthTitle' => t('Password strength:'),
- 'hasWeaknesses' => t('To make your password stronger:'),
- 'tooShort' => t('Make it at least 6 characters'),
- 'addLowerCase' => t('Add lowercase letters'),
- 'addUpperCase' => t('Add uppercase letters'),
- 'addNumbers' => t('Add numbers'),
- 'addPunctuation' => t('Add punctuation'),
- 'sameAsUsername' => t('Make it different from your username'),
- 'confirmSuccess' => t('yes'),
- 'confirmFailure' => t('no'),
- 'weak' => t('Weak'),
- 'fair' => t('Fair'),
- 'good' => t('Good'),
- 'strong' => t('Strong'),
- 'confirmTitle' => t('Passwords match:'),
- 'username' => (isset($user->name) ? $user->name : ''),
- ),
- );
-
- $element['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.js';
- // Ensure settings are only added once per page.
- static $already_added = FALSE;
- if (!$already_added) {
- $already_added = TRUE;
- $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
- }
-
- return $element;
-}
-
-/**
- * Implements hook_node_load().
- */
-function user_node_load($nodes, $types) {
- // Build an array of all uids for node authors, keyed by nid.
- $uids = array();
- foreach ($nodes as $nid => $node) {
- $uids[$nid] = $node->uid;
- }
-
- // Fetch name, picture, and data for these users.
- $user_fields = db_query("SELECT uid, name, picture, data FROM {users} WHERE uid IN (:uids)", array(':uids' => $uids))->fetchAllAssoc('uid');
-
- // Add these values back into the node objects.
- foreach ($uids as $nid => $uid) {
- $nodes[$nid]->name = $user_fields[$uid]->name;
- $nodes[$nid]->picture = $user_fields[$uid]->picture;
- $nodes[$nid]->data = $user_fields[$uid]->data;
- }
-}
-
-/**
- * Implements hook_image_style_delete().
- */
-function user_image_style_delete($style) {
- // If a style is deleted, update the variables.
- // Administrators choose a replacement style when deleting.
- user_image_style_save($style);
-}
-
-/**
- * Implements hook_image_style_save().
- */
-function user_image_style_save($style) {
- // If a style is renamed, update the variables that use it.
- if (isset($style['old_name']) && $style['old_name'] == variable_get('user_picture_style', '')) {
- variable_set('user_picture_style', $style['name']);
- }
-}
-
-/**
- * Implements hook_action_info().
- */
-function user_action_info() {
- return array(
- 'user_block_user_action' => array(
- 'label' => t('Block current user'),
- 'type' => 'user',
- 'configurable' => FALSE,
- 'triggers' => array('any'),
- ),
- );
-}
-
-/**
- * Blocks a specific user or the current user, if one is not specified.
- *
- * @param $entity
- * (optional) An entity object; if it is provided and it has a uid property,
- * the user with that ID is blocked.
- * @param $context
- * (optional) An associative array; if no user ID is found in $entity, the
- * 'uid' element of this array determines the user to block.
- *
- * @ingroup actions
- */
-function user_block_user_action(&$entity, $context = array()) {
- // First priority: If there is a $entity->uid, block that user.
- // This is most likely a user object or the author if a node or comment.
- if (isset($entity->uid)) {
- $uid = $entity->uid;
- }
- elseif (isset($context['uid'])) {
- $uid = $context['uid'];
- }
- // If neither of those are valid, then block the current user.
- else {
- $uid = $GLOBALS['user']->uid;
- }
- $account = user_load($uid);
- $account = user_save($account, array('status' => 0));
- watchdog('action', 'Blocked user %name.', array('%name' => $account->name));
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Add a checkbox for the 'user_register_form' instance settings on the 'Edit
- * field instance' form.
- */
-function user_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
- $instance = $form['#instance'];
-
- if ($instance['entity_type'] == 'user' && !$form['#field']['locked']) {
- $form['instance']['settings']['user_register_form'] = array(
- '#type' => 'checkbox',
- '#title' => t('Display on user registration form.'),
- '#description' => t("This is compulsory for 'required' fields."),
- // Field instances created in D7 beta releases before the setting was
- // introduced might be set as 'required' and 'not shown on user_register
- // form'. We make sure the checkbox comes as 'checked' for those.
- '#default_value' => $instance['settings']['user_register_form'] || $instance['required'],
- // Display just below the 'required' checkbox.
- '#weight' => $form['instance']['required']['#weight'] + .1,
- // Disabled when the 'required' checkbox is checked.
- '#states' => array(
- 'enabled' => array('input[name="instance[required]"]' => array('checked' => FALSE)),
- ),
- // Checked when the 'required' checkbox is checked. This is done through
- // a custom behavior, since the #states system would also synchronize on
- // uncheck.
- '#attached' => array(
- 'js' => array(drupal_get_path('module', 'user') . '/user.js'),
- ),
- );
-
- array_unshift($form['#submit'], 'user_form_field_ui_field_edit_form_submit');
- }
-}
-
-/**
- * Additional submit handler for the 'Edit field instance' form.
- *
- * Make sure the 'user_register_form' setting is set for required fields.
- */
-function user_form_field_ui_field_edit_form_submit($form, &$form_state) {
- $instance = $form_state['values']['instance'];
-
- if (!empty($instance['required'])) {
- form_set_value($form['instance']['settings']['user_register_form'], 1, $form_state);
- }
-}
-
-/**
- * Form builder; the user registration form.
- *
- * @ingroup forms
- * @see user_account_form()
- * @see user_account_form_validate()
- * @see user_register_submit()
- */
-function user_register_form($form, &$form_state) {
- global $user;
-
- $admin = user_access('administer users');
-
- // Pass access information to the submit handler. Running an access check
- // inside the submit function interferes with form processing and breaks
- // hook_form_alter().
- $form['administer_users'] = array(
- '#type' => 'value',
- '#value' => $admin,
- );
-
- // If we aren't admin but already logged on, go to the user page instead.
- if (!$admin && $user->uid) {
- drupal_goto('user/' . $user->uid);
- }
-
- $form['#user'] = drupal_anonymous_user();
- $form['#user_category'] = 'register';
-
- $form['#attached']['library'][] = array('system', 'jquery.cookie');
- $form['#attributes']['class'][] = 'user-info-from-cookie';
-
- // Start with the default user account fields.
- user_account_form($form, $form_state);
-
- // Attach field widgets, and hide the ones where the 'user_register_form'
- // setting is not on.
- $langcode = entity_language('user', $form['#user']);
- field_attach_form('user', $form['#user'], $form, $form_state, $langcode);
- foreach (field_info_instances('user', 'user') as $field_name => $instance) {
- if (empty($instance['settings']['user_register_form'])) {
- $form[$field_name]['#access'] = FALSE;
- }
- }
-
- if ($admin) {
- // Redirect back to page which initiated the create request;
- // usually admin/people/create.
- $form_state['redirect'] = $_GET['q'];
- }
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Create new account'),
- );
-
- $form['#validate'][] = 'user_register_validate';
- // Add the final user registration form submit handler.
- $form['#submit'][] = 'user_register_submit';
-
- return $form;
-}
-
-/**
- * Validation function for the user registration form.
- */
-function user_register_validate($form, &$form_state) {
- entity_form_field_validate('user', $form, $form_state);
-}
-
-/**
- * Submit handler for the user registration form.
- *
- * This function is shared by the installation form and the normal registration form,
- * which is why it can't be in the user.pages.inc file.
- *
- * @see user_register_form()
- */
-function user_register_submit($form, &$form_state) {
- $admin = $form_state['values']['administer_users'];
-
- if (!variable_get('user_email_verification', TRUE) || $admin) {
- $pass = $form_state['values']['pass'];
- }
- else {
- $pass = user_password();
- }
- $notify = !empty($form_state['values']['notify']);
-
- // Remove unneeded values.
- form_state_values_clean($form_state);
-
- $form_state['values']['pass'] = $pass;
- $form_state['values']['init'] = $form_state['values']['mail'];
-
- $account = $form['#user'];
-
- entity_form_submit_build_entity('user', $account, $form, $form_state);
-
- // Populate $edit with the properties of $account, which have been edited on
- // this form by taking over all values, which appear in the form values too.
- $edit = array_intersect_key((array) $account, $form_state['values']);
- $account = user_save($account, $edit);
-
- // Terminate if an error occurred during user_save().
- if (!$account) {
- drupal_set_message(t("Error saving user account."), 'error');
- $form_state['redirect'] = '';
- return;
- }
- $form_state['user'] = $account;
- $form_state['values']['uid'] = $account->uid;
-
- watchdog('user', 'New user: %name (%email).', array('%name' => $form_state['values']['name'], '%email' => $form_state['values']['mail']), WATCHDOG_NOTICE, l(t('edit'), 'user/' . $account->uid . '/edit'));
-
- // Add plain text password into user account to generate mail tokens.
- $account->password = $pass;
-
- // New administrative account without notification.
- $uri = entity_uri('user', $account);
- if ($admin && !$notify) {
- drupal_set_message(t('Created a new user account for
%name . No e-mail has been sent.', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
- }
- // No e-mail verification required; log in user immediately.
- elseif (!$admin && !variable_get('user_email_verification', TRUE) && $account->status) {
- _user_mail_notify('register_no_approval_required', $account);
- $form_state['uid'] = $account->uid;
- user_login_submit(array(), $form_state);
- drupal_set_message(t('Registration successful. You are now logged in.'));
- $form_state['redirect'] = '';
- }
- // No administrator approval required.
- elseif ($account->status || $notify) {
- $op = $notify ? 'register_admin_created' : 'register_no_approval_required';
- _user_mail_notify($op, $account);
- if ($notify) {
- drupal_set_message(t('A welcome message with further instructions has been e-mailed to the new user
%name .', array('@url' => url($uri['path'], $uri['options']), '%name' => $account->name)));
- }
- else {
- drupal_set_message(t('A welcome message with further instructions has been sent to your e-mail address.'));
- $form_state['redirect'] = '';
- }
- }
- // Administrator approval required.
- else {
- _user_mail_notify('register_pending_approval', $account);
- drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.
In the meantime, a welcome message with further instructions has been sent to your e-mail address.'));
- $form_state['redirect'] = '';
- }
-}
-
-/**
- * Implements hook_modules_installed().
- */
-function user_modules_installed($modules) {
- // Assign all available permissions to the administrator role.
- $rid = variable_get('user_admin_role', 0);
- if ($rid) {
- $permissions = array();
- foreach ($modules as $module) {
- if ($module_permissions = module_invoke($module, 'permission')) {
- $permissions = array_merge($permissions, array_keys($module_permissions));
- }
- }
- if (!empty($permissions)) {
- user_role_grant_permissions($rid, $permissions);
- }
- }
-}
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function user_modules_uninstalled($modules) {
- db_delete('role_permission')
- ->condition('module', $modules, 'IN')
- ->execute();
-}
-
-/**
- * Helper function to rewrite the destination to avoid redirecting to login page after login.
- *
- * Third-party authentication modules may use this function to determine the
- * proper destination after a user has been properly logged in.
- */
-function user_login_destination() {
- $destination = drupal_get_destination();
- if ($destination['destination'] == 'user/login') {
- $destination['destination'] = 'user';
- }
- return $destination;
-}
-
-/**
- * Saves visitor information as a cookie so it can be reused.
- *
- * @param $values
- * An array of key/value pairs to be saved into a cookie.
- */
-function user_cookie_save(array $values) {
- foreach ($values as $field => $value) {
- // Set cookie for 365 days.
- setrawcookie('Drupal.visitor.' . $field, rawurlencode($value), REQUEST_TIME + 31536000, '/');
- }
-}
-
-/**
- * Delete a visitor information cookie.
- *
- * @param $cookie_name
- * A cookie name such as 'homepage'.
- */
-function user_cookie_delete($cookie_name) {
- setrawcookie('Drupal.visitor.' . $cookie_name, '', REQUEST_TIME - 3600, '/');
-}
-
-/**
- * Implements hook_rdf_mapping().
- */
-function user_rdf_mapping() {
- return array(
- array(
- 'type' => 'user',
- 'bundle' => RDF_DEFAULT_BUNDLE,
- 'mapping' => array(
- 'rdftype' => array('sioc:UserAccount'),
- 'name' => array(
- 'predicates' => array('foaf:name'),
- ),
- 'homepage' => array(
- 'predicates' => array('foaf:page'),
- 'type' => 'rel',
- ),
- ),
- ),
- );
-}
-
-/**
- * Implements hook_file_download_access().
- */
-function user_file_download_access($field, $entity_type, $entity) {
- if ($entity_type == 'user') {
- return user_view_access($entity);
- }
-}
-
-/**
- * Implements hook_system_info_alter().
- *
- * Drupal 7 ships with two methods to add additional fields to users: Profile
- * module, a legacy module dating back from 2002, and Field API integration
- * with users. While Field API support for users currently provides less end
- * user features, the inefficient data storage mechanism of Profile module, as
- * well as its lack of consistency with the rest of the entity / field based
- * systems in Drupal 7, make this a sub-optimal solution to those who were not
- * using it in previous releases of Drupal.
- *
- * To prevent new Drupal 7 sites from installing Profile module, and
- * unwittingly ending up with two completely different and incompatible methods
- * of extending users, only make the Profile module available if the profile_*
- * tables are present.
- *
- * @todo: Remove in D8, pending upgrade path.
- */
-function user_system_info_alter(&$info, $file, $type) {
- if ($type == 'module' && $file->name == 'profile' && db_table_exists('profile_field')) {
- $info['hidden'] = FALSE;
- }
-}
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
deleted file mode 100644
index 7d40663e..00000000
--- a/modules/user/user.pages.inc
+++ /dev/null
@@ -1,562 +0,0 @@
-fields('users', array('name'))->condition('name', db_like($string) . '%', 'LIKE')->range(0, 10)->execute();
- foreach ($result as $user) {
- $matches[$user->name] = check_plain($user->name);
- }
- }
-
- drupal_json_output($matches);
-}
-
-/**
- * Form builder; Request a password reset.
- *
- * @ingroup forms
- * @see user_pass_validate()
- * @see user_pass_submit()
- */
-function user_pass() {
- global $user;
-
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Username or e-mail address'),
- '#size' => 60,
- '#maxlength' => max(USERNAME_MAX_LENGTH, EMAIL_MAX_LENGTH),
- '#required' => TRUE,
- '#default_value' => isset($_GET['name']) ? $_GET['name'] : '',
- );
- // Allow logged in users to request this also.
- if ($user->uid > 0) {
- $form['name']['#type'] = 'value';
- $form['name']['#value'] = $user->mail;
- $form['mail'] = array(
- '#prefix' => '
',
- '#markup' => t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)),
- '#suffix' => '
',
- );
- }
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('E-mail new password'));
-
- return $form;
-}
-
-function user_pass_validate($form, &$form_state) {
- $name = trim($form_state['values']['name']);
- // Try to load by email.
- $users = user_load_multiple(array(), array('mail' => $name, 'status' => '1'));
- $account = reset($users);
- if (!$account) {
- // No success, try to load by name.
- $users = user_load_multiple(array(), array('name' => $name, 'status' => '1'));
- $account = reset($users);
- }
- if (isset($account->uid)) {
- form_set_value(array('#parents' => array('account')), $account, $form_state);
- }
- else {
- form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name)));
- }
-}
-
-function user_pass_submit($form, &$form_state) {
- global $language;
-
- $account = $form_state['values']['account'];
- // Mail one time login URL and instructions using current language.
- $mail = _user_mail_notify('password_reset', $account, $language);
- if (!empty($mail)) {
- watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
- drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
- }
-
- $form_state['redirect'] = 'user';
- return;
-}
-
-/**
- * Menu callback; process one time login link and redirects to the user page on success.
- */
-function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $action = NULL) {
- global $user;
-
- // When processing the one-time login link, we have to make sure that a user
- // isn't already logged in.
- if ($user->uid) {
- // The existing user is already logged in.
- if ($user->uid == $uid) {
- drupal_set_message(t('You are logged in as %user.
Change your password. ', array('%user' => $user->name, '!user_edit' => url("user/$user->uid/edit"))));
- }
- // A different user is already logged in on the computer.
- else {
- $reset_link_account = user_load($uid);
- if (!empty($reset_link_account)) {
- drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please
logout and try using the link again.',
- array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))));
- } else {
- // Invalid one-time link specifies an unknown user.
- drupal_set_message(t('The one-time login link you clicked is invalid.'));
- }
- }
- drupal_goto();
- }
- else {
- // Time out, in seconds, until login URL expires. Defaults to 24 hours =
- // 86400 seconds.
- $timeout = variable_get('user_password_reset_timeout', 86400);
- $current = REQUEST_TIME;
- // Some redundant checks for extra security ?
- $users = user_load_multiple(array($uid), array('status' => '1'));
- if ($timestamp <= $current && $account = reset($users)) {
- // No time out for first time login.
- if ($account->login && $current - $timestamp > $timeout) {
- drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
- drupal_goto('user/password');
- }
- elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
- // First stage is a confirmation form, then login
- if ($action == 'login') {
- // Set the new user.
- $user = $account;
- // user_login_finalize() also updates the login timestamp of the
- // user, which invalidates further use of the one-time login link.
- user_login_finalize();
- watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
- drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
- // Let the user's password be changed without the current password check.
- $token = drupal_random_key();
- $_SESSION['pass_reset_' . $user->uid] = $token;
- drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
- }
- else {
- $form['message'] = array('#markup' => t('
This is a one-time login for %user_name and will expire on %expiration_date.
Click on this button to log in to the site and change your password.
', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
- $form['help'] = array('#markup' => '
' . t('This login can be used only once.') . '
');
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
- $form['#action'] = url("user/reset/$uid/$timestamp/$hashed_pass/login");
- return $form;
- }
- }
- else {
- drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
- drupal_goto('user/password');
- }
- }
- else {
- // Deny access, no more clues.
- // Everything will be in the watchdog's URL for the administrator to check.
- drupal_access_denied();
- drupal_exit();
- }
- }
-}
-
-/**
- * Menu callback; logs the current user out, and redirects to the home page.
- */
-function user_logout() {
- global $user;
-
- watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
-
- module_invoke_all('user_logout', $user);
-
- // Destroy the current session, and reset $user to the anonymous user.
- session_destroy();
-
- drupal_goto();
-}
-
-/**
- * Process variables for user-profile.tpl.php.
- *
- * The $variables array contains the following arguments:
- * - $account
- *
- * @see user-profile.tpl.php
- */
-function template_preprocess_user_profile(&$variables) {
- $account = $variables['elements']['#account'];
-
- // Helpful $user_profile variable for templates.
- foreach (element_children($variables['elements']) as $key) {
- $variables['user_profile'][$key] = $variables['elements'][$key];
- }
-
- // Preprocess fields.
- field_attach_preprocess('user', $account, $variables['elements'], $variables);
-}
-
-/**
- * Process variables for user-profile-item.tpl.php.
- *
- * The $variables array contains the following arguments:
- * - $element
- *
- * @see user-profile-item.tpl.php
- */
-function template_preprocess_user_profile_item(&$variables) {
- $variables['title'] = $variables['element']['#title'];
- $variables['value'] = $variables['element']['#markup'];
- $variables['attributes'] = '';
- if (isset($variables['element']['#attributes'])) {
- $variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
- }
-}
-
-/**
- * Process variables for user-profile-category.tpl.php.
- *
- * The $variables array contains the following arguments:
- * - $element
- *
- * @see user-profile-category.tpl.php
- */
-function template_preprocess_user_profile_category(&$variables) {
- $variables['title'] = check_plain($variables['element']['#title']);
- $variables['profile_items'] = $variables['element']['#children'];
- $variables['attributes'] = '';
- if (isset($variables['element']['#attributes'])) {
- $variables['attributes'] = drupal_attributes($variables['element']['#attributes']);
- }
-}
-
-/**
- * Form builder; edit a user account or one of their profile categories.
- *
- * @ingroup forms
- * @see user_account_form()
- * @see user_account_form_validate()
- * @see user_profile_form_validate()
- * @see user_profile_form_submit()
- * @see user_cancel_confirm_form_submit()
- */
-function user_profile_form($form, &$form_state, $account, $category = 'account') {
- global $user;
-
- // During initial form build, add the entity to the form state for use during
- // form building and processing. During a rebuild, use what is in the form
- // state.
- if (!isset($form_state['user'])) {
- $form_state['user'] = $account;
- }
- else {
- $account = $form_state['user'];
- }
-
- // @todo Legacy support. Modules are encouraged to access the entity using
- // $form_state. Remove in Drupal 8.
- $form['#user'] = $account;
- $form['#user_category'] = $category;
-
- if ($category == 'account') {
- user_account_form($form, $form_state);
- // Attach field widgets.
- $langcode = entity_language('user', $account);
- field_attach_form('user', $account, $form, $form_state, $langcode);
- }
-
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- );
- if ($category == 'account') {
- $form['actions']['cancel'] = array(
- '#type' => 'submit',
- '#value' => t('Cancel account'),
- '#submit' => array('user_edit_cancel_submit'),
- '#access' => $account->uid > 1 && (($account->uid == $user->uid && user_access('cancel account')) || user_access('administer users')),
- );
- }
-
- $form['#validate'][] = 'user_profile_form_validate';
- // Add the final user profile form submit handler.
- $form['#submit'][] = 'user_profile_form_submit';
-
- return $form;
-}
-
-/**
- * Validation function for the user account and profile editing form.
- */
-function user_profile_form_validate($form, &$form_state) {
- entity_form_field_validate('user', $form, $form_state);
-}
-
-/**
- * Submit function for the user account and profile editing form.
- */
-function user_profile_form_submit($form, &$form_state) {
- $account = $form_state['user'];
- $category = $form['#user_category'];
- // Remove unneeded values.
- form_state_values_clean($form_state);
-
- // Before updating the account entity, keep an unchanged copy for use with
- // user_save() later. This is necessary for modules implementing the user
- // hooks to be able to react on changes by comparing the values of $account
- // and $edit.
- $account_unchanged = clone $account;
-
- entity_form_submit_build_entity('user', $account, $form, $form_state);
-
- // Populate $edit with the properties of $account, which have been edited on
- // this form by taking over all values, which appear in the form values too.
- $edit = array_intersect_key((array) $account, $form_state['values']);
-
- user_save($account_unchanged, $edit, $category);
- $form_state['values']['uid'] = $account->uid;
-
- if ($category == 'account' && !empty($edit['pass'])) {
- // Remove the password reset tag since a new password was saved.
- unset($_SESSION['pass_reset_'. $account->uid]);
- }
- // Clear the page cache because pages can contain usernames and/or profile information:
- cache_clear_all();
-
- drupal_set_message(t('The changes have been saved.'));
-}
-
-/**
- * Submit function for the 'Cancel account' button on the user edit form.
- */
-function user_edit_cancel_submit($form, &$form_state) {
- $destination = array();
- if (isset($_GET['destination'])) {
- $destination = drupal_get_destination();
- unset($_GET['destination']);
- }
- // Note: We redirect from user/uid/edit to user/uid/cancel to make the tabs disappear.
- $form_state['redirect'] = array("user/" . $form['#user']->uid . "/cancel", array('query' => $destination));
-}
-
-/**
- * Form builder; confirm form for cancelling user account.
- *
- * @ingroup forms
- * @see user_edit_cancel_submit()
- */
-function user_cancel_confirm_form($form, &$form_state, $account) {
- global $user;
-
- $form['_account'] = array('#type' => 'value', '#value' => $account);
-
- // Display account cancellation method selection, if allowed.
- $default_method = variable_get('user_cancel_method', 'user_cancel_block');
- $admin_access = user_access('administer users');
- $can_select_method = $admin_access || user_access('select account cancellation method');
- $form['user_cancel_method'] = array(
- '#type' => 'item',
- '#title' => ($account->uid == $user->uid ? t('When cancelling your account') : t('When cancelling the account')),
- '#access' => $can_select_method,
- );
- $form['user_cancel_method'] += user_cancel_methods();
-
- // Allow user administrators to skip the account cancellation confirmation
- // mail (by default), as long as they do not attempt to cancel their own
- // account.
- $override_access = $admin_access && ($account->uid != $user->uid);
- $form['user_cancel_confirm'] = array(
- '#type' => 'checkbox',
- '#title' => t('Require e-mail confirmation to cancel account.'),
- '#default_value' => ($override_access ? FALSE : TRUE),
- '#access' => $override_access,
- '#description' => t('When enabled, the user must confirm the account cancellation via e-mail.'),
- );
- // Also allow to send account canceled notification mail, if enabled.
- $default_notify = variable_get('user_mail_status_canceled_notify', FALSE);
- $form['user_cancel_notify'] = array(
- '#type' => 'checkbox',
- '#title' => t('Notify user when account is canceled.'),
- '#default_value' => ($override_access ? FALSE : $default_notify),
- '#access' => $override_access && $default_notify,
- '#description' => t('When enabled, the user will receive an e-mail notification after the account has been cancelled.'),
- );
-
- // Prepare confirmation form page title and description.
- if ($account->uid == $user->uid) {
- $question = t('Are you sure you want to cancel your account?');
- }
- else {
- $question = t('Are you sure you want to cancel the account %name?', array('%name' => $account->name));
- }
- $description = '';
- if ($can_select_method) {
- $description = t('Select the method to cancel the account above.');
- foreach (element_children($form['user_cancel_method']) as $element) {
- unset($form['user_cancel_method'][$element]['#description']);
- }
- }
- else {
- // The radio button #description is used as description for the confirmation
- // form.
- foreach (element_children($form['user_cancel_method']) as $element) {
- if ($form['user_cancel_method'][$element]['#default_value'] == $form['user_cancel_method'][$element]['#return_value']) {
- $description = $form['user_cancel_method'][$element]['#description'];
- }
- unset($form['user_cancel_method'][$element]['#description']);
- }
- }
-
- // Always provide entity id in the same form key as in the entity edit form.
- $form['uid'] = array('#type' => 'value', '#value' => $account->uid);
- return confirm_form($form,
- $question,
- 'user/' . $account->uid,
- $description . ' ' . t('This action cannot be undone.'),
- t('Cancel account'), t('Cancel'));
-}
-
-/**
- * Submit handler for the account cancellation confirm form.
- *
- * @see user_cancel_confirm_form()
- * @see user_multiple_cancel_confirm_submit()
- */
-function user_cancel_confirm_form_submit($form, &$form_state) {
- global $user;
- $account = $form_state['values']['_account'];
-
- // Cancel account immediately, if the current user has administrative
- // privileges, no confirmation mail shall be sent, and the user does not
- // attempt to cancel the own account.
- if (user_access('administer users') && empty($form_state['values']['user_cancel_confirm']) && $account->uid != $user->uid) {
- user_cancel($form_state['values'], $account->uid, $form_state['values']['user_cancel_method']);
-
- $form_state['redirect'] = 'admin/people';
- }
- else {
- // Store cancelling method and whether to notify the user in $account for
- // user_cancel_confirm().
- $edit = array(
- 'user_cancel_method' => $form_state['values']['user_cancel_method'],
- 'user_cancel_notify' => $form_state['values']['user_cancel_notify'],
- );
- $account = user_save($account, $edit);
- _user_mail_notify('cancel_confirm', $account);
- drupal_set_message(t('A confirmation request to cancel your account has been sent to your e-mail address.'));
- watchdog('user', 'Sent account cancellation request to %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
-
- $form_state['redirect'] = "user/$account->uid";
- }
-}
-
-/**
- * Helper function to return available account cancellation methods.
- *
- * See documentation of hook_user_cancel_methods_alter().
- *
- * @return
- * An array containing all account cancellation methods as form elements.
- *
- * @see hook_user_cancel_methods_alter()
- * @see user_admin_settings()
- * @see user_cancel_confirm_form()
- * @see user_multiple_cancel_confirm()
- */
-function user_cancel_methods() {
- $methods = array(
- 'user_cancel_block' => array(
- 'title' => t('Disable the account and keep its content.'),
- 'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'),
- ),
- 'user_cancel_block_unpublish' => array(
- 'title' => t('Disable the account and unpublish its content.'),
- 'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'),
- ),
- 'user_cancel_reassign' => array(
- 'title' => t('Delete the account and make its content belong to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
- 'description' => t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))),
- ),
- 'user_cancel_delete' => array(
- 'title' => t('Delete the account and its content.'),
- 'description' => t('Your account will be removed and all account information deleted. All of your content will also be deleted.'),
- 'access' => user_access('administer users'),
- ),
- );
- // Allow modules to customize account cancellation methods.
- drupal_alter('user_cancel_methods', $methods);
-
- // Turn all methods into real form elements.
- $default_method = variable_get('user_cancel_method', 'user_cancel_block');
- foreach ($methods as $name => $method) {
- $form[$name] = array(
- '#type' => 'radio',
- '#title' => $method['title'],
- '#description' => (isset($method['description']) ? $method['description'] : NULL),
- '#return_value' => $name,
- '#default_value' => $default_method,
- '#parents' => array('user_cancel_method'),
- );
- }
- return $form;
-}
-
-/**
- * Menu callback; Cancel a user account via e-mail confirmation link.
- *
- * @see user_cancel_confirm_form()
- * @see user_cancel_url()
- */
-function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
- // Time out in seconds until cancel URL expires; 24 hours = 86400 seconds.
- $timeout = 86400;
- $current = REQUEST_TIME;
-
- // Basic validation of arguments.
- if (isset($account->data['user_cancel_method']) && !empty($timestamp) && !empty($hashed_pass)) {
- // Validate expiration and hashed password/login.
- if ($timestamp <= $current && $current - $timestamp < $timeout && $account->uid && $timestamp >= $account->login && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
- $edit = array(
- 'user_cancel_notify' => isset($account->data['user_cancel_notify']) ? $account->data['user_cancel_notify'] : variable_get('user_mail_status_canceled_notify', FALSE),
- );
- user_cancel($edit, $account->uid, $account->data['user_cancel_method']);
- // Since user_cancel() is not invoked via Form API, batch processing needs
- // to be invoked manually and should redirect to the front page after
- // completion.
- batch_process('');
- }
- else {
- drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
- drupal_goto("user/$account->uid/cancel");
- }
- }
- return MENU_ACCESS_DENIED;
-}
-
-/**
- * Page callback: Displays the user page.
- *
- * Displays user profile if user is logged in, or login form for anonymous
- * users.
- *
- * @return
- * A render array for either a user profile or a login form.
- *
- * @see user_view_page()
- * @see user_login()
- */
-function user_page() {
- global $user;
- if ($user->uid) {
- menu_set_active_item('user/' . $user->uid);
- return menu_execute_active_handler(NULL, FALSE);
- }
- else {
- return drupal_get_form('user_login');
- }
-}
diff --git a/modules/user/user.permissions.js b/modules/user/user.permissions.js
deleted file mode 100644
index 988820e1..00000000
--- a/modules/user/user.permissions.js
+++ /dev/null
@@ -1,69 +0,0 @@
-(function ($) {
-
-/**
- * Shows checked and disabled checkboxes for inherited permissions.
- */
-Drupal.behaviors.permissions = {
- attach: function (context) {
- 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.
- var $dummy = $('
')
- .attr('title', Drupal.t("This permission is inherited from the authenticated user role."))
- .hide();
-
- $('input[type=checkbox]', this).not('.rid-2, .rid-1').addClass('real-checkbox').each(function () {
- $dummy.clone().insertAfter(this);
- });
-
- // Initialize the authenticated user checkbox.
- $('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');
- });
- }
-};
-
-})(jQuery);
diff --git a/modules/user/user.test b/modules/user/user.test
deleted file mode 100644
index e2086d4f..00000000
--- a/modules/user/user.test
+++ /dev/null
@@ -1,2368 +0,0 @@
- 'User registration',
- 'description' => 'Test registration of user under different configurations.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp('field_test');
- }
-
- function testRegistrationWithEmailVerification() {
- // Require e-mail verification.
- variable_set('user_email_verification', TRUE);
-
- // Set registration to administrator only.
- variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY);
- $this->drupalGet('user/register');
- $this->assertResponse(403, 'Registration page is inaccessible when only administrators can create accounts.');
-
- // Allow registration by site visitors without administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS);
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), 'User registered successfully.');
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertTrue($new_user->status, 'New account is active after registration.');
-
- // Allow registration by site visitors, but require administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertFalse($new_user->status, 'New account is blocked until approved by an administrator.');
- }
-
- function testRegistrationWithoutEmailVerification() {
- // Don't require e-mail verification.
- variable_set('user_email_verification', FALSE);
-
- // Allow registration by site visitors without administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS);
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
-
- // Try entering a mismatching password.
- $edit['pass[pass1]'] = '99999.0';
- $edit['pass[pass2]'] = '99999';
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.');
-
- // Enter a correct password.
- $edit['pass[pass1]'] = $new_pass = $this->randomName();
- $edit['pass[pass2]'] = $new_pass;
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertText(t('Registration successful. You are now logged in.'), 'Users are logged in after registering.');
- $this->drupalLogout();
-
- // Allow registration by site visitors, but require administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- $edit['pass[pass1]'] = $pass = $this->randomName();
- $edit['pass[pass2]'] = $pass;
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval');
-
- // Try to login before administrator approval.
- $auth = array(
- 'name' => $name,
- 'pass' => $pass,
- );
- $this->drupalPost('user/login', $auth, t('Log in'));
- $this->assertText(t('The username @name has not been activated or is blocked.', array('@name' => $name)), 'User cannot login yet.');
-
- // Activate the new account.
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $admin_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($admin_user);
- $edit = array(
- 'status' => 1,
- );
- $this->drupalPost('user/' . $new_user->uid . '/edit', $edit, t('Save'));
- $this->drupalLogout();
-
- // Login after administrator approval.
- $this->drupalPost('user/login', $auth, t('Log in'));
- $this->assertText(t('Member for'), 'User can log in after administrator approval.');
- }
-
- function testRegistrationEmailDuplicates() {
- // Don't require e-mail verification.
- variable_set('user_email_verification', FALSE);
-
- // Allow registration by site visitors without administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS);
-
- // Set up a user to check for duplicates.
- $duplicate_user = $this->drupalCreateUser();
-
- $edit = array();
- $edit['name'] = $this->randomName();
- $edit['mail'] = $duplicate_user->mail;
-
- // Attempt to create a new account using an existing e-mail address.
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying an exact duplicate email address displays an error message');
-
- // Attempt to bypass duplicate email registration validation by adding spaces.
- $edit['mail'] = ' ' . $duplicate_user->mail . ' ';
-
- $this->drupalPost('user/register', $edit, t('Create new account'));
- $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying a duplicate email address with added whitespace displays an error message');
- }
-
- function testRegistrationDefaultValues() {
- // Allow registration by site visitors without administrator approval.
- variable_set('user_register', USER_REGISTER_VISITORS);
-
- // Don't require e-mail verification.
- variable_set('user_email_verification', FALSE);
-
- // Set the default timezone to Brussels.
- variable_set('configurable_timezones', 1);
- variable_set('date_default_timezone', 'Europe/Brussels');
-
- // Check that the account information fieldset's options are not displayed
- // is a fieldset if there is not more than one fieldset in the form.
- $this->drupalGet('user/register');
- $this->assertNoRaw('
Account information ', 'Account settings fieldset was hidden.');
-
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- $edit['pass[pass1]'] = $new_pass = $this->randomName();
- $edit['pass[pass2]'] = $new_pass;
- $this->drupalPost(NULL, $edit, t('Create new account'));
-
- // Check user fields.
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertEqual($new_user->name, $name, 'Username matches.');
- $this->assertEqual($new_user->mail, $mail, 'E-mail address matches.');
- $this->assertEqual($new_user->theme, '', 'Correct theme field.');
- $this->assertEqual($new_user->signature, '', 'Correct signature field.');
- $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), 'Correct creation time.');
- $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
- $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), 'Correct time zone field.');
- $this->assertEqual($new_user->language, '', 'Correct language field.');
- $this->assertEqual($new_user->picture, '', 'Correct picture field.');
- $this->assertEqual($new_user->init, $mail, 'Correct init field.');
- }
-
- /**
- * Tests Field API fields on user registration forms.
- */
- function testRegistrationWithUserFields() {
- // Create a field, and an instance on 'user' entity type.
- $field = array(
- 'type' => 'test_field',
- 'field_name' => 'test_user_field',
- 'cardinality' => 1,
- );
- field_create_field($field);
- $instance = array(
- 'field_name' => 'test_user_field',
- 'entity_type' => 'user',
- 'label' => 'Some user field',
- 'bundle' => 'user',
- 'required' => TRUE,
- 'settings' => array('user_register_form' => FALSE),
- );
- field_create_instance($instance);
-
- // Check that the field does not appear on the registration form.
- $this->drupalGet('user/register');
- $this->assertNoText($instance['label'], 'The field does not appear on user registration form');
-
- // Have the field appear on the registration form.
- $instance['settings']['user_register_form'] = TRUE;
- field_update_instance($instance);
- $this->drupalGet('user/register');
- $this->assertText($instance['label'], 'The field appears on user registration form');
-
- // Check that validation errors are correctly reported.
- $edit = array();
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- // Missing input in required field.
- $edit['test_user_field[und][0][value]'] = '';
- $this->drupalPost(NULL, $edit, t('Create new account'));
- $this->assertRaw(t('@name field is required.', array('@name' => $instance['label'])), 'Field validation error was correctly reported.');
- // Invalid input.
- $edit['test_user_field[und][0][value]'] = '-1';
- $this->drupalPost(NULL, $edit, t('Create new account'));
- $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $instance['label'])), 'Field validation error was correctly reported.');
-
- // Submit with valid data.
- $value = rand(1, 255);
- $edit['test_user_field[und][0][value]'] = $value;
- $this->drupalPost(NULL, $edit, t('Create new account'));
- // Check user fields.
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, 'The field value was correctly saved.');
-
- // Check that the 'add more' button works.
- $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
- field_update_field($field);
- foreach (array('js', 'nojs') as $js) {
- $this->drupalGet('user/register');
- // Add two inputs.
- $value = rand(1, 255);
- $edit = array();
- $edit['test_user_field[und][0][value]'] = $value;
- if ($js == 'js') {
- $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
- $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more');
- }
- else {
- $this->drupalPost(NULL, $edit, t('Add another item'));
- $this->drupalPost(NULL, $edit, t('Add another item'));
- }
- // Submit with three values.
- $edit['test_user_field[und][1][value]'] = $value + 1;
- $edit['test_user_field[und][2][value]'] = $value + 2;
- $edit['name'] = $name = $this->randomName();
- $edit['mail'] = $mail = $edit['name'] . '@example.com';
- $this->drupalPost(NULL, $edit, t('Create new account'));
- // Check user fields.
- $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
- $new_user = reset($accounts);
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
- $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
- }
- }
-}
-
-class UserValidationTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Username/e-mail validation',
- 'description' => 'Verify that username/email validity checks behave as designed.',
- 'group' => 'User'
- );
- }
-
- // Username validation.
- function testUsernames() {
- $test_cases = array( // '' => array('', 'assert'),
- 'foo' => array('Valid username', 'assertNull'),
- 'FOO' => array('Valid username', 'assertNull'),
- 'Foo O\'Bar' => array('Valid username', 'assertNull'),
- 'foo@bar' => array('Valid username', 'assertNull'),
- 'foo@example.com' => array('Valid username', 'assertNull'),
- 'foo@-example.com' => array('Valid username', 'assertNull'), // invalid domains are allowed in usernames
- 'þòøÇߪř€' => array('Valid username', 'assertNull'),
- 'ᚠᛇᚻ᛫ᛒᛦᚦ' => array('Valid UTF8 username', 'assertNull'), // runes
- ' foo' => array('Invalid username that starts with a space', 'assertNotNull'),
- 'foo ' => array('Invalid username that ends with a space', 'assertNotNull'),
- 'foo bar' => array('Invalid username that contains 2 spaces \' \'', 'assertNotNull'),
- '' => array('Invalid empty username', 'assertNotNull'),
- 'foo/' => array('Invalid username containing invalid chars', 'assertNotNull'),
- 'foo' . chr(0) . 'bar' => array('Invalid username containing chr(0)', 'assertNotNull'), // NULL
- 'foo' . chr(13) . 'bar' => array('Invalid username containing chr(13)', 'assertNotNull'), // CR
- str_repeat('x', USERNAME_MAX_LENGTH + 1) => array('Invalid excessively long username', 'assertNotNull'),
- );
- foreach ($test_cases as $name => $test_case) {
- list($description, $test) = $test_case;
- $result = user_validate_name($name);
- $this->$test($result, $description . ' (' . $name . ')');
- }
- }
-
- // Mail validation. More extensive tests can be found at common.test
- function testMailAddresses() {
- $test_cases = array( // '' => array('', 'assert'),
- '' => array('Empty mail address', 'assertNotNull'),
- 'foo' => array('Invalid mail address', 'assertNotNull'),
- 'foo@example.com' => array('Valid mail address', 'assertNull'),
- );
- foreach ($test_cases as $name => $test_case) {
- list($description, $test) = $test_case;
- $result = user_validate_mail($name);
- $this->$test($result, $description . ' (' . $name . ')');
- }
- }
-}
-
-/**
- * Functional tests for user logins, including rate limiting of login attempts.
- */
-class UserLoginTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User login',
- 'description' => 'Ensure that login works as expected.',
- 'group' => 'User',
- );
- }
-
- /**
- * Test the global login flood control.
- */
- function testGlobalLoginFloodControl() {
- // Set the global login limit.
- variable_set('user_failed_login_ip_limit', 10);
- // Set a high per-user limit out so that it is not relevant in the test.
- variable_set('user_failed_login_user_limit', 4000);
-
- $user1 = $this->drupalCreateUser(array());
- $incorrect_user1 = clone $user1;
- $incorrect_user1->pass_raw .= 'incorrect';
-
- // Try 2 failed logins.
- for ($i = 0; $i < 2; $i++) {
- $this->assertFailedLogin($incorrect_user1);
- }
-
- // A successful login will not reset the IP-based flood control count.
- $this->drupalLogin($user1);
- $this->drupalLogout();
-
- // Try 8 more failed logins, they should not trigger the flood control
- // mechanism.
- for ($i = 0; $i < 8; $i++) {
- $this->assertFailedLogin($incorrect_user1);
- }
-
- // The next login trial should result in an IP-based flood error message.
- $this->assertFailedLogin($incorrect_user1, 'ip');
-
- // A login with the correct password should also result in a flood error
- // message.
- $this->assertFailedLogin($user1, 'ip');
- }
-
- /**
- * Test the per-user login flood control.
- */
- function testPerUserLoginFloodControl() {
- // Set a high global limit out so that it is not relevant in the test.
- variable_set('user_failed_login_ip_limit', 4000);
- // Set the per-user login limit.
- variable_set('user_failed_login_user_limit', 3);
-
- $user1 = $this->drupalCreateUser(array());
- $incorrect_user1 = clone $user1;
- $incorrect_user1->pass_raw .= 'incorrect';
-
- $user2 = $this->drupalCreateUser(array());
-
- // Try 2 failed logins.
- for ($i = 0; $i < 2; $i++) {
- $this->assertFailedLogin($incorrect_user1);
- }
-
- // A successful login will reset the per-user flood control count.
- $this->drupalLogin($user1);
- $this->drupalLogout();
-
- // Try 3 failed logins for user 1, they will not trigger flood control.
- for ($i = 0; $i < 3; $i++) {
- $this->assertFailedLogin($incorrect_user1);
- }
-
- // Try one successful attempt for user 2, it should not trigger any
- // flood control.
- $this->drupalLogin($user2);
- $this->drupalLogout();
-
- // Try one more attempt for user 1, it should be rejected, even if the
- // correct password has been used.
- $this->assertFailedLogin($user1, 'user');
- }
-
- /**
- * Test that user password is re-hashed upon login after changing $count_log2.
- */
- function testPasswordRehashOnLogin() {
- // Load password hashing API.
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- // Set initial $count_log2 to the default, DRUPAL_HASH_COUNT.
- variable_set('password_count_log2', DRUPAL_HASH_COUNT);
- // Create a new user and authenticate.
- $account = $this->drupalCreateUser(array());
- $password = $account->pass_raw;
- $this->drupalLogin($account);
- $this->drupalLogout();
- // Load the stored user. The password hash should reflect $count_log2.
- $account = user_load($account->uid);
- $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT);
- // Change $count_log2 and log in again.
- variable_set('password_count_log2', DRUPAL_HASH_COUNT + 1);
- $account->pass_raw = $password;
- $this->drupalLogin($account);
- // Load the stored user, which should have a different password hash now.
- $account = user_load($account->uid, TRUE);
- $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT + 1);
- }
-
- /**
- * Make an unsuccessful login attempt.
- *
- * @param $account
- * A user object with name and pass_raw attributes for the login attempt.
- * @param $flood_trigger
- * Whether or not to expect that the flood control mechanism will be
- * triggered.
- */
- function assertFailedLogin($account, $flood_trigger = NULL) {
- $edit = array(
- 'name' => $account->name,
- 'pass' => $account->pass_raw,
- );
- $this->drupalPost('user', $edit, t('Log in'));
- $this->assertNoFieldByXPath("//input[@name='pass' and @value!='']", NULL, 'Password value attribute is blank.');
- if (isset($flood_trigger)) {
- if ($flood_trigger == 'user') {
- $this->assertRaw(format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or request a new password .', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or request a new password .', array('@url' => url('user/password'))));
- }
- else {
- // No uid, so the limit is IP-based.
- $this->assertRaw(t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or request a new password .', array('@url' => url('user/password'))));
- }
- }
- else {
- $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'));
- }
- }
-}
-
-/**
- * Tests resetting a user password.
- */
-class UserPasswordResetTestCase extends DrupalWebTestCase {
- protected $profile = 'standard';
-
- public static function getInfo() {
- return array(
- 'name' => 'Reset password',
- 'description' => 'Ensure that password reset methods work as expected.',
- 'group' => 'User',
- );
- }
-
- /**
- * Tests password reset functionality.
- */
- function testUserPasswordReset() {
- // Create a user.
- $account = $this->drupalCreateUser();
- $this->drupalLogin($account);
- $this->drupalLogout();
- // Attempt to reset password.
- $edit = array('name' => $account->name);
- $this->drupalPost('user/password', $edit, t('E-mail new password'));
- // Confirm the password reset.
- $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.');
- }
-
- /**
- * Attempts login using an expired password reset link.
- */
- function testUserPasswordResetExpired() {
- // Set password reset timeout variable to 43200 seconds = 12 hours.
- $timeout = 43200;
- variable_set('user_password_reset_timeout', $timeout);
-
- // Create a user.
- $account = $this->drupalCreateUser();
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
- $this->drupalLogout();
-
- // To attempt an expired password reset, create a password reset link as if
- // its request time was 60 seconds older than the allowed limit of timeout.
- $bogus_timestamp = REQUEST_TIME - variable_get('user_password_reset_timeout', 86400) - 60;
- $this->drupalGet("user/reset/$account->uid/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
- $this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.');
- }
-
- /**
- * Prefill the text box on incorrect login via link to password reset page.
- */
- function testUserPasswordTextboxFilled() {
- $this->drupalGet('user/login');
- $edit = array(
- 'name' => $this->randomName(),
- 'pass' => $this->randomName(),
- );
- $this->drupalPost('user', $edit, t('Log in'));
- $this->assertRaw(t('Sorry, unrecognized username or password. Have you forgotten your password? ',
- array('@password' => url('user/password', array('query' => array('name' => $edit['name']))))));
- unset($edit['pass']);
- $this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
- $this->assertFieldByName('name', $edit['name'], 'User name found.');
- }
-
-}
-
-/**
- * Test cancelling a user.
- */
-class UserCancelTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Cancel account',
- 'description' => 'Ensure that account cancellation methods work as expected.',
- 'group' => 'User',
- );
- }
-
- function setUp() {
- parent::setUp('comment');
- }
-
- /**
- * Attempt to cancel account without permission.
- */
- function testUserCancelWithoutPermission() {
- variable_set('user_cancel_method', 'user_cancel_reassign');
-
- // Create a user.
- $account = $this->drupalCreateUser(array());
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
-
- // Create a node.
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
-
- // Attempt to cancel account.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->assertNoRaw(t('Cancel account'), 'No cancel account button displayed.');
-
- // Attempt bogus account cancellation request confirmation.
- $timestamp = $account->login;
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $this->assertResponse(403, 'Bogus cancelling request rejected.');
- $account = user_load($account->uid);
- $this->assertTrue($account->status == 1, 'User account was not canceled.');
-
- // Confirm user's content has not been altered.
- $test_node = node_load($node->nid, NULL, TRUE);
- $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
- }
-
- /**
- * Tests that user account for uid 1 cannot be cancelled.
- *
- * This should never be possible, or the site owner would become unable to
- * administer the site.
- */
- function testUserCancelUid1() {
- // Update uid 1's name and password to we know it.
- $password = user_password();
- require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- $account = array(
- 'name' => 'user1',
- 'pass' => user_hash_password(trim($password)),
- );
- // We cannot use user_save() here or the password would be hashed again.
- db_update('users')
- ->fields($account)
- ->condition('uid', 1)
- ->execute();
-
- // Reload and log in uid 1.
- $user1 = user_load(1, TRUE);
- $user1->pass_raw = $password;
-
- // Try to cancel uid 1's account with a different user.
- $this->admin_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($this->admin_user);
- $edit = array(
- 'operation' => 'cancel',
- 'accounts[1]' => TRUE,
- );
- $this->drupalPost('admin/people', $edit, t('Update'));
-
- // Verify that uid 1's account was not cancelled.
- $user1 = user_load(1, TRUE);
- $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
- }
-
- /**
- * Attempt invalid account cancellations.
- */
- function testUserCancelInvalid() {
- variable_set('user_cancel_method', 'user_cancel_reassign');
-
- // Create a user.
- $account = $this->drupalCreateUser(array('cancel account'));
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
-
- // Create a node.
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
-
- // Attempt to cancel account.
- $this->drupalPost('user/' . $account->uid . '/edit', NULL, t('Cancel account'));
-
- // Confirm account cancellation.
- $timestamp = time();
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
-
- // Attempt bogus account cancellation request confirmation.
- $bogus_timestamp = $timestamp + 60;
- $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
- $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Bogus cancelling request rejected.');
- $account = user_load($account->uid);
- $this->assertTrue($account->status == 1, 'User account was not canceled.');
-
- // Attempt expired account cancellation request confirmation.
- $bogus_timestamp = $timestamp - 86400 - 60;
- $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login));
- $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Expired cancel account request rejected.');
- $accounts = user_load_multiple(array($account->uid), array('status' => 1));
- $this->assertTrue(reset($accounts), 'User account was not canceled.');
-
- // Confirm user's content has not been altered.
- $test_node = node_load($node->nid, NULL, TRUE);
- $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.');
- }
-
- /**
- * Disable account and keep all content.
- */
- function testUserBlock() {
- variable_set('user_cancel_method', 'user_cancel_block');
-
- // Create a user.
- $web_user = $this->drupalCreateUser(array('cancel account'));
- $this->drupalLogin($web_user);
-
- // Load real user object.
- $account = user_load($web_user->uid, TRUE);
-
- // Attempt to cancel account.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
- $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'), 'Informs that all content will be remain as is.');
- $this->assertNoText(t('Select the method to cancel the account above.'), 'Does not allow user to select account cancellation method.');
-
- // Confirm account cancellation.
- $timestamp = time();
-
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
-
- // Confirm account cancellation request.
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $account = user_load($account->uid, TRUE);
- $this->assertTrue($account->status == 0, 'User has been blocked.');
-
- // Confirm that the confirmation message made it through to the end user.
- $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
- }
-
- /**
- * Disable account and unpublish all content.
- */
- function testUserBlockUnpublish() {
- variable_set('user_cancel_method', 'user_cancel_block_unpublish');
-
- // Create a user.
- $account = $this->drupalCreateUser(array('cancel account'));
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
-
- // Create a node with two revisions.
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
- $settings = get_object_vars($node);
- $settings['revision'] = 1;
- $node = $this->drupalCreateNode($settings);
-
- // Attempt to cancel account.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
- $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'), 'Informs that all content will be unpublished.');
-
- // Confirm account cancellation.
- $timestamp = time();
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
-
- // Confirm account cancellation request.
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $account = user_load($account->uid, TRUE);
- $this->assertTrue($account->status == 0, 'User has been blocked.');
-
- // Confirm user's content has been unpublished.
- $test_node = node_load($node->nid, NULL, TRUE);
- $this->assertTrue($test_node->status == 0, 'Node of the user has been unpublished.');
- $test_node = node_load($node->nid, $node->vid, TRUE);
- $this->assertTrue($test_node->status == 0, 'Node revision of the user has been unpublished.');
-
- // Confirm that the confirmation message made it through to the end user.
- $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user.");
- }
-
- /**
- * Delete account and anonymize all content.
- */
- function testUserAnonymize() {
- variable_set('user_cancel_method', 'user_cancel_reassign');
-
- // Create a user.
- $account = $this->drupalCreateUser(array('cancel account'));
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
-
- // Create a simple node.
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
-
- // Create a node with two revisions, the initial one belonging to the
- // cancelling user.
- $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
- $revision = $revision_node->vid;
- $settings = get_object_vars($revision_node);
- $settings['revision'] = 1;
- $settings['uid'] = 1; // Set new/current revision to someone else.
- $revision_node = $this->drupalCreateNode($settings);
-
- // Attempt to cancel account.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
- $this->assertRaw(t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))), 'Informs that all content will be attributed to anonymous account.');
-
- // Confirm account cancellation.
- $timestamp = time();
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
-
- // Confirm account cancellation request.
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
-
- // Confirm that user's content has been attributed to anonymous user.
- $test_node = node_load($node->nid, NULL, TRUE);
- $this->assertTrue(($test_node->uid == 0 && $test_node->status == 1), 'Node of the user has been attributed to anonymous user.');
- $test_node = node_load($revision_node->nid, $revision, TRUE);
- $this->assertTrue(($test_node->revision_uid == 0 && $test_node->status == 1), 'Node revision of the user has been attributed to anonymous user.');
- $test_node = node_load($revision_node->nid, NULL, TRUE);
- $this->assertTrue(($test_node->uid != 0 && $test_node->status == 1), "Current revision of the user's node was not attributed to anonymous user.");
-
- // Confirm that the confirmation message made it through to the end user.
- $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
- }
-
- /**
- * Delete account and remove all content.
- */
- function testUserDelete() {
- variable_set('user_cancel_method', 'user_cancel_delete');
-
- // Create a user.
- $account = $this->drupalCreateUser(array('cancel account', 'post comments', 'skip comment approval'));
- $this->drupalLogin($account);
- // Load real user object.
- $account = user_load($account->uid, TRUE);
-
- // Create a simple node.
- $node = $this->drupalCreateNode(array('uid' => $account->uid));
-
- // Create comment.
- $langcode = LANGUAGE_NONE;
- $edit = array();
- $edit['subject'] = $this->randomName(8);
- $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
-
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
- $this->drupalPost(NULL, array(), t('Save'));
- $this->assertText(t('Your comment has been posted.'));
- $comments = comment_load_multiple(array(), array('subject' => $edit['subject']));
- $comment = reset($comments);
- $this->assertTrue($comment->cid, 'Comment found.');
-
- // Create a node with two revisions, the initial one belonging to the
- // cancelling user.
- $revision_node = $this->drupalCreateNode(array('uid' => $account->uid));
- $revision = $revision_node->vid;
- $settings = get_object_vars($revision_node);
- $settings['revision'] = 1;
- $settings['uid'] = 1; // Set new/current revision to someone else.
- $revision_node = $this->drupalCreateNode($settings);
-
- // Attempt to cancel account.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
- $this->assertText(t('Your account will be removed and all account information deleted. All of your content will also be deleted.'), 'Informs that all content will be deleted.');
-
- // Confirm account cancellation.
- $timestamp = time();
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
-
- // Confirm account cancellation request.
- $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login));
- $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.');
-
- // Confirm that user's content has been deleted.
- $this->assertFalse(node_load($node->nid, NULL, TRUE), 'Node of the user has been deleted.');
- $this->assertFalse(node_load($node->nid, $revision, TRUE), 'Node revision of the user has been deleted.');
- $this->assertTrue(node_load($revision_node->nid, NULL, TRUE), "Current revision of the user's node was not deleted.");
- $this->assertFalse(comment_load($comment->cid), 'Comment of the user has been deleted.');
-
- // Confirm that the confirmation message made it through to the end user.
- $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user.");
- }
-
- /**
- * Create an administrative user and delete another user.
- */
- function testUserCancelByAdmin() {
- variable_set('user_cancel_method', 'user_cancel_reassign');
-
- // Create a regular user.
- $account = $this->drupalCreateUser(array());
-
- // Create administrative user.
- $admin_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($admin_user);
-
- // Delete regular user.
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertRaw(t('Are you sure you want to cancel the account %name?', array('%name' => $account->name)), 'Confirmation form to cancel account displayed.');
- $this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.');
-
- // Confirm deletion.
- $this->drupalPost(NULL, NULL, t('Cancel account'));
- $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), 'User deleted.');
- $this->assertFalse(user_load($account->uid), 'User is not found in the database.');
- }
-
- /**
- * Create an administrative user and mass-delete other users.
- */
- function testMassUserCancelByAdmin() {
- variable_set('user_cancel_method', 'user_cancel_reassign');
- // Enable account cancellation notification.
- variable_set('user_mail_status_canceled_notify', TRUE);
-
- // Create administrative user.
- $admin_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($admin_user);
-
- // Create some users.
- $users = array();
- for ($i = 0; $i < 3; $i++) {
- $account = $this->drupalCreateUser(array());
- $users[$account->uid] = $account;
- }
-
- // Cancel user accounts, including own one.
- $edit = array();
- $edit['operation'] = 'cancel';
- foreach ($users as $uid => $account) {
- $edit['accounts[' . $uid . ']'] = TRUE;
- }
- $edit['accounts[' . $admin_user->uid . ']'] = TRUE;
- // Also try to cancel uid 1.
- $edit['accounts[1]'] = TRUE;
- $this->drupalPost('admin/people', $edit, t('Update'));
- $this->assertText(t('Are you sure you want to cancel these user accounts?'), 'Confirmation form to cancel accounts displayed.');
- $this->assertText(t('When cancelling these accounts'), 'Allows to select account cancellation method.');
- $this->assertText(t('Require e-mail confirmation to cancel account.'), 'Allows to send confirmation mail.');
- $this->assertText(t('Notify user when account is canceled.'), 'Allows to send notification mail.');
-
- // Confirm deletion.
- $this->drupalPost(NULL, NULL, t('Cancel accounts'));
- $status = TRUE;
- foreach ($users as $account) {
- $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->name))) !== FALSE);
- $status = $status && !user_load($account->uid, TRUE);
- }
- $this->assertTrue($status, 'Users deleted and not found in the database.');
-
- // Ensure that admin account was not cancelled.
- $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.');
- $admin_user = user_load($admin_user->uid);
- $this->assertTrue($admin_user->status == 1, 'Administrative user is found in the database and enabled.');
-
- // Verify that uid 1's account was not cancelled.
- $user1 = user_load(1, TRUE);
- $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.');
- }
-}
-
-class UserPictureTestCase extends DrupalWebTestCase {
- protected $user;
- protected $_directory_test;
-
- public static function getInfo() {
- return array(
- 'name' => 'Upload user picture',
- 'description' => 'Assure that dimension check, extension check and image scaling work as designed.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp();
- // Enable user pictures.
- variable_set('user_pictures', 1);
-
- $this->user = $this->drupalCreateUser();
-
- // Test if directories specified in settings exist in filesystem.
- $file_dir = 'public://';
- $file_check = file_prepare_directory($file_dir, FILE_CREATE_DIRECTORY);
- // TODO: Test public and private methods?
-
- $picture_dir = variable_get('user_picture_path', 'pictures');
- $picture_path = $file_dir . $picture_dir;
-
- $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY);
- $this->_directory_test = is_writable($picture_path);
- $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
- }
-
- function testNoPicture() {
- $this->drupalLogin($this->user);
-
- // Try to upload a file that is not an image for the user picture.
- $not_an_image = current($this->drupalGetTestFiles('html'));
- $this->saveUserPicture($not_an_image);
- $this->assertRaw(t('Only JPEG, PNG and GIF images are allowed.'), 'Non-image files are not accepted.');
- }
-
- /**
- * Do the test:
- * GD Toolkit is installed
- * Picture has invalid dimension
- *
- * results: The image should be uploaded because ImageGDToolkit resizes the picture
- */
- function testWithGDinvalidDimension() {
- if ($this->_directory_test && image_get_toolkit()) {
- $this->drupalLogin($this->user);
-
- $image = current($this->drupalGetTestFiles('image'));
- $info = image_get_info($image->uri);
-
- // Set new variables: invalid dimensions, valid filesize (0 = no limit).
- $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', 0);
-
- $pic_path = $this->saveUserPicture($image);
- // Check that the image was resized and is being displayed on the
- // user's profile page.
- $text = t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $test_dim));
- $this->assertRaw($text, 'Image was resized.');
- $alt = t("@user's picture", array('@user' => format_username($this->user)));
- $style = variable_get('user_picture_style', '');
- $this->assertRaw(check_plain(image_style_url($style, $pic_path)), "Image is displayed in user's edit page");
-
- // Check if file is located in proper directory.
- $this->assertTrue(is_file($pic_path), "File is located in proper directory");
- }
- }
-
- /**
- * Do the test:
- * GD Toolkit is installed
- * Picture has invalid size
- *
- * results: The image should be uploaded because ImageGDToolkit resizes the picture
- */
- function testWithGDinvalidSize() {
- if ($this->_directory_test && image_get_toolkit()) {
- $this->drupalLogin($this->user);
-
- // Images are sorted first by size then by name. We need an image
- // bigger than 1 KB so we'll grab the last one.
- $files = $this->drupalGetTestFiles('image');
- $image = end($files);
- $info = image_get_info($image->uri);
-
- // Set new variables: valid dimensions, invalid filesize.
- $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
- $test_size = 1;
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', $test_size);
-
- $pic_path = $this->saveUserPicture($image);
-
- // Test that the upload failed and that the correct reason was cited.
- $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
- $this->assertRaw($text, 'Upload failed.');
- $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024)));
- $this->assertRaw($text, 'File size cited as reason for failure.');
-
- // Check if file is not uploaded.
- $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
- }
- }
-
- /**
- * Do the test:
- * GD Toolkit is not installed
- * Picture has invalid size
- *
- * results: The image shouldn't be uploaded
- */
- function testWithoutGDinvalidDimension() {
- if ($this->_directory_test && !image_get_toolkit()) {
- $this->drupalLogin($this->user);
-
- $image = current($this->drupalGetTestFiles('image'));
- $info = image_get_info($image->uri);
-
- // Set new variables: invalid dimensions, valid filesize (0 = no limit).
- $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', 0);
-
- $pic_path = $this->saveUserPicture($image);
-
- // Test that the upload failed and that the correct reason was cited.
- $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
- $this->assertRaw($text, 'Upload failed.');
- $text = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $test_dim));
- $this->assertRaw($text, 'Checking response on invalid image (dimensions).');
-
- // Check if file is not uploaded.
- $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
- }
- }
-
- /**
- * Do the test:
- * GD Toolkit is not installed
- * Picture has invalid size
- *
- * results: The image shouldn't be uploaded
- */
- function testWithoutGDinvalidSize() {
- if ($this->_directory_test && !image_get_toolkit()) {
- $this->drupalLogin($this->user);
-
- $image = current($this->drupalGetTestFiles('image'));
- $info = image_get_info($image->uri);
-
- // Set new variables: valid dimensions, invalid filesize.
- $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
- $test_size = 1;
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', $test_size);
-
- $pic_path = $this->saveUserPicture($image);
-
- // Test that the upload failed and that the correct reason was cited.
- $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename));
- $this->assertRaw($text, 'Upload failed.');
- $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024)));
- $this->assertRaw($text, 'File size cited as reason for failure.');
-
- // Check if file is not uploaded.
- $this->assertFalse(is_file($pic_path), 'File was not uploaded.');
- }
- }
-
- /**
- * Do the test:
- * Picture is valid (proper size and dimension)
- *
- * results: The image should be uploaded
- */
- function testPictureIsValid() {
- if ($this->_directory_test) {
- $this->drupalLogin($this->user);
-
- $image = current($this->drupalGetTestFiles('image'));
- $info = image_get_info($image->uri);
-
- // Set new variables: valid dimensions, valid filesize (0 = no limit).
- $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', 0);
-
- $pic_path = $this->saveUserPicture($image);
-
- // Check if image is displayed in user's profile page.
- $this->drupalGet('user');
- $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
-
- // Check if file is located in proper directory.
- $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
-
- // Set new picture dimensions.
- $test_dim = ($info['width'] + 5) . 'x' . ($info['height'] + 5);
- variable_set('user_picture_dimensions', $test_dim);
-
- $pic_path2 = $this->saveUserPicture($image);
- $this->assertNotEqual($pic_path, $pic_path2, 'Filename of second picture is different.');
- }
- }
-
- /**
- * Test HTTP schema working with user pictures.
- */
- function testExternalPicture() {
- $this->drupalLogin($this->user);
- // Set the default picture to an URI with a HTTP schema.
- $images = $this->drupalGetTestFiles('image');
- $image = $images[0];
- $pic_path = file_create_url($image->uri);
- variable_set('user_picture_default', $pic_path);
-
- // Check if image is displayed in user's profile page.
- $this->drupalGet('user');
-
- // Get the user picture image via xpath.
- $elements = $this->xpath('//div[@class="user-picture"]/img');
- $this->assertEqual(count($elements), 1, "There is exactly one user picture on the user's profile page");
- $this->assertEqual($pic_path, (string) $elements[0]['src'], "User picture source is correct.");
- }
-
- /**
- * Tests deletion of user pictures.
- */
- function testDeletePicture() {
- $this->drupalLogin($this->user);
-
- $image = current($this->drupalGetTestFiles('image'));
- $info = image_get_info($image->uri);
-
- // Set new variables: valid dimensions, valid filesize (0 = no limit).
- $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
- variable_set('user_picture_dimensions', $test_dim);
- variable_set('user_picture_file_size', 0);
-
- // Save a new picture.
- $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
- $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
-
- // Load actual user data from database.
- $account = user_load($this->user->uid, TRUE);
- $pic_path = isset($account->picture) ? $account->picture->uri : NULL;
-
- // Check if image is displayed in user's profile page.
- $this->drupalGet('user');
- $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page");
-
- // Check if file is located in proper directory.
- $this->assertTrue(is_file($pic_path), 'File is located in proper directory');
-
- $edit = array('picture_delete' => 1);
- $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
-
- // Load actual user data from database.
- $account1 = user_load($this->user->uid, TRUE);
- $this->assertNull($account1->picture, 'User object has no picture');
-
- $file = file_load($account->picture->fid);
- $this->assertFalse($file, 'File is removed from database');
-
- // Clear out PHP's file stat cache so we see the current value.
- clearstatcache();
- $this->assertFalse(is_file($pic_path), 'File is removed from file system');
- }
-
- function saveUserPicture($image) {
- $edit = array('files[picture_upload]' => drupal_realpath($image->uri));
- $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save'));
-
- // Load actual user data from database.
- $account = user_load($this->user->uid, TRUE);
- return isset($account->picture) ? $account->picture->uri : NULL;
- }
-
- /**
- * Tests the admin form validates user picture settings.
- */
- function testUserPictureAdminFormValidation() {
- $this->drupalLogin($this->drupalCreateUser(array('administer users')));
-
- // The default values are valid.
- $this->drupalPost('admin/config/people/accounts', array(), t('Save configuration'));
- $this->assertText(t('The configuration options have been saved.'), 'The default values are valid.');
-
- // The form does not save with an invalid file size.
- $edit = array(
- 'user_picture_file_size' => $this->randomName(),
- );
- $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
- $this->assertNoText(t('The configuration options have been saved.'), 'The form does not save with an invalid file size.');
- }
-}
-
-
-class UserPermissionsTestCase extends DrupalWebTestCase {
- protected $admin_user;
- protected $rid;
-
- public static function getInfo() {
- return array(
- 'name' => 'Role permissions',
- 'description' => 'Verify that role permissions can be added and removed via the permissions page.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp();
-
- $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users'));
-
- // Find the new role ID - it must be the maximum.
- $all_rids = array_keys($this->admin_user->roles);
- sort($all_rids);
- $this->rid = array_pop($all_rids);
- }
-
- /**
- * Change user permissions and check user_access().
- */
- function testUserPermissionChanges() {
- $this->drupalLogin($this->admin_user);
- $rid = $this->rid;
- $account = $this->admin_user;
-
- // Add a permission.
- $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
- $edit = array();
- $edit[$rid . '[administer nodes]'] = TRUE;
- $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
- $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
-
- // Remove a permission.
- $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
- $edit = array();
- $edit[$rid . '[access user profiles]'] = FALSE;
- $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
- $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
- drupal_static_reset('user_access');
- drupal_static_reset('user_role_permissions');
- $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
- }
-
- /**
- * Test assigning of permissions for the administrator role.
- */
- function testAdministratorRole() {
- $this->drupalLogin($this->admin_user);
- $this->drupalGet('admin/config/people/accounts');
-
- // Set the user's role to be the administrator role.
- $edit = array();
- $edit['user_admin_role'] = $this->rid;
- $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration'));
-
- // Enable aggregator module and ensure the 'administer news feeds'
- // permission is assigned by default.
- $edit = array();
- $edit['modules[Core][aggregator][enable]'] = TRUE;
- $this->drupalPost('admin/modules', $edit, t('Save configuration'));
- $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role');
- }
-
- /**
- * Verify proper permission changes by user_role_change_permissions().
- */
- function testUserRoleChangePermissions() {
- $rid = $this->rid;
- $account = $this->admin_user;
-
- // Verify current permissions.
- $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
- $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
- $this->assertTrue(user_access('administer site configuration', $account), 'User has "administer site configuration" permission.');
-
- // Change permissions.
- $permissions = array(
- 'administer nodes' => 1,
- 'access user profiles' => 0,
- );
- user_role_change_permissions($rid, $permissions);
-
- // Verify proper permission changes.
- $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
- $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
- $this->assertTrue(user_access('administer site configuration', $account), 'User still has "administer site configuration" permission.');
- }
-}
-
-class UserAdminTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User administration',
- 'description' => 'Test user administration page functionality.',
- 'group' => 'User'
- );
- }
-
- /**
- * Registers a user and deletes it.
- */
- function testUserAdmin() {
-
- $user_a = $this->drupalCreateUser(array());
- $user_b = $this->drupalCreateUser(array('administer taxonomy'));
- $user_c = $this->drupalCreateUser(array('administer taxonomy'));
-
- // Create admin user to delete registered user.
- $admin_user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($admin_user);
- $this->drupalGet('admin/people');
- $this->assertText($user_a->name, 'Found user A on admin users page');
- $this->assertText($user_b->name, 'Found user B on admin users page');
- $this->assertText($user_c->name, 'Found user C on admin users page');
- $this->assertText($admin_user->name, 'Found Admin user on admin users page');
-
- // Test for existence of edit link in table.
- $link = l(t('edit'), "user/$user_a->uid/edit", array('query' => array('destination' => 'admin/people')));
- $this->assertRaw($link, 'Found user A edit link on admin users page');
-
- // Filter the users by permission 'administer taxonomy'.
- $edit = array();
- $edit['permission'] = 'administer taxonomy';
- $this->drupalPost('admin/people', $edit, t('Filter'));
-
- // Check if the correct users show up.
- $this->assertNoText($user_a->name, 'User A not on filtered by perm admin users page');
- $this->assertText($user_b->name, 'Found user B on filtered by perm admin users page');
- $this->assertText($user_c->name, 'Found user C on filtered by perm admin users page');
-
- // Filter the users by role. Grab the system-generated role name for User C.
- $edit['role'] = max(array_flip($user_c->roles));
- $this->drupalPost('admin/people', $edit, t('Refine'));
-
- // Check if the correct users show up when filtered by role.
- $this->assertNoText($user_a->name, 'User A not on filtered by role on admin users page');
- $this->assertNoText($user_b->name, 'User B not on filtered by role on admin users page');
- $this->assertText($user_c->name, 'User C on filtered by role on admin users page');
-
- // Test blocking of a user.
- $account = user_load($user_c->uid);
- $this->assertEqual($account->status, 1, 'User C not blocked');
- $edit = array();
- $edit['operation'] = 'block';
- $edit['accounts[' . $account->uid . ']'] = TRUE;
- $this->drupalPost('admin/people', $edit, t('Update'));
- $account = user_load($user_c->uid, TRUE);
- $this->assertEqual($account->status, 0, 'User C blocked');
-
- // Test unblocking of a user from /admin/people page and sending of activation mail
- $editunblock = array();
- $editunblock['operation'] = 'unblock';
- $editunblock['accounts[' . $account->uid . ']'] = TRUE;
- $this->drupalPost('admin/people', $editunblock, t('Update'));
- $account = user_load($user_c->uid, TRUE);
- $this->assertEqual($account->status, 1, 'User C unblocked');
- $this->assertMail("to", $account->mail, "Activation mail sent to user C");
-
- // Test blocking and unblocking another user from /user/[uid]/edit form and sending of activation mail
- $user_d = $this->drupalCreateUser(array());
- $account1 = user_load($user_d->uid, TRUE);
- $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => 0), t('Save'));
- $account1 = user_load($user_d->uid, TRUE);
- $this->assertEqual($account1->status, 0, 'User D blocked');
- $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => TRUE), t('Save'));
- $account1 = user_load($user_d->uid, TRUE);
- $this->assertEqual($account1->status, 1, 'User D unblocked');
- $this->assertMail("to", $account1->mail, "Activation mail sent to user D");
- }
-}
-
-/**
- * Tests for user-configurable time zones.
- */
-class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User time zones',
- 'description' => 'Set a user time zone and verify that dates are displayed in local time.',
- 'group' => 'User',
- );
- }
-
- /**
- * Tests the display of dates and time when user-configurable time zones are set.
- */
- function testUserTimeZone() {
- // Setup date/time settings for Los Angeles time.
- variable_set('date_default_timezone', 'America/Los_Angeles');
- variable_set('configurable_timezones', 1);
- variable_set('date_format_medium', 'Y-m-d H:i T');
-
- // Create a user account and login.
- $web_user = $this->drupalCreateUser();
- $this->drupalLogin($web_user);
-
- // Create some nodes with different authored-on dates.
- // Two dates in PST (winter time):
- $date1 = '2007-03-09 21:00:00 -0800';
- $date2 = '2007-03-11 01:00:00 -0800';
- // One date in PDT (summer time):
- $date3 = '2007-03-20 21:00:00 -0700';
- $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article'));
- $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article'));
- $node3 = $this->drupalCreateNode(array('created' => strtotime($date3), 'type' => 'article'));
-
- // Confirm date format and time zone.
- $this->drupalGet("node/$node1->nid");
- $this->assertText('2007-03-09 21:00 PST', 'Date should be PST.');
- $this->drupalGet("node/$node2->nid");
- $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.');
- $this->drupalGet("node/$node3->nid");
- $this->assertText('2007-03-20 21:00 PDT', 'Date should be PDT.');
-
- // Change user time zone to Santiago time.
- $edit = array();
- $edit['mail'] = $web_user->mail;
- $edit['timezone'] = 'America/Santiago';
- $this->drupalPost("user/$web_user->uid/edit", $edit, t('Save'));
- $this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.');
-
- // Confirm date format and time zone.
- $this->drupalGet("node/$node1->nid");
- $this->assertText('2007-03-10 02:00 CLST', 'Date should be Chile summer time; five hours ahead of PST.');
- $this->drupalGet("node/$node2->nid");
- $this->assertText('2007-03-11 05:00 CLT', 'Date should be Chile time; four hours ahead of PST');
- $this->drupalGet("node/$node3->nid");
- $this->assertText('2007-03-21 00:00 CLT', 'Date should be Chile time; three hours ahead of PDT.');
- }
-}
-
-/**
- * Test user autocompletion.
- */
-class UserAutocompleteTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User autocompletion',
- 'description' => 'Test user autocompletion functionality.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp();
-
- // Set up two users with different permissions to test access.
- $this->unprivileged_user = $this->drupalCreateUser();
- $this->privileged_user = $this->drupalCreateUser(array('access user profiles'));
- }
-
- /**
- * Tests access to user autocompletion and verify the correct results.
- */
- function testUserAutocomplete() {
- // Check access from unprivileged user, should be denied.
- $this->drupalLogin($this->unprivileged_user);
- $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
- $this->assertResponse(403, 'Autocompletion access denied to user without permission.');
-
- // Check access from privileged user.
- $this->drupalLogout();
- $this->drupalLogin($this->privileged_user);
- $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]);
- $this->assertResponse(200, 'Autocompletion access allowed.');
-
- // Using first letter of the user's name, make sure the user's full name is in the results.
- $this->assertRaw($this->unprivileged_user->name, 'User name found in autocompletion results.');
- }
-}
-
-
-/**
- * Tests user links in the secondary menu.
- */
-class UserAccountLinksUnitTests extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User account links',
- 'description' => 'Test user-account links.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp('menu');
- }
-
- /**
- * Tests the secondary menu.
- */
- function testSecondaryMenu() {
- // Create a regular user.
- $user = $this->drupalCreateUser(array());
-
- // Log in and get the homepage.
- $this->drupalLogin($user);
- $this->drupalGet('');
-
- // For a logged-in user, expect the secondary menu to have links for "My
- // account" and "Log out".
- $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
- ':menu_id' => 'secondary-menu-links',
- ':href' => 'user',
- ':text' => 'My account',
- ));
- $this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
-
- $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
- ':menu_id' => 'secondary-menu-links',
- ':href' => 'user/logout',
- ':text' => 'Log out',
- ));
- $this->assertEqual(count($link), 1, 'Log out link is in secondary menu.');
-
- // Log out and get the homepage.
- $this->drupalLogout();
- $this->drupalGet('');
-
- // For a logged-out user, expect no secondary links.
- $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links'));
- $this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.');
- }
-
- /**
- * Tests disabling the 'My account' link.
- */
- function testDisabledAccountLink() {
- // Create an admin user and log in.
- $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu')));
-
- // Verify that the 'My account' link is enabled.
- $this->drupalGet('admin/structure/menu/manage/user-menu');
- $label = $this->xpath('//label[contains(.,:text)]/@for', array(':text' => 'Enable My account menu link'));
- $this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
-
- // Disable the 'My account' link.
- $input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0]));
- $edit = array(
- (string) $input[0] => FALSE,
- );
- $this->drupalPost('admin/structure/menu/manage/user-menu', $edit, t('Save configuration'));
-
- // Get the homepage.
- $this->drupalGet('');
-
- // Verify that the 'My account' link does not appear when disabled.
- $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array(
- ':menu_id' => 'secondary-menu-links',
- ':href' => 'user',
- ':text' => 'My account',
- ));
- $this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.');
- }
-
-}
-
-/**
- * Test user blocks.
- */
-class UserBlocksUnitTests extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User blocks',
- 'description' => 'Test user blocks.',
- 'group' => 'User'
- );
- }
-
- /**
- * Test the user login block.
- */
- function testUserLoginBlock() {
- // Create a user with some permission that anonymous users lack.
- $user = $this->drupalCreateUser(array('administer permissions'));
-
- // Log in using the block.
- $edit = array();
- $edit['name'] = $user->name;
- $edit['pass'] = $user->pass_raw;
- $this->drupalPost('admin/people/permissions', $edit, t('Log in'));
- $this->assertNoText(t('User login'), 'Logged in.');
-
- // Check that we are still on the same page.
- $this->assertEqual(url('admin/people/permissions', array('absolute' => TRUE)), $this->getUrl(), 'Still on the same page after login for access denied page');
-
- // Now, log out and repeat with a non-403 page.
- $this->drupalLogout();
- $this->drupalPost('filter/tips', $edit, t('Log in'));
- $this->assertNoText(t('User login'), 'Logged in.');
- $this->assertPattern('!!', 'Still on the same page after login for allowed page');
-
- // Check that the user login block is not vulnerable to information
- // disclosure to third party sites.
- $this->drupalLogout();
- $this->drupalPost('http://example.com/', $edit, t('Log in'), array('external' => FALSE));
- // Check that we remain on the site after login.
- $this->assertEqual(url('user/' . $user->uid, array('absolute' => TRUE)), $this->getUrl(), 'Redirected to user profile page after login from the frontpage');
- }
-
- /**
- * Test the Who's Online block.
- */
- function testWhosOnlineBlock() {
- // Generate users and make sure there are no current user sessions.
- $user1 = $this->drupalCreateUser(array());
- $user2 = $this->drupalCreateUser(array());
- $user3 = $this->drupalCreateUser(array());
- $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions}")->fetchField(), 0, 'Sessions table is empty.');
-
- // Insert a user with two sessions.
- $this->insertSession(array('uid' => $user1->uid));
- $this->insertSession(array('uid' => $user1->uid));
- $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid", array(':uid' => $user1->uid))->fetchField(), 2, 'Duplicate user session has been inserted.');
-
- // Insert a user with only one session.
- $this->insertSession(array('uid' => $user2->uid, 'timestamp' => REQUEST_TIME + 1));
-
- // Insert an inactive logged-in user who should not be seen in the block.
- $this->insertSession(array('uid' => $user3->uid, 'timestamp' => (REQUEST_TIME - variable_get('user_block_seconds_online', 900) - 1)));
-
- // Insert two anonymous user sessions.
- $this->insertSession();
- $this->insertSession();
-
- // Test block output.
- $block = user_block_view('online');
- $this->drupalSetContent($block['content']);
- $this->assertRaw(t('2 users'), 'Correct number of online users (2 users).');
- $this->assertText($user1->name, 'Active user 1 found in online list.');
- $this->assertText($user2->name, 'Active user 2 found in online list.');
- $this->assertNoText($user3->name, "Inactive user not found in online list.");
- $this->assertTrue(strpos($this->drupalGetContent(), $user1->name) > strpos($this->drupalGetContent(), $user2->name), 'Online users are ordered correctly.');
- }
-
- /**
- * Insert a user session into the {sessions} table. This function is used
- * since we cannot log in more than one user at the same time in tests.
- */
- private function insertSession(array $fields = array()) {
- $fields += array(
- 'uid' => 0,
- 'sid' => drupal_hash_base64(uniqid(mt_rand(), TRUE)),
- 'timestamp' => REQUEST_TIME,
- );
- db_insert('sessions')
- ->fields($fields)
- ->execute();
- $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid AND sid = :sid AND timestamp = :timestamp", array(':uid' => $fields['uid'], ':sid' => $fields['sid'], ':timestamp' => $fields['timestamp']))->fetchField(), 1, 'Session record inserted.');
- }
-}
-
-/**
- * Tests saving a user account.
- */
-class UserSaveTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User save test',
- 'description' => 'Test user_save() for arbitrary new uid.',
- 'group' => 'User',
- );
- }
-
- /**
- * Test creating a user with arbitrary uid.
- */
- function testUserImport() {
- // User ID must be a number that is not in the database.
- $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField();
- $test_uid = $max_uid + mt_rand(1000, 1000000);
- $test_name = $this->randomName();
-
- // Create the base user, based on drupalCreateUser().
- $user = array(
- 'name' => $test_name,
- 'uid' => $test_uid,
- 'mail' => $test_name . '@example.com',
- 'is_new' => TRUE,
- 'pass' => user_password(),
- 'status' => 1,
- );
- $user_by_return = user_save(drupal_anonymous_user(), $user);
- $this->assertTrue($user_by_return, 'Loading user by return of user_save().');
-
- // Test if created user exists.
- $user_by_uid = user_load($test_uid);
- $this->assertTrue($user_by_uid, 'Loading user by uid.');
-
- $user_by_name = user_load_by_name($test_name);
- $this->assertTrue($user_by_name, 'Loading user by name.');
- }
-}
-
-/**
- * Test the create user administration page.
- */
-class UserCreateTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User create',
- 'description' => 'Test the create user administration page.',
- 'group' => 'User',
- );
- }
-
- /**
- * Create a user through the administration interface and ensure that it
- * displays in the user list.
- */
- protected function testUserAdd() {
- $user = $this->drupalCreateUser(array('administer users'));
- $this->drupalLogin($user);
-
- foreach (array(FALSE, TRUE) as $notify) {
- $edit = array(
- 'name' => $this->randomName(),
- 'mail' => $this->randomName() . '@example.com',
- 'pass[pass1]' => $pass = $this->randomString(),
- 'pass[pass2]' => $pass,
- 'notify' => $notify,
- );
- $this->drupalPost('admin/people/create', $edit, t('Create new account'));
-
- if ($notify) {
- $this->assertText(t('A welcome message with further instructions has been e-mailed to the new user @name.', array('@name' => $edit['name'])), 'User created');
- $this->assertEqual(count($this->drupalGetMails()), 1, 'Notification e-mail sent');
- }
- else {
- $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created');
- $this->assertEqual(count($this->drupalGetMails()), 0, 'Notification e-mail not sent');
- }
-
- $this->drupalGet('admin/people');
- $this->assertText($edit['name'], 'User found in list of users');
- }
- }
-}
-
-/**
- * Tests editing a user account.
- */
-class UserEditTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User edit',
- 'description' => 'Test user edit page.',
- 'group' => 'User',
- );
- }
-
- /**
- * Test user edit page.
- */
- function testUserEdit() {
- // Test user edit functionality with user pictures disabled.
- variable_set('user_pictures', 0);
- $user1 = $this->drupalCreateUser(array('change own username'));
- $user2 = $this->drupalCreateUser(array());
- $this->drupalLogin($user1);
-
- // Test that error message appears when attempting to use a non-unique user name.
- $edit['name'] = $user2->name;
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
-
- // Repeat the test with user pictures enabled, which modifies the form.
- variable_set('user_pictures', 1);
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name'])));
-
- // Check that filling out a single password field does not validate.
- $edit = array();
- $edit['pass[pass1]'] = '';
- $edit['pass[pass2]'] = $this->randomName();
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
-
- $edit['pass[pass1]'] = $this->randomName();
- $edit['pass[pass2]'] = '';
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
-
- // Test that the error message appears when attempting to change the mail or
- // pass without the current password.
- $edit = array();
- $edit['mail'] = $this->randomName() . '@new.example.com';
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('E-mail address'))));
-
- $edit['current_pass'] = $user1->pass_raw;
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t("The changes have been saved."));
-
- // Test that the user must enter current password before changing passwords.
- $edit = array();
- $edit['pass[pass1]'] = $new_pass = $this->randomName();
- $edit['pass[pass2]'] = $new_pass;
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password'))));
-
- // Try again with the current password.
- $edit['current_pass'] = $user1->pass_raw;
- $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
- $this->assertRaw(t("The changes have been saved."));
-
- // Make sure the user can log in with their new password.
- $this->drupalLogout();
- $user1->pass_raw = $new_pass;
- $this->drupalLogin($user1);
- $this->drupalLogout();
- }
-}
-
-/**
- * Test case for user signatures.
- */
-class UserSignatureTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User signatures',
- 'description' => 'Test user signatures.',
- 'group' => 'User',
- );
- }
-
- function setUp() {
- parent::setUp('comment');
-
- // Enable user signatures.
- variable_set('user_signatures', 1);
-
- // Prefetch text formats.
- $this->full_html_format = filter_format_load('full_html');
- $this->plain_text_format = filter_format_load('plain_text');
-
- // Create regular and administrative users.
- $this->web_user = $this->drupalCreateUser(array());
- $admin_permissions = array('administer comments');
- foreach (filter_formats() as $format) {
- if ($permission = filter_permission_name($format)) {
- $admin_permissions[] = $permission;
- }
- }
- $this->admin_user = $this->drupalCreateUser($admin_permissions);
- }
-
- /**
- * Test that a user can change their signature format and that it is respected
- * upon display.
- */
- function testUserSignature() {
- // Create a new node with comments on.
- $node = $this->drupalCreateNode(array('comment' => COMMENT_NODE_OPEN));
-
- // Verify that user signature field is not displayed on registration form.
- $this->drupalGet('user/register');
- $this->assertNoText(t('Signature'));
-
- // Log in as a regular user and create a signature.
- $this->drupalLogin($this->web_user);
- $signature_text = "" . $this->randomName() . " ";
- $edit = array(
- 'signature[value]' => $signature_text,
- 'signature[format]' => $this->plain_text_format->format,
- );
- $this->drupalPost('user/' . $this->web_user->uid . '/edit', $edit, t('Save'));
-
- // Verify that values were stored.
- $this->assertFieldByName('signature[value]', $edit['signature[value]'], 'Submitted signature text found.');
- $this->assertFieldByName('signature[format]', $edit['signature[format]'], 'Submitted signature format found.');
-
- // Create a comment.
- $langcode = LANGUAGE_NONE;
- $edit = array();
- $edit['subject'] = $this->randomName(8);
- $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
- $this->drupalPost(NULL, array(), t('Save'));
-
- // Get the comment ID. (This technique is the same one used in the Comment
- // module's CommentHelperCase test case.)
- preg_match('/#comment-([0-9]+)/', $this->getURL(), $match);
- $comment_id = $match[1];
-
- // Log in as an administrator and edit the comment to use Full HTML, so
- // that the comment text itself is not filtered at all.
- $this->drupalLogin($this->admin_user);
- $edit['comment_body[' . $langcode . '][0][format]'] = $this->full_html_format->format;
- $this->drupalPost('comment/' . $comment_id . '/edit', $edit, t('Save'));
-
- // Assert that the signature did not make it through unfiltered.
- $this->drupalGet('node/' . $node->nid);
- $this->assertNoRaw($signature_text, 'Unfiltered signature text not found.');
- $this->assertRaw(check_markup($signature_text, $this->plain_text_format->format), 'Filtered signature text found.');
- }
-}
-
-/*
- * Test that a user, having editing their own account, can still log in.
- */
-class UserEditedOwnAccountTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User edited own account',
- 'description' => 'Test user edited own account can still log in.',
- 'group' => 'User',
- );
- }
-
- function testUserEditedOwnAccount() {
- // Change account setting 'Who can register accounts?' to Administrators
- // only.
- variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY);
-
- // Create a new user account and log in.
- $account = $this->drupalCreateUser(array('change own username'));
- $this->drupalLogin($account);
-
- // Change own username.
- $edit = array();
- $edit['name'] = $this->randomName();
- $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save'));
-
- // Log out.
- $this->drupalLogout();
-
- // Set the new name on the user account and attempt to log back in.
- $account->name = $edit['name'];
- $this->drupalLogin($account);
- }
-}
-
-/**
- * Test case to test adding, editing and deleting roles.
- */
-class UserRoleAdminTestCase extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User role administration',
- 'description' => 'Test adding, editing and deleting user roles and changing role weights.',
- 'group' => 'User',
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
- }
-
- /**
- * Test adding, renaming and deleting roles.
- */
- function testRoleAdministration() {
- $this->drupalLogin($this->admin_user);
-
- // Test adding a role. (In doing so, we use a role name that happens to
- // correspond to an integer, to test that the role administration pages
- // correctly distinguish between role names and IDs.)
- $role_name = '123';
- $edit = array('name' => $role_name);
- $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
- $this->assertText(t('The role has been added.'), 'The role has been added.');
- $role = user_role_load_by_name($role_name);
- $this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
-
- // Try adding a duplicate role.
- $this->drupalPost(NULL, $edit, t('Add role'));
- $this->assertRaw(t('The role name %name already exists. Choose another role name.', array('%name' => $role_name)), 'Duplicate role warning displayed.');
-
- // Test renaming a role.
- $old_name = $role_name;
- $role_name = '456';
- $edit = array('name' => $role_name);
- $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", $edit, t('Save role'));
- $this->assertText(t('The role has been renamed.'), 'The role has been renamed.');
- $this->assertFalse(user_role_load_by_name($old_name), 'The role can no longer be retrieved from the database using its old name.');
- $this->assertTrue(is_object(user_role_load_by_name($role_name)), 'The role can be retrieved from the database using its new name.');
-
- // Test deleting a role.
- $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", NULL, t('Delete role'));
- $this->drupalPost(NULL, NULL, t('Delete'));
- $this->assertText(t('The role has been deleted.'), 'The role has been deleted');
- $this->assertNoLinkByHref("admin/people/permissions/roles/edit/{$role->rid}", 'Role edit link removed.');
- $this->assertFalse(user_role_load_by_name($role_name), 'A deleted role can no longer be loaded.');
-
- // Make sure that the system-defined roles cannot be edited via the user
- // interface.
- $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_ANONYMOUS_RID);
- $this->assertResponse(403, 'Access denied when trying to edit the built-in anonymous role.');
- $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_AUTHENTICATED_RID);
- $this->assertResponse(403, 'Access denied when trying to edit the built-in authenticated role.');
- }
-
- /**
- * Test user role weight change operation.
- */
- function testRoleWeightChange() {
- $this->drupalLogin($this->admin_user);
-
- // Pick up a random role and get its weight.
- $rid = array_rand(user_roles());
- $role = user_role_load($rid);
- $old_weight = $role->weight;
-
- // Change the role weight and submit the form.
- $edit = array('roles['. $rid .'][weight]' => $old_weight + 1);
- $this->drupalPost('admin/people/permissions/roles', $edit, t('Save order'));
- $this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
-
- // Retrieve the saved role and compare its weight.
- $role = user_role_load($rid);
- $new_weight = $role->weight;
- $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.');
- }
-}
-
-/**
- * Test user token replacement in strings.
- */
-class UserTokenReplaceTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User token replacement',
- 'description' => 'Generates text using placeholders for dummy content to check user token replacement.',
- 'group' => 'User',
- );
- }
-
- /**
- * Creates a user, then tests the tokens generated from it.
- */
- function testUserTokenReplacement() {
- global $language;
- $url_options = array(
- 'absolute' => TRUE,
- 'language' => $language,
- );
-
- // Create two users and log them in one after another.
- $user1 = $this->drupalCreateUser(array());
- $user2 = $this->drupalCreateUser(array());
- $this->drupalLogin($user1);
- $this->drupalLogout();
- $this->drupalLogin($user2);
-
- $account = user_load($user1->uid);
- $global_account = user_load($GLOBALS['user']->uid);
-
- // Generate and test sanitized tokens.
- $tests = array();
- $tests['[user:uid]'] = $account->uid;
- $tests['[user:name]'] = check_plain(format_username($account));
- $tests['[user:mail]'] = check_plain($account->mail);
- $tests['[user:url]'] = url("user/$account->uid", $url_options);
- $tests['[user:edit-url]'] = url("user/$account->uid/edit", $url_options);
- $tests['[user:last-login]'] = format_date($account->login, 'medium', '', NULL, $language->language);
- $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language);
- $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language);
- $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language);
- $tests['[current-user:name]'] = check_plain(format_username($global_account));
-
- // Test to make sure that we generated something for each token.
- $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('user' => $account), array('language' => $language));
- $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input)));
- }
-
- // Generate and test unsanitized tokens.
- $tests['[user:name]'] = format_username($account);
- $tests['[user:mail]'] = $account->mail;
- $tests['[current-user:name]'] = format_username($global_account);
-
- foreach ($tests as $input => $expected) {
- $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE));
- $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input)));
- }
- }
-}
-
-/**
- * Test user search.
- */
-class UserUserSearchTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'User search',
- 'description' => 'Tests the user search page and verifies that sensitive information is hidden from unauthorized users.',
- 'group' => 'User',
- );
- }
-
- function testUserSearch() {
- $user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search'));
- $this->drupalLogin($user1);
- $keys = $user1->mail;
- $edit = array('keys' => $keys);
- $this->drupalPost('search/user/', $edit, t('Search'));
- $this->assertNoText($keys);
- $this->drupalLogout();
-
- $user2 = $this->drupalCreateUser(array('administer users', 'access user profiles', 'search content', 'use advanced search'));
- $this->drupalLogin($user2);
- $keys = $user2->mail;
- $edit = array('keys' => $keys);
- $this->drupalPost('search/user/', $edit, t('Search'));
- $this->assertText($keys);
-
- // Create a blocked user.
- $blocked_user = $this->drupalCreateUser();
- $edit = array('status' => 0);
- $blocked_user = user_save($blocked_user, $edit);
-
- // Verify that users with "administer users" permissions can see blocked
- // accounts in search results.
- $edit = array('keys' => $blocked_user->name);
- $this->drupalPost('search/user/', $edit, t('Search'));
- $this->assertText($blocked_user->name, 'Blocked users are listed on the user search results for users with the "administer users" permission.');
-
- // Verify that users without "administer users" permissions do not see
- // blocked accounts in search results.
- $this->drupalLogin($user1);
- $edit = array('keys' => $blocked_user->name);
- $this->drupalPost('search/user/', $edit, t('Search'));
- $this->assertNoText($blocked_user->name, 'Blocked users are hidden from the user search results.');
-
- $this->drupalLogout();
- }
-}
-
-/**
- * Test role assignment.
- */
-class UserRolesAssignmentTestCase extends DrupalWebTestCase {
- protected $admin_user;
-
- public static function getInfo() {
- return array(
- 'name' => 'Role assignment',
- 'description' => 'Tests that users can be assigned and unassigned roles.',
- 'group' => 'User'
- );
- }
-
- function setUp() {
- parent::setUp();
- $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users'));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Tests that a user can be assigned a role and that the role can be removed
- * again.
- */
- function testAssignAndRemoveRole() {
- $rid = $this->drupalCreateRole(array('administer content types'));
- $account = $this->drupalCreateUser();
-
- // Assign the role to the user.
- $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => $rid), t('Save'));
- $this->assertText(t('The changes have been saved.'));
- $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
- $this->userLoadAndCheckRoleAssigned($account, $rid);
-
- // Remove the role from the user.
- $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
- $this->assertText(t('The changes have been saved.'));
- $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
- $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
- }
-
- /**
- * Tests that when creating a user the role can be assigned. And that it can
- * be removed again.
- */
- function testCreateUserWithRole() {
- $rid = $this->drupalCreateRole(array('administer content types'));
- // Create a new user and add the role at the same time.
- $edit = array(
- 'name' => $this->randomName(),
- 'mail' => $this->randomName() . '@example.com',
- 'pass[pass1]' => $pass = $this->randomString(),
- 'pass[pass2]' => $pass,
- "roles[$rid]" => $rid,
- );
- $this->drupalPost('admin/people/create', $edit, t('Create new account'));
- $this->assertText(t('Created a new user account for !name.', array('!name' => $edit['name'])));
- // Get the newly added user.
- $account = user_load_by_name($edit['name']);
-
- $this->drupalGet('user/' . $account->uid . '/edit');
- $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
- $this->userLoadAndCheckRoleAssigned($account, $rid);
-
- // Remove the role again.
- $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save'));
- $this->assertText(t('The changes have been saved.'));
- $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
- $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
- }
-
- /**
- * Check role on user object.
- *
- * @param object $account
- * The user account to check.
- * @param string $rid
- * The role ID to search for.
- * @param bool $is_assigned
- * (optional) Whether to assert that $rid exists (TRUE) or not (FALSE).
- * Defaults to TRUE.
- */
- private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) {
- $account = user_load($account->uid, TRUE);
- if ($is_assigned) {
- $this->assertTrue(array_key_exists($rid, $account->roles), 'The role is present in the user object.');
- }
- else {
- $this->assertFalse(array_key_exists($rid, $account->roles), 'The role is not present in the user object.');
- }
- }
-}
-
-
-/**
- * Unit test for authmap assignment.
- */
-class UserAuthmapAssignmentTestCase extends DrupalWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Authmap assignment',
- 'description' => 'Tests that users can be assigned and unassigned authmaps.',
- 'group' => 'User'
- );
- }
-
- /**
- * Test authmap assignment and retrieval.
- */
- function testAuthmapAssignment() {
- $account = $this->drupalCreateUser();
-
- // Assign authmaps to the user.
- $authmaps = array(
- 'authname_poll' => 'external username one',
- 'authname_book' => 'external username two',
- );
- user_set_authmaps($account, $authmaps);
-
- // Test for expected authmaps.
- $expected_authmaps = array(
- 'external username one' => array(
- 'poll' => 'external username one',
- ),
- 'external username two' => array(
- 'book' => 'external username two',
- ),
- );
- foreach ($expected_authmaps as $authname => $expected_output) {
- $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
- }
-
- // Remove authmap for module poll, add authmap for module blog.
- $authmaps = array(
- 'authname_poll' => NULL,
- 'authname_blog' => 'external username three',
- );
- user_set_authmaps($account, $authmaps);
-
- // Assert that external username one does not have authmaps.
- $remove_username = 'external username one';
- unset($expected_authmaps[$remove_username]);
- $this->assertFalse(user_get_authmaps($remove_username), format_string('Authmap for %authname was removed.', array('%authname' => $remove_username)));
-
- // Assert that a new authmap was created for external username three, and
- // existing authmaps for external username two were unchanged.
- $expected_authmaps['external username three'] = array('blog' => 'external username three');
- foreach ($expected_authmaps as $authname => $expected_output) {
- $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname)));
- }
- }
-}
-
-/**
- * Tests user_validate_current_pass on a custom form.
- */
-class UserValidateCurrentPassCustomForm extends DrupalWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => 'User validate current pass custom form',
- 'description' => 'Test that user_validate_current_pass is usable on a custom form.',
- 'group' => 'User',
- );
- }
-
- /**
- * User with permission to view content.
- */
- protected $accessUser;
-
- /**
- * User permission to administer users.
- */
- protected $adminUser;
-
- function setUp() {
- parent::setUp('user_form_test');
- // Create two users
- $this->accessUser = $this->drupalCreateUser(array('access content'));
- $this->adminUser = $this->drupalCreateUser(array('administer users'));
- }
-
- /**
- * Tests that user_validate_current_pass can be reused on a custom form.
- */
- function testUserValidateCurrentPassCustomForm() {
- $this->drupalLogin($this->adminUser);
-
- // Submit the custom form with the admin user using the access user's password.
- $edit = array();
- $edit['user_form_test_field'] = $this->accessUser->name;
- $edit['current_pass'] = $this->accessUser->pass_raw;
- $this->drupalPost('user_form_test_current_password/' . $this->accessUser->uid, $edit, t('Test'));
- $this->assertText(t('The password has been validated and the form submitted successfully.'));
- }
-}
diff --git a/modules/user/user.tokens.inc b/modules/user/user.tokens.inc
deleted file mode 100644
index 8dcea4b5..00000000
--- a/modules/user/user.tokens.inc
+++ /dev/null
@@ -1,131 +0,0 @@
- t('Users'),
- 'description' => t('Tokens related to individual user accounts.'),
- 'needs-data' => 'user',
- );
- $types['current-user'] = array(
- 'name' => t('Current user'),
- 'description' => t('Tokens related to the currently logged in user.'),
- 'type' => 'user',
- );
-
- $user['uid'] = array(
- 'name' => t('User ID'),
- 'description' => t("The unique ID of the user account."),
- );
- $user['name'] = array(
- 'name' => t("Name"),
- 'description' => t("The login name of the user account."),
- );
- $user['mail'] = array(
- 'name' => t("Email"),
- 'description' => t("The email address of the user account."),
- );
- $user['url'] = array(
- 'name' => t("URL"),
- 'description' => t("The URL of the account profile page."),
- );
- $user['edit-url'] = array(
- 'name' => t("Edit URL"),
- 'description' => t("The URL of the account edit page."),
- );
-
- $user['last-login'] = array(
- 'name' => t("Last login"),
- 'description' => t("The date the user last logged in to the site."),
- 'type' => 'date',
- );
- $user['created'] = array(
- 'name' => t("Created"),
- 'description' => t("The date the user account was created."),
- 'type' => 'date',
- );
-
- return array(
- 'types' => $types,
- 'tokens' => array('user' => $user),
- );
-}
-
-/**
- * Implements hook_tokens().
- */
-function user_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $url_options = array('absolute' => TRUE);
- if (isset($options['language'])) {
- $url_options['language'] = $options['language'];
- $language_code = $options['language']->language;
- }
- else {
- $language_code = NULL;
- }
- $sanitize = !empty($options['sanitize']);
-
- $replacements = array();
-
- if ($type == 'user' && !empty($data['user'])) {
- $account = $data['user'];
- foreach ($tokens as $name => $original) {
- switch ($name) {
- // Basic user account information.
- case 'uid':
- // In the case of hook user_presave uid is not set yet.
- $replacements[$original] = !empty($account->uid) ? $account->uid : t('not yet assigned');
- break;
-
- case 'name':
- $name = format_username($account);
- $replacements[$original] = $sanitize ? check_plain($name) : $name;
- break;
-
- case 'mail':
- $replacements[$original] = $sanitize ? check_plain($account->mail) : $account->mail;
- break;
-
- case 'url':
- $replacements[$original] = !empty($account->uid) ? url("user/$account->uid", $url_options) : t('not yet assigned');
- break;
-
- case 'edit-url':
- $replacements[$original] = !empty($account->uid) ? url("user/$account->uid/edit", $url_options) : t('not yet assigned');
- break;
-
- // These tokens are default variations on the chained tokens handled below.
- case 'last-login':
- $replacements[$original] = !empty($account->login) ? format_date($account->login, 'medium', '', NULL, $language_code) : t('never');
- break;
-
- case 'created':
- // In the case of user_presave the created date may not yet be set.
- $replacements[$original] = !empty($account->created) ? format_date($account->created, 'medium', '', NULL, $language_code) : t('not yet created');
- break;
- }
- }
-
- if ($login_tokens = token_find_with_prefix($tokens, 'last-login')) {
- $replacements += token_generate('date', $login_tokens, array('date' => $account->login), $options);
- }
-
- if ($registered_tokens = token_find_with_prefix($tokens, 'created')) {
- $replacements += token_generate('date', $registered_tokens, array('date' => $account->created), $options);
- }
- }
-
- if ($type == 'current-user') {
- $account = user_load($GLOBALS['user']->uid);
- $replacements += token_generate('user', $tokens, array('user' => $account), $options);
- }
-
- return $replacements;
-}
diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info
deleted file mode 100644
index 30551407..00000000
--- a/profiles/minimal/minimal.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = Minimal
-description = Start with only a few modules enabled.
-version = VERSION
-core = 7.x
-dependencies[] = block
-dependencies[] = dblog
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/profiles/minimal/minimal.install b/profiles/minimal/minimal.install
deleted file mode 100644
index 9cf4fa2f..00000000
--- a/profiles/minimal/minimal.install
+++ /dev/null
@@ -1,81 +0,0 @@
- 'system',
- 'delta' => 'main',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'content',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'user',
- 'delta' => 'login',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'navigation',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'management',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 1,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'help',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'help',
- 'pages' => '',
- 'cache' => -1,
- ),
- );
- $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
- foreach ($values as $record) {
- $query->values($record);
- }
- $query->execute();
-
- // Allow visitor account creation, but with administrative approval.
- variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
-
- // Enable default permissions for system roles.
- user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access content'));
- user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access content'));
-}
diff --git a/profiles/minimal/minimal.profile b/profiles/minimal/minimal.profile
deleted file mode 100644
index fe6da8c3..00000000
--- a/profiles/minimal/minimal.profile
+++ /dev/null
@@ -1,15 +0,0 @@
- 'filtered_html',
- 'name' => 'Filtered HTML',
- 'weight' => 0,
- 'filters' => array(
- // URL filter.
- 'filter_url' => array(
- 'weight' => 0,
- 'status' => 1,
- ),
- // HTML filter.
- 'filter_html' => array(
- 'weight' => 1,
- 'status' => 1,
- ),
- // Line break filter.
- 'filter_autop' => array(
- 'weight' => 2,
- 'status' => 1,
- ),
- // HTML corrector filter.
- 'filter_htmlcorrector' => array(
- 'weight' => 10,
- 'status' => 1,
- ),
- ),
- );
- $filtered_html_format = (object) $filtered_html_format;
- filter_format_save($filtered_html_format);
-
- $full_html_format = array(
- 'format' => 'full_html',
- 'name' => 'Full HTML',
- 'weight' => 1,
- 'filters' => array(
- // URL filter.
- 'filter_url' => array(
- 'weight' => 0,
- 'status' => 1,
- ),
- // Line break filter.
- 'filter_autop' => array(
- 'weight' => 1,
- 'status' => 1,
- ),
- // HTML corrector filter.
- 'filter_htmlcorrector' => array(
- 'weight' => 10,
- 'status' => 1,
- ),
- ),
- );
- $full_html_format = (object) $full_html_format;
- filter_format_save($full_html_format);
-
- // Enable some standard blocks.
- $default_theme = variable_get('theme_default', 'bartik');
- $admin_theme = 'seven';
- $blocks = array(
- array(
- 'module' => 'system',
- 'delta' => 'main',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'content',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'search',
- 'delta' => 'form',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => -1,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'node',
- 'delta' => 'recent',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => 10,
- 'region' => 'dashboard_main',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'user',
- 'delta' => 'login',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'navigation',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'sidebar_first',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'powered-by',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 10,
- 'region' => 'footer',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'help',
- 'theme' => $default_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'help',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'main',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'content',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'system',
- 'delta' => 'help',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'help',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'user',
- 'delta' => 'login',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => 10,
- 'region' => 'content',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'user',
- 'delta' => 'new',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => 0,
- 'region' => 'dashboard_sidebar',
- 'pages' => '',
- 'cache' => -1,
- ),
- array(
- 'module' => 'search',
- 'delta' => 'form',
- 'theme' => $admin_theme,
- 'status' => 1,
- 'weight' => -10,
- 'region' => 'dashboard_sidebar',
- 'pages' => '',
- 'cache' => -1,
- ),
- );
- $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
- foreach ($blocks as $block) {
- $query->values($block);
- }
- $query->execute();
-
- // Insert default pre-defined node types into the database. For a complete
- // list of available node type attributes, refer to the node type API
- // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
- $types = array(
- array(
- 'type' => 'page',
- 'name' => st('Basic page'),
- 'base' => 'node_content',
- 'description' => st("Use basic pages for your static content, such as an 'About us' page."),
- 'custom' => 1,
- 'modified' => 1,
- 'locked' => 0,
- ),
- array(
- 'type' => 'article',
- 'name' => st('Article'),
- 'base' => 'node_content',
- 'description' => st('Use articles for time-sensitive content like news, press releases or blog posts.'),
- 'custom' => 1,
- 'modified' => 1,
- 'locked' => 0,
- ),
- );
-
- foreach ($types as $type) {
- $type = node_type_set_defaults($type);
- node_type_save($type);
- node_add_body_field($type);
- }
-
- // Insert default pre-defined RDF mapping into the database.
- $rdf_mappings = array(
- array(
- 'type' => 'node',
- 'bundle' => 'page',
- 'mapping' => array(
- 'rdftype' => array('foaf:Document'),
- ),
- ),
- array(
- 'type' => 'node',
- 'bundle' => 'article',
- 'mapping' => array(
- 'field_image' => array(
- 'predicates' => array('og:image', 'rdfs:seeAlso'),
- 'type' => 'rel',
- ),
- 'field_tags' => array(
- 'predicates' => array('dc:subject'),
- 'type' => 'rel',
- ),
- ),
- ),
- );
- foreach ($rdf_mappings as $rdf_mapping) {
- rdf_mapping_save($rdf_mapping);
- }
-
- // Default "Basic page" to not be promoted and have comments disabled.
- variable_set('node_options_page', array('status'));
- variable_set('comment_page', COMMENT_NODE_HIDDEN);
-
- // Don't display date and author information for "Basic page" nodes by default.
- variable_set('node_submitted_page', FALSE);
-
- // Enable user picture support and set the default to a square thumbnail option.
- variable_set('user_pictures', '1');
- variable_set('user_picture_dimensions', '1024x1024');
- variable_set('user_picture_file_size', '800');
- variable_set('user_picture_style', 'thumbnail');
-
- // Allow visitor account creation with administrative approval.
- variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
-
- // Create a default vocabulary named "Tags", enabled for the 'article' content type.
- $description = st('Use tags to group articles on similar topics into categories.');
- $vocabulary = (object) array(
- 'name' => st('Tags'),
- 'description' => $description,
- 'machine_name' => 'tags',
- );
- taxonomy_vocabulary_save($vocabulary);
-
- $field = array(
- 'field_name' => 'field_' . $vocabulary->machine_name,
- 'type' => 'taxonomy_term_reference',
- // Set cardinality to unlimited for tagging.
- 'cardinality' => FIELD_CARDINALITY_UNLIMITED,
- 'settings' => array(
- 'allowed_values' => array(
- array(
- 'vocabulary' => $vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($field);
-
- $help = st('Enter a comma-separated list of words to describe your content.');
- $instance = array(
- 'field_name' => 'field_' . $vocabulary->machine_name,
- 'entity_type' => 'node',
- 'label' => 'Tags',
- 'bundle' => 'article',
- 'description' => $help,
- 'widget' => array(
- 'type' => 'taxonomy_autocomplete',
- 'weight' => -4,
- ),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- 'teaser' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- ),
- );
- field_create_instance($instance);
-
-
- // Create an image field named "Image", enabled for the 'article' content type.
- // Many of the following values will be defaulted, they're included here as an illustrative examples.
- // See http://api.drupal.org/api/function/field_create_field/7
-
- $field = array(
- 'field_name' => 'field_image',
- 'type' => 'image',
- 'cardinality' => 1,
- 'locked' => FALSE,
- 'indexes' => array('fid' => array('fid')),
- 'settings' => array(
- 'uri_scheme' => 'public',
- 'default_image' => FALSE,
- ),
- 'storage' => array(
- 'type' => 'field_sql_storage',
- 'settings' => array(),
- ),
- );
- field_create_field($field);
-
-
- // Many of the following values will be defaulted, they're included here as an illustrative examples.
- // See http://api.drupal.org/api/function/field_create_instance/7
- $instance = array(
- 'field_name' => 'field_image',
- 'entity_type' => 'node',
- 'label' => 'Image',
- 'bundle' => 'article',
- 'description' => st('Upload an image to go with this article.'),
- 'required' => FALSE,
-
- 'settings' => array(
- 'file_directory' => 'field/image',
- 'file_extensions' => 'png gif jpg jpeg',
- 'max_filesize' => '',
- 'max_resolution' => '',
- 'min_resolution' => '',
- 'alt_field' => TRUE,
- 'title_field' => '',
- ),
-
- 'widget' => array(
- 'type' => 'image_image',
- 'settings' => array(
- 'progress_indicator' => 'throbber',
- 'preview_image_style' => 'thumbnail',
- ),
- 'weight' => -1,
- ),
-
- 'display' => array(
- 'default' => array(
- 'label' => 'hidden',
- 'type' => 'image',
- 'settings' => array('image_style' => 'large', 'image_link' => ''),
- 'weight' => -1,
- ),
- 'teaser' => array(
- 'label' => 'hidden',
- 'type' => 'image',
- 'settings' => array('image_style' => 'medium', 'image_link' => 'content'),
- 'weight' => -1,
- ),
- ),
- );
- field_create_instance($instance);
-
- // Enable default permissions for system roles.
- $filtered_html_permission = filter_permission_name($filtered_html_format);
- user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access content', 'access comments', $filtered_html_permission));
- user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'skip comment approval', $filtered_html_permission));
-
- // Create a default role for site administrators, with all available permissions assigned.
- $admin_role = new stdClass();
- $admin_role->name = 'administrator';
- $admin_role->weight = 2;
- user_role_save($admin_role);
- user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));
- // Set this as the administrator role.
- variable_set('user_admin_role', $admin_role->rid);
-
- // Assign user 1 the "administrator" role.
- db_insert('users_roles')
- ->fields(array('uid' => 1, 'rid' => $admin_role->rid))
- ->execute();
-
- // Create a Home link in the main menu.
- $item = array(
- 'link_title' => st('Home'),
- 'link_path' => '',
- 'menu_name' => 'main-menu',
- );
- menu_link_save($item);
-
- // Update the menu router information.
- menu_rebuild();
-
- // Enable the admin theme.
- db_update('system')
- ->fields(array('status' => 1))
- ->condition('type', 'theme')
- ->condition('name', 'seven')
- ->execute();
- variable_set('admin_theme', 'seven');
- variable_set('node_admin_theme', '1');
-}
diff --git a/profiles/standard/standard.profile b/profiles/standard/standard.profile
deleted file mode 100644
index d554c937..00000000
--- a/profiles/standard/standard.profile
+++ /dev/null
@@ -1,15 +0,0 @@
- 'Installation profile module tests helper',
- 'description' => 'Verifies that tests in installation profile modules are found and may use another profile for running tests.',
- 'group' => 'Installation profile',
- );
- }
-
- function setUp() {
- // Attempt to install a module in Testing profile, while this test runs with
- // a different profile.
- parent::setUp(array('drupal_system_listing_compatible_test'));
- }
-
- /**
- * Non-empty test* method required to executed the test case class.
- */
- function testDrupalSystemListing() {
- $this->pass(__CLASS__ . ' test executed.');
- }
-}
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
deleted file mode 100644
index e805fb4e..00000000
--- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info
+++ /dev/null
@@ -1,15 +0,0 @@
-name = "Drupal system listing incompatible test"
-description = "Support module for testing the drupal_system_listing function."
-package = Testing
-version = VERSION
-; This deliberately has the wrong core version, to test that it does not take
-; precedence over the version of the same module that is in the
-; modules/simpletest/tests directory.
-core = 6.x
-hidden = TRUE
-
-; Information added by Drupal.org packaging script on 2014-01-15
-version = "7.26"
-project = "drupal"
-datestamp = "1389815930"
-
diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
deleted file mode 100644
index b3d9bbc7..00000000
--- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.module
+++ /dev/null
@@ -1 +0,0 @@
- /dev/null 2>&1
diff --git a/scripts/drupal.sh b/scripts/drupal.sh
deleted file mode 100755
index 76bd750f..00000000
--- a/scripts/drupal.sh
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env php
-"
-Example: {$script} "http://mysite.org/node"
-
-All arguments are long options.
-
- --help This page.
-
- --root Set the working directory for the script to the specified path.
- To execute Drupal this has to be the root directory of your
- Drupal installation, f.e. /home/www/foo/drupal (assuming Drupal
- running on Unix). Current directory is not required.
- Use surrounding quotation marks on Windows.
-
- --verbose This option displays the options as they are set, but will
- produce errors from setting the session.
-
- URI The URI to execute, i.e. http://default/foo/bar for executing
- the path '/foo/bar' in your site 'default'. URI has to be
- enclosed by quotation marks if there are ampersands in it
- (f.e. index.php?q=node&foo=bar). Prefix 'http://' is required,
- and the domain must exist in Drupal's sites-directory.
-
- If the given path and file exists it will be executed directly,
- i.e. if URI is set to http://default/bar/foo.php
- and bar/foo.php exists, this script will be executed without
- bootstrapping Drupal. To execute Drupal's cron.php, specify
- http://default/cron.php as the URI.
-
-
-To run this script without --root argument invoke it from the root directory
-of your Drupal installation with
-
- ./scripts/{$script}
-\n
-EOF;
- exit;
-}
-
-// define default settings
-$cmd = 'index.php';
-$_SERVER['HTTP_HOST'] = 'default';
-$_SERVER['PHP_SELF'] = '/index.php';
-$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
-$_SERVER['SERVER_SOFTWARE'] = NULL;
-$_SERVER['REQUEST_METHOD'] = 'GET';
-$_SERVER['QUERY_STRING'] = '';
-$_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = '/';
-$_SERVER['HTTP_USER_AGENT'] = 'console';
-
-// toggle verbose mode
-if (in_array('--verbose', $_SERVER['argv'])) {
- $_verbose_mode = true;
-}
-else {
- $_verbose_mode = false;
-}
-
-// parse invocation arguments
-while ($param = array_shift($_SERVER['argv'])) {
- switch ($param) {
- case '--root':
- // change working directory
- $path = array_shift($_SERVER['argv']);
- if (is_dir($path)) {
- chdir($path);
- if ($_verbose_mode) {
- echo "cwd changed to: {$path}\n";
- }
- }
- else {
- echo "\nERROR: {$path} not found.\n\n";
- }
- break;
-
- default:
- if (substr($param, 0, 2) == '--') {
- // ignore unknown options
- break;
- }
- else {
- // parse the URI
- $path = parse_url($param);
-
- // set site name
- if (isset($path['host'])) {
- $_SERVER['HTTP_HOST'] = $path['host'];
- }
-
- // set query string
- if (isset($path['query'])) {
- $_SERVER['QUERY_STRING'] = $path['query'];
- parse_str($path['query'], $_GET);
- $_REQUEST = $_GET;
- }
-
- // set file to execute or Drupal path (clean URLs enabled)
- if (isset($path['path']) && file_exists(substr($path['path'], 1))) {
- $_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = $path['path'];
- $cmd = substr($path['path'], 1);
- }
- elseif (isset($path['path'])) {
- if (!isset($_GET['q'])) {
- $_REQUEST['q'] = $_GET['q'] = $path['path'];
- }
- }
-
- // display setup in verbose mode
- if ($_verbose_mode) {
- echo "Hostname set to: {$_SERVER['HTTP_HOST']}\n";
- echo "Script name set to: {$cmd}\n";
- echo "Path set to: {$_GET['q']}\n";
- }
- }
- break;
- }
-}
-
-if (file_exists($cmd)) {
- include $cmd;
-}
-else {
- echo "\nERROR: {$cmd} not found.\n\n";
-}
-exit();
diff --git a/scripts/dump-database-d6.sh b/scripts/dump-database-d6.sh
deleted file mode 100644
index 41146b07..00000000
--- a/scripts/dump-database-d6.sh
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env php
- $data) {
- // Remove descriptions to save time and code.
- unset($data['description']);
- foreach ($data['fields'] as &$field) {
- unset($field['description']);
- }
-
- // Dump the table structure.
- $output .= "db_create_table('" . $table . "', " . drupal_var_export($data) . ");\n";
-
- // Don't output values for those tables.
- if (substr($table, 0, 5) == 'cache' || $table == 'sessions' || $table == 'watchdog') {
- $output .= "\n";
- continue;
- }
-
- // Prepare the export of values.
- $result = db_query('SELECT * FROM {'. $table .'}');
- $insert = '';
- while ($record = db_fetch_array($result)) {
- // users.uid is a serial and inserting 0 into a serial can break MySQL.
- // So record uid + 1 instead of uid for every uid and once all records
- // are in place, fix them up.
- if ($table == 'users') {
- $record['uid']++;
- }
- $insert .= '->values('. drupal_var_export($record) .")\n";
- }
-
- // Dump the values if there are some.
- if ($insert) {
- $output .= "db_insert('". $table . "')->fields(". drupal_var_export(array_keys($data['fields'])) .")\n";
- $output .= $insert;
- $output .= "->execute();\n";
- }
-
- // Add the statement fixing the serial in the user table.
- if ($table == 'users') {
- $output .= "db_query('UPDATE {users} SET uid = uid - 1');\n";
- }
-
- $output .= "\n";
-}
-
-print $output;
diff --git a/scripts/dump-database-d7.sh b/scripts/dump-database-d7.sh
deleted file mode 100644
index 7692c40d..00000000
--- a/scripts/dump-database-d7.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env php
- $data) {
- // Remove descriptions to save time and code.
- unset($data['description']);
- foreach ($data['fields'] as &$field) {
- unset($field['description']);
- }
-
- // Dump the table structure.
- $output .= "db_create_table('" . $table . "', " . drupal_var_export($data) . ");\n";
-
- // Don't output values for those tables.
- if (substr($table, 0, 5) == 'cache' || $table == 'sessions' || $table == 'watchdog') {
- $output .= "\n";
- continue;
- }
-
- // Prepare the export of values.
- $result = db_query('SELECT * FROM {'. $table .'}', array(), array('fetch' => PDO::FETCH_ASSOC));
- $insert = '';
- foreach ($result as $record) {
- $insert .= '->values('. drupal_var_export($record) .")\n";
- }
-
- // Dump the values if there are some.
- if ($insert) {
- $output .= "db_insert('". $table . "')->fields(". drupal_var_export(array_keys($data['fields'])) .")\n";
- $output .= $insert;
- $output .= "->execute();\n";
- }
-
- $output .= "\n";
-}
-
-print $output;
diff --git a/scripts/generate-d6-content.sh b/scripts/generate-d6-content.sh
deleted file mode 100644
index fc4c68f9..00000000
--- a/scripts/generate-d6-content.sh
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/env php
- 11 ? array('page' => TRUE) : array();
- $vocabulary['multiple'] = $multiple[$i % 12];
- $vocabulary['required'] = $required[$i % 12];
- $vocabulary['relations'] = 1;
- $vocabulary['hierarchy'] = $hierarchy[$i % 12];
- $vocabulary['weight'] = $i;
- taxonomy_save_vocabulary($vocabulary);
- $parents = array();
- // Vocabularies without hierarchy get one term, single parent vocabularies get
- // one parent and one child term. Multiple parent vocabularies get three
- // terms: t0, t1, t2 where t0 is a parent of both t1 and t2.
- for ($j = 0; $j < $vocabulary['hierarchy'] + 1; $j++) {
- $term = array();
- $term['vid'] = $vocabulary['vid'];
- // For multiple parent vocabularies, omit the t0-t1 relation, otherwise
- // every parent in the vocabulary is a parent.
- $term['parent'] = $vocabulary['hierarchy'] == 2 && i == 1 ? array() : $parents;
- ++$term_id;
- $term['name'] = "term $term_id of vocabulary $voc_id (j=$j)";
- $term['description'] = 'description of ' . $term['name'];
- $term['weight'] = $i * 3 + $j;
- taxonomy_save_term($term);
- $terms[] = $term['tid'];
- $parents[] = $term['tid'];
- }
-}
-
-$node_id = 0;
-$revision_id = 0;
-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->uid = $uid;
- $node->type = $i < 12 ? 'page' : 'story';
- $node->sticky = 0;
- ++$node_id;
- ++$revision_id;
- $node->title = "node title $node_id rev $revision_id (i=$i)";
- $type = node_get_types('type', $node->type);
- if ($type->has_body) {
- $node->body = str_repeat("node body ($node->type) - $i", 100);
- $node->teaser = node_teaser($node->body);
- $node->filter = variable_get('filter_default_format', 1);
- $node->format = FILTER_FORMAT_DEFAULT;
- }
- $node->status = intval($i / 4) % 2;
- $node->language = '';
- $node->revision = $i < 12;
- $node->promote = $i % 2;
- $node->created = $now + $i * 86400;
- $node->log = "added $i node";
- // Make every term association different a little. For nodes with revisions,
- // make the initial revision have a different set of terms than the
- // newest revision.
- $node_terms = $terms;
- unset($node_terms[$i], $node_terms[47 - $i]);
- if ($node->revision) {
- $node->taxonomy = array($i => $terms[$i], 47-$i => $terms[47 - $i]);
- }
- else {
- $node->taxonomy = $node_terms;
- }
- node_save($node);
- path_set_alias("node/$node->nid", "content/$node->created");
- if ($node->revision) {
- $user = user_load($uid + 3);
- ++$revision_id;
- $node->title .= " rev2 $revision_id";
- $node->body = str_repeat("node revision body ($node->type) - $i", 100);
- $node->log = "added $i revision";
- $node->taxonomy = $node_terms;
- node_save($node);
- }
-}
-
-// Create poll content
-for ($i = 0; $i < 12; $i++) {
- $uid = intval($i / 4) + 3;
- $user = user_load($uid);
- $node = new stdClass();
- $node->uid = $uid;
- $node->type = 'poll';
- $node->sticky = 0;
- $node->title = "poll title $i";
- $type = node_get_types('type', $node->type);
- if ($type->has_body) {
- $node->body = str_repeat("node body ($node->type) - $i", 100);
- $node->teaser = node_teaser($node->body);
- $node->filter = variable_get('filter_default_format', 1);
- $node->format = FILTER_FORMAT_DEFAULT;
- }
- $node->status = intval($i / 2) % 2;
- $node->language = '';
- $node->revision = 1;
- $node->promote = $i % 2;
- $node->created = $now + $i * 43200;
- $node->log = "added $i poll";
-
- $nbchoices = ($i % 4) + 2;
- for ($c = 0; $c < $nbchoices; $c++) {
- $node->choice[] = array('chtext' => "Choice $c for poll $i");
- }
- node_save($node);
- path_set_alias("node/$node->nid", "content/poll/$i");
- path_set_alias("node/$node->nid/results", "content/poll/$i/results");
-
- // Add some votes
- for ($v = 0; $v < ($i % 4) + 5; $v++) {
- $c = $v % $nbchoices;
- $form_state = array();
- $form_state['values']['choice'] = $c;
- $form_state['values']['op'] = t('Vote');
- drupal_execute('poll_view_voting', $form_state, $node);
- }
-}
-
-$uid = 6;
-$user = user_load($uid);
-$node = new stdClass();
-$node->uid = $uid;
-$node->type = 'broken';
-$node->sticky = 0;
-$node->title = "node title 24";
-$node->body = str_repeat("node body ($node->type) - 37", 100);
-$node->teaser = node_teaser($node->body);
-$node->filter = variable_get('filter_default_format', 1);
-$node->format = FILTER_FORMAT_DEFAULT;
-$node->status = 1;
-$node->language = '';
-$node->revision = 0;
-$node->promote = 0;
-$node->created = 1263769200;
-$node->log = "added $i node";
-node_save($node);
-path_set_alias("node/$node->nid", "content/1263769200");
diff --git a/scripts/generate-d7-content.sh b/scripts/generate-d7-content.sh
deleted file mode 100644
index 1e1d13fa..00000000
--- a/scripts/generate-d7-content.sh
+++ /dev/null
@@ -1,320 +0,0 @@
-#!/usr/bin/env php
-fields(array('uid', 'name', 'pass', 'mail', 'status', 'created', 'access'));
-for ($i = 0; $i < 6; $i++) {
- $name = "test user $i";
- $pass = md5("test PassW0rd $i !(.)");
- $mail = "test$i@example.com";
- $now = mktime(0, 0, 0, 1, $i + 1, 2010);
- $query->values(array(db_next_id(), $name, user_hash_password($pass), $mail, 1, $now, $now));
-}
-$query->execute();
-
-// Create vocabularies and terms.
-
-if (module_exists('taxonomy')) {
- $terms = array();
-
- // All possible combinations of these vocabulary properties.
- $hierarchy = array(0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2);
- $multiple = array(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1);
- $required = array(0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1);
-
- $voc_id = 0;
- $term_id = 0;
- for ($i = 0; $i < 24; $i++) {
- $vocabulary = new stdClass;
- ++$voc_id;
- $vocabulary->name = "vocabulary $voc_id (i=$i)";
- $vocabulary->machine_name = 'vocabulary_' . $voc_id . '_' . $i;
- $vocabulary->description = "description of ". $vocabulary->name;
- $vocabulary->multiple = $multiple[$i % 12];
- $vocabulary->required = $required[$i % 12];
- $vocabulary->relations = 1;
- $vocabulary->hierarchy = $hierarchy[$i % 12];
- $vocabulary->weight = $i;
- taxonomy_vocabulary_save($vocabulary);
- $field = array(
- 'field_name' => 'taxonomy_'. $vocabulary->machine_name,
- 'module' => 'taxonomy',
- 'type' => 'taxonomy_term_reference',
- 'cardinality' => $vocabulary->multiple || $vocabulary->tags ? FIELD_CARDINALITY_UNLIMITED : 1,
- 'settings' => array(
- 'required' => $vocabulary->required ? TRUE : FALSE,
- 'allowed_values' => array(
- array(
- 'vocabulary' => $vocabulary->machine_name,
- 'parent' => 0,
- ),
- ),
- ),
- );
- field_create_field($field);
- $node_types = $i > 11 ? array('page') : array_keys(node_type_get_types());
- foreach ($node_types as $bundle) {
- $instance = array(
- 'label' => $vocabulary->name,
- 'field_name' => $field['field_name'],
- 'bundle' => $bundle,
- 'entity_type' => 'node',
- 'settings' => array(),
- 'description' => $vocabulary->help,
- 'required' => $vocabulary->required,
- 'widget' => array(),
- 'display' => array(
- 'default' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- 'teaser' => array(
- 'type' => 'taxonomy_term_reference_link',
- 'weight' => 10,
- ),
- ),
- );
- if ($vocabulary->tags) {
- $instance['widget'] = array(
- 'type' => 'taxonomy_autocomplete',
- 'module' => 'taxonomy',
- 'settings' => array(
- 'size' => 60,
- 'autocomplete_path' => 'taxonomy/autocomplete',
- ),
- );
- }
- else {
- $instance['widget'] = array(
- 'type' => 'options_select',
- 'settings' => array(),
- );
- }
- field_create_instance($instance);
- }
- $parents = array();
- // Vocabularies without hierarchy get one term; single parent vocabularies
- // get one parent and one child term. Multiple parent vocabularies get
- // three terms: t0, t1, t2 where t0 is a parent of both t1 and t2.
- for ($j = 0; $j < $vocabulary->hierarchy + 1; $j++) {
- $term = new stdClass;
- $term->vocabulary_machine_name = $vocabulary->machine_name;
- // For multiple parent vocabularies, omit the t0-t1 relation, otherwise
- // every parent in the vocabulary is a parent.
- $term->parent = $vocabulary->hierarchy == 2 && i == 1 ? array() : $parents;
- ++$term_id;
- $term->name = "term $term_id of vocabulary $voc_id (j=$j)";
- $term->description = 'description of ' . $term->name;
- $term->format = 'filtered_html';
- $term->weight = $i * 3 + $j;
- taxonomy_term_save($term);
- $terms[] = $term->tid;
- $term_vocabs[$term->tid] = 'taxonomy_' . $vocabulary->machine_name;
- $parents[] = $term->tid;
- }
- }
-}
-
-$node_id = 0;
-$revision_id = 0;
-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->uid = $uid;
- $node->type = $i < 12 ? 'page' : 'story';
- $node->sticky = 0;
- ++$node_id;
- ++$revision_id;
- $node->title = "node title $node_id rev $revision_id (i=$i)";
- $node->language = LANGUAGE_NONE;
- $body_text = str_repeat("node body ($node->type) - $i", 100);
- $node->body[$node->language][0]['value'] = $body_text;
- $node->body[$node->language][0]['summary'] = text_summary($body_text);
- $node->body[$node->language][0]['format'] = 'filtered_html';
- $node->status = intval($i / 4) % 2;
- $node->revision = $i < 12;
- $node->promote = $i % 2;
- $node->created = $now + $i * 86400;
- $node->log = "added $i node";
- // Make every term association different a little. For nodes with revisions,
- // make the initial revision have a different set of terms than the
- // newest revision.
- $items = array();
- if (module_exists('taxonomy')) {
- if ($node->revision) {
- $node_terms = array($terms[$i], $terms[47-$i]);
- }
- else {
- $node_terms = $terms;
- unset($node_terms[$i], $node_terms[47 - $i]);
- }
- foreach ($node_terms as $tid) {
- $field_name = $term_vocabs[$tid];
- $node->{$field_name}[LANGUAGE_NONE][] = array('tid' => $tid);
- }
- }
- $node->path = array('alias' => "content/$node->created");
- node_save($node);
- if ($node->revision) {
- $user = user_load($uid + 3);
- ++$revision_id;
- $node->title .= " rev2 $revision_id";
- $body_text = str_repeat("node revision body ($node->type) - $i", 100);
- $node->body[$node->language][0]['value'] = $body_text;
- $node->body[$node->language][0]['summary'] = text_summary($body_text);
- $node->body[$node->language][0]['format'] = 'filtered_html';
- $node->log = "added $i revision";
- $node_terms = $terms;
- unset($node_terms[$i], $node_terms[47 - $i]);
- foreach ($node_terms as $tid) {
- $field_name = $term_vocabs[$tid];
- $node->{$field_name}[LANGUAGE_NONE][] = array('tid' => $tid);
- }
- node_save($node);
- }
-}
-
-if (module_exists('poll')) {
- // Create poll content.
- for ($i = 0; $i < 12; $i++) {
- $uid = intval($i / 4) + 3;
- $user = user_load($uid);
- $node = new stdClass();
- $node->uid = $uid;
- $node->type = 'poll';
- $node->sticky = 0;
- $node->title = "poll title $i";
- $node->language = LANGUAGE_NONE;
- $node->status = intval($i / 2) % 2;
- $node->revision = 1;
- $node->promote = $i % 2;
- $node->created = REQUEST_TIME + $i * 43200;
- $node->runtime = 0;
- $node->active = 1;
- $node->log = "added $i poll";
- $node->path = array('alias' => "content/poll/$i");
-
- $nbchoices = ($i % 4) + 2;
- for ($c = 0; $c < $nbchoices; $c++) {
- $node->choice[] = array('chtext' => "Choice $c for poll $i", 'chvotes' => 0, 'weight' => 0);
- }
- node_save($node);
- $path = array(
- 'alias' => "content/poll/$i/results",
- 'source' => "node/$node->nid/results",
- );
- path_save($path);
-
- // Add some votes.
- $node = node_load($node->nid);
- $choices = array_keys($node->choice);
- $original_user = $GLOBALS['user'];
- for ($v = 0; $v < ($i % 4); $v++) {
- drupal_static_reset('ip_address');
- $_SERVER['REMOTE_ADDR'] = "127.0.$v.1";
- $GLOBALS['user'] = drupal_anonymous_user();// We should have already allowed anon to vote.
- $c = $v % $nbchoices;
- $form_state = array();
- $form_state['values']['choice'] = $choices[$c];
- $form_state['values']['op'] = t('Vote');
- drupal_form_submit('poll_view_voting', $form_state, $node);
- }
- }
-}
-
-// Test that upgrade works even on a bundle whose parent module was disabled.
-// This is simulated by creating an existing content type and changing the
-// bundle to another type through direct database update queries.
-$node_type = 'broken';
-$uid = 6;
-$user = user_load($uid);
-$node = new stdClass();
-$node->uid = $uid;
-$node->type = 'article';
-$body_text = str_repeat("node body ($node_type) - 37", 100);
-$node->sticky = 0;
-$node->title = "node title 24";
-$node->language = LANGUAGE_NONE;
-$node->body[$node->language][0]['value'] = $body_text;
-$node->body[$node->language][0]['summary'] = text_summary($body_text);
-$node->body[$node->language][0]['format'] = 'filtered_html';
-$node->status = 1;
-$node->revision = 0;
-$node->promote = 0;
-$node->created = 1263769200;
-$node->log = "added a broken node";
-$node->path = array('alias' => "content/1263769200");
-node_save($node);
-db_update('node')
- ->fields(array(
- 'type' => $node_type,
- ))
- ->condition('nid', $node->nid)
- ->execute();
-if (db_table_exists('field_data_body')) {
- db_update('field_data_body')
- ->fields(array(
- 'bundle' => $node_type,
- ))
- ->condition('entity_id', $node->nid)
- ->condition('entity_type', 'node')
- ->execute();
- db_update('field_revision_body')
- ->fields(array(
- 'bundle' => $node_type,
- ))
- ->condition('entity_id', $node->nid)
- ->condition('entity_type', 'node')
- ->execute();
-}
-db_update('field_config_instance')
- ->fields(array(
- 'bundle' => $node_type,
- ))
- ->condition('bundle', 'article')
- ->execute();
diff --git a/scripts/password-hash.sh b/scripts/password-hash.sh
deleted file mode 100755
index 004421a8..00000000
--- a/scripts/password-hash.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/php
-"
-Example: {$script} "mynewpassword"
-
-All arguments are long options.
-
- --help Print this page.
-
- --root
-
- Set the working directory for the script to the specified path.
- To execute this script this has to be the root directory of your
- Drupal installation, e.g. /home/www/foo/drupal (assuming Drupal
- running on Unix). Use surrounding quotation marks on Windows.
-
- "" ["" ["" ...]]
-
- One or more plan-text passwords enclosed by double quotes. The
- output hash may be manually entered into the {users}.pass field to
- change a password via SQL to a known value.
-
-To run this script without the --root argument invoke it from the root directory
-of your Drupal installation as
-
- ./scripts/{$script}
-\n
-EOF;
- exit;
-}
-
-$passwords = array();
-
-// Parse invocation arguments.
-while ($param = array_shift($_SERVER['argv'])) {
- switch ($param) {
- case '--root':
- // Change the working directory.
- $path = array_shift($_SERVER['argv']);
- if (is_dir($path)) {
- chdir($path);
- }
- break;
- default:
- // Add a password to the list to be processed.
- $passwords[] = $param;
- break;
- }
-}
-
-define('DRUPAL_ROOT', getcwd());
-
-include_once DRUPAL_ROOT . '/includes/password.inc';
-include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-
-foreach ($passwords as $password) {
- print("\npassword: $password \t\thash: ". user_hash_password($password) ."\n");
-}
-print("\n");
-
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
deleted file mode 100755
index 189d7f2e..00000000
--- a/scripts/run-tests.sh
+++ /dev/null
@@ -1,676 +0,0 @@
- $tests) {
- $all_tests = array_merge($all_tests, array_keys($tests));
-}
-$test_list = array();
-
-if ($args['list']) {
- // Display all available tests.
- echo "\nAvailable test groups & classes\n";
- echo "-------------------------------\n\n";
- foreach ($groups as $group => $tests) {
- echo $group . "\n";
- foreach ($tests as $class => $info) {
- echo " - " . $info['name'] . ' (' . $class . ')' . "\n";
- }
- }
- exit;
-}
-
-$test_list = simpletest_script_get_test_list();
-
-// Try to allocate unlimited time to run the tests.
-drupal_set_time_limit(0);
-
-simpletest_script_reporter_init();
-
-// Setup database for test results.
-$test_id = db_insert('simpletest_test_id')->useDefaults(array('test_id'))->execute();
-
-// Execute tests.
-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
-// fatal errors caused the test to crash.
-list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
-simpletest_log_read($test_id, $last_prefix, $last_test_class);
-
-// Stop the timer.
-simpletest_script_reporter_timer_stop();
-
-// Display results before database is cleared.
-simpletest_script_reporter_display_results();
-
-if ($args['xml']) {
- simpletest_script_reporter_write_xml_results();
-}
-
-// Cleanup our test results.
-simpletest_clean_results_table($test_id);
-
-// Test complete, exit.
-exit;
-
-/**
- * Print help text.
- */
-function simpletest_script_help() {
- global $args;
-
- echo <<
-Example: {$args['script']} Profile
-
-All arguments are long options.
-
- --help Print this page.
-
- --list Display all available test groups.
-
- --clean Cleans up database tables or directories from previous, failed,
- tests and then exits (no tests are run).
-
- --url Immediately precedes a URL to set the host and path. You will
- need this parameter if Drupal is in a subdirectory on your
- localhost and you have not set \$base_url in settings.php. Tests
- can be run under SSL by including https:// in the URL.
-
- --php The absolute path to the PHP executable. Usually not needed.
-
- --concurrency [num]
-
- Run tests in parallel, up to [num] tests at a time.
-
- --all Run all available tests.
-
- --class Run tests identified by specific class names, instead of group names.
-
- --file Run tests identified by specific file names, instead of group names.
- Specify the path and the extension (i.e. 'modules/user/user.test').
-
- --xml
-
- If provided, test results will be written as xml files to this path.
-
- --color Output text format results with color highlighting.
-
- --verbose Output detailed assertion messages in addition to summary.
-
- [,[, ...]]
-
- One or more tests to be run. By default, these are interpreted
- as the names of test groups as shown at
- ?q=admin/config/development/testing.
- These group names typically correspond to module names like "User"
- or "Profile" or "System", but there is also a group "XML-RPC".
- If --class is specified then these are interpreted as the names of
- specific test classes whose test methods will be run. Tests must
- be separated by commas. Ignored if --all is specified.
-
-To run this script you will normally invoke it from the root directory of your
-Drupal installation as the webserver user (differs per configuration), or root:
-
-sudo -u [wwwrun|www-data|etc] php ./scripts/{$args['script']}
- --url http://example.com/ --all
-sudo -u [wwwrun|www-data|etc] php ./scripts/{$args['script']}
- --url http://example.com/ --class BlockTestCase
-\n
-EOF;
-}
-
-/**
- * Parse execution argument and ensure that all are valid.
- *
- * @return The list of arguments.
- */
-function simpletest_script_parse_args() {
- // Set default values.
- $args = array(
- 'script' => '',
- 'help' => FALSE,
- 'list' => FALSE,
- 'clean' => FALSE,
- 'url' => '',
- 'php' => '',
- 'concurrency' => 1,
- 'all' => FALSE,
- 'class' => FALSE,
- 'file' => FALSE,
- 'color' => FALSE,
- 'verbose' => FALSE,
- 'test_names' => array(),
- // Used internally.
- 'test-id' => 0,
- 'execute-test' => '',
- 'xml' => '',
- );
-
- // Override with set values.
- $args['script'] = basename(array_shift($_SERVER['argv']));
-
- $count = 0;
- while ($arg = array_shift($_SERVER['argv'])) {
- if (preg_match('/--(\S+)/', $arg, $matches)) {
- // Argument found.
- if (array_key_exists($matches[1], $args)) {
- // Argument found in list.
- $previous_arg = $matches[1];
- if (is_bool($args[$previous_arg])) {
- $args[$matches[1]] = TRUE;
- }
- else {
- $args[$matches[1]] = array_shift($_SERVER['argv']);
- }
- // Clear extraneous values.
- $args['test_names'] = array();
- $count++;
- }
- else {
- // Argument not found in list.
- simpletest_script_print_error("Unknown argument '$arg'.");
- exit;
- }
- }
- else {
- // Values found without an argument should be test names.
- $args['test_names'] += explode(',', $arg);
- $count++;
- }
- }
-
- // Validate the concurrency argument
- if (!is_numeric($args['concurrency']) || $args['concurrency'] <= 0) {
- simpletest_script_print_error("--concurrency must be a strictly positive integer.");
- exit;
- }
-
- return array($args, $count);
-}
-
-/**
- * Initialize script variables and perform general setup requirements.
- */
-function simpletest_script_init($server_software) {
- global $args, $php;
-
- $host = 'localhost';
- $path = '';
- // Determine location of php command automatically, unless a command line argument is supplied.
- if (!empty($args['php'])) {
- $php = $args['php'];
- }
- elseif ($php_env = getenv('_')) {
- // '_' is an environment variable set by the shell. It contains the command that was executed.
- $php = $php_env;
- }
- elseif ($sudo = getenv('SUDO_COMMAND')) {
- // 'SUDO_COMMAND' is an environment variable set by the sudo program.
- // Extract only the PHP interpreter, not the rest of the command.
- list($php, ) = explode(' ', $sudo, 2);
- }
- else {
- simpletest_script_print_error('Unable to automatically determine the path to the PHP interpreter. Supply the --php command line argument.');
- simpletest_script_help();
- exit();
- }
-
- // Get URL from arguments.
- if (!empty($args['url'])) {
- $parsed_url = parse_url($args['url']);
- $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '');
- $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
-
- // If the passed URL schema is 'https' then setup the $_SERVER variables
- // properly so that testing will run under HTTPS.
- if ($parsed_url['scheme'] == 'https') {
- $_SERVER['HTTPS'] = 'on';
- }
- }
-
- $_SERVER['HTTP_HOST'] = $host;
- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
- $_SERVER['SERVER_ADDR'] = '127.0.0.1';
- $_SERVER['SERVER_SOFTWARE'] = $server_software;
- $_SERVER['SERVER_NAME'] = 'localhost';
- $_SERVER['REQUEST_URI'] = $path .'/';
- $_SERVER['REQUEST_METHOD'] = 'GET';
- $_SERVER['SCRIPT_NAME'] = $path .'/index.php';
- $_SERVER['PHP_SELF'] = $path .'/index.php';
- $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
-
- if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
- // Ensure that any and all environment variables are changed to https://.
- foreach ($_SERVER as $key => $value) {
- $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
- }
- }
-
- chdir(realpath(dirname(__FILE__) . '/..'));
- define('DRUPAL_ROOT', getcwd());
- require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
-}
-
-/**
- * Execute a batch of tests.
- */
-function simpletest_script_execute_batch($test_id, $test_classes) {
- global $args;
-
- // Multi-process execution.
- $children = array();
- while (!empty($test_classes) || !empty($children)) {
- while (count($children) < $args['concurrency']) {
- if (empty($test_classes)) {
- break;
- }
-
- // 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;
- }
-
- // Register our new child.
- $children[] = array(
- 'process' => $process,
- 'class' => $test_class,
- 'pipes' => $pipes,
- );
- }
-
- // 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]);
- }
- }
- }
-}
-
-/**
- * Bootstrap Drupal and run a single test.
- */
-function simpletest_script_run_one_test($test_id, $test_class) {
- try {
- // Bootstrap Drupal.
- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-
- simpletest_classloader_register();
-
- $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));
-
- // Finished, kill this runner.
- exit(0);
- }
- catch (Exception $e) {
- echo (string) $e;
- exit(1);
- }
-}
-
-/**
- * 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($test_id, $test_class) {
- global $args, $php;
-
- $command = escapeshellarg($php) . ' ' . escapeshellarg('./scripts/' . $args['script']) . ' --url ' . escapeshellarg($args['url']);
- if ($args['color']) {
- $command .= ' --color';
- }
- $command .= " --php " . escapeshellarg($php) . " --test-id $test_id --execute-test " . escapeshellarg($test_class);
- return $command;
-}
-
-/**
- * Get list of tests based on arguments. If --all specified then
- * returns all available tests, otherwise reads list of tests.
- *
- * Will print error and exit if no valid tests were found.
- *
- * @return List of tests.
- */
-function simpletest_script_get_test_list() {
- global $args, $all_tests, $groups;
-
- $test_list = array();
- if ($args['all']) {
- $test_list = $all_tests;
- }
- else {
- if ($args['class']) {
- // Check for valid class names.
- foreach ($args['test_names'] as $class_name) {
- if (in_array($class_name, $all_tests)) {
- $test_list[] = $class_name;
- }
- }
- }
- elseif ($args['file']) {
- $files = array();
- foreach ($args['test_names'] as $file) {
- $files[drupal_realpath($file)] = 1;
- }
-
- // Check for valid class names.
- foreach ($all_tests as $class_name) {
- $refclass = new ReflectionClass($class_name);
- $file = $refclass->getFileName();
- if (isset($files[$file])) {
- $test_list[] = $class_name;
- }
- }
- }
- else {
- // Check for valid group names and get all valid classes in group.
- foreach ($args['test_names'] as $group_name) {
- if (isset($groups[$group_name])) {
- foreach ($groups[$group_name] as $class_name => $info) {
- $test_list[] = $class_name;
- }
- }
- }
- }
- }
-
- if (empty($test_list)) {
- simpletest_script_print_error('No valid tests were specified.');
- exit;
- }
- return $test_list;
-}
-
-/**
- * Initialize the reporter.
- */
-function simpletest_script_reporter_init() {
- global $args, $all_tests, $test_list, $results_map;
-
- $results_map = array(
- 'pass' => 'Pass',
- 'fail' => 'Fail',
- 'exception' => 'Exception'
- );
-
- echo "\n";
- echo "Drupal test run\n";
- echo "---------------\n";
- echo "\n";
-
- // Tell the user about what tests are to be run.
- if ($args['all']) {
- echo "All tests will run.\n\n";
- }
- else {
- echo "Tests to be run:\n";
- foreach ($test_list as $class_name) {
- $info = call_user_func(array($class_name, 'getInfo'));
- echo " - " . $info['name'] . ' (' . $class_name . ')' . "\n";
- }
- echo "\n";
- }
-
- echo "Test run started:\n";
- echo " " . format_date($_SERVER['REQUEST_TIME'], 'long') . "\n";
- timer_start('run-tests');
- echo "\n";
-
- echo "Test summary\n";
- echo "------------\n";
- echo "\n";
-}
-
-/**
- * Display jUnit XML test results.
- */
-function simpletest_script_reporter_write_xml_results() {
- global $args, $test_id, $results_map;
-
- $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
-
- $test_class = '';
- $xml_files = array();
-
- foreach ($results as $result) {
- if (isset($results_map[$result->status])) {
- if ($result->test_class != $test_class) {
- // We've moved onto a new class, so write the last classes results to a file:
- if (isset($xml_files[$test_class])) {
- file_put_contents($args['xml'] . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
- unset($xml_files[$test_class]);
- }
- $test_class = $result->test_class;
- if (!isset($xml_files[$test_class])) {
- $doc = new DomDocument('1.0');
- $root = $doc->createElement('testsuite');
- $root = $doc->appendChild($root);
- $xml_files[$test_class] = array('doc' => $doc, 'suite' => $root);
- }
- }
-
- // For convenience:
- $dom_document = &$xml_files[$test_class]['doc'];
-
- // Create the XML element for this test case:
- $case = $dom_document->createElement('testcase');
- $case->setAttribute('classname', $test_class);
- list($class, $name) = explode('->', $result->function, 2);
- $case->setAttribute('name', $name);
-
- // Passes get no further attention, but failures and exceptions get to add more detail:
- if ($result->status == 'fail') {
- $fail = $dom_document->createElement('failure');
- $fail->setAttribute('type', 'failure');
- $fail->setAttribute('message', $result->message_group);
- $text = $dom_document->createTextNode($result->message);
- $fail->appendChild($text);
- $case->appendChild($fail);
- }
- elseif ($result->status == 'exception') {
- // In the case of an exception the $result->function may not be a class
- // method so we record the full function name:
- $case->setAttribute('name', $result->function);
-
- $fail = $dom_document->createElement('error');
- $fail->setAttribute('type', 'exception');
- $fail->setAttribute('message', $result->message_group);
- $full_message = $result->message . "\n\nline: " . $result->line . "\nfile: " . $result->file;
- $text = $dom_document->createTextNode($full_message);
- $fail->appendChild($text);
- $case->appendChild($fail);
- }
- // Append the test case XML to the test suite:
- $xml_files[$test_class]['suite']->appendChild($case);
- }
- }
- // The last test case hasn't been saved to a file yet, so do that now:
- if (isset($xml_files[$test_class])) {
- file_put_contents($args['xml'] . '/' . $test_class . '.xml', $xml_files[$test_class]['doc']->saveXML());
- unset($xml_files[$test_class]);
- }
-}
-
-/**
- * Stop the test timer.
- */
-function simpletest_script_reporter_timer_stop() {
- echo "\n";
- $end = timer_stop('run-tests');
- echo "Test run duration: " . format_interval($end['time'] / 1000);
- echo "\n\n";
-}
-
-/**
- * Display test results.
- */
-function simpletest_script_reporter_display_results() {
- global $args, $test_id, $results_map;
-
- if ($args['verbose']) {
- // Report results.
- echo "Detailed test results\n";
- echo "---------------------\n";
-
- $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
- $test_class = '';
- foreach ($results as $result) {
- if (isset($results_map[$result->status])) {
- if ($result->test_class != $test_class) {
- // Display test class every time results are for new test class.
- echo "\n\n---- $result->test_class ----\n\n\n";
- $test_class = $result->test_class;
-
- // Print table header.
- echo "Status Group Filename Line Function \n";
- echo "--------------------------------------------------------------------------------\n";
- }
-
- simpletest_script_format_result($result);
- }
- }
- }
-}
-
-/**
- * Format the result so that it fits within the default 80 character
- * terminal size.
- *
- * @param $result The result object to format.
- */
-function simpletest_script_format_result($result) {
- global $results_map, $color;
-
- $summary = sprintf("%-9.9s %-10.10s %-17.17s %4.4s %-35.35s\n",
- $results_map[$result->status], $result->message_group, basename($result->file), $result->line, $result->function);
-
- simpletest_script_print($summary, simpletest_script_color_code($result->status));
-
- $lines = explode("\n", wordwrap(trim(strip_tags($result->message)), 76));
- foreach ($lines as $line) {
- echo " $line\n";
- }
-}
-
-/**
- * Print error message prefixed with " ERROR: " and displayed in fail color
- * if color output is enabled.
- *
- * @param $message The message to print.
- */
-function simpletest_script_print_error($message) {
- simpletest_script_print(" ERROR: $message\n", SIMPLETEST_SCRIPT_COLOR_FAIL);
-}
-
-/**
- * Print a message to the console, if color is enabled then the specified
- * color code will be used.
- *
- * @param $message The message to print.
- * @param $color_code The color code to use for coloring.
- */
-function simpletest_script_print($message, $color_code) {
- global $args;
- if ($args['color']) {
- echo "\033[" . $color_code . "m" . $message . "\033[0m";
- }
- else {
- echo $message;
- }
-}
-
-/**
- * Get the color code associated with the specified status.
- *
- * @param $status The status string to get code for.
- * @return Color code.
- */
-function simpletest_script_color_code($status) {
- switch ($status) {
- case 'pass':
- return SIMPLETEST_SCRIPT_COLOR_PASS;
- case 'fail':
- return SIMPLETEST_SCRIPT_COLOR_FAIL;
- case 'exception':
- return SIMPLETEST_SCRIPT_COLOR_EXCEPTION;
- }
- return 0; // Default formatting.
-}
diff --git a/scripts/test.script b/scripts/test.script
deleted file mode 100644
index a45f3f0c..00000000
--- a/scripts/test.script
+++ /dev/null
@@ -1,4 +0,0 @@
-This file is for testing purposes only.
-
-It is used to test the functionality of drupal_get_filename(). See
-BootstrapGetFilenameTestCase::testDrupalGetFilename() for more information.
diff --git a/sites/README.txt b/sites/README.txt
deleted file mode 100644
index 9aecef2d..00000000
--- a/sites/README.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This directory structure contains the settings and configuration files specific
-to your site or sites and is an integral part of multisite configuration.
-
-The sites/all/ subdirectory structure should be used to place your custom and
-downloaded extensions including modules, themes, and third party libraries.
-
-Downloaded installation profiles should be placed in the /profiles directory
-in the Drupal root.
-
-In multisite configuration, extensions found in the sites/all directory
-structure are available to all sites. Alternatively, the sites/your_site_name/
-subdirectory pattern may be used to restrict extensions to a specific
-site instance.
-
-See the respective README.txt files in sites/all/themes and sites/all/modules
-for additional information about obtaining and organizing extensions.
-
-See INSTALL.txt in the Drupal root for information about single-site
-installation or multisite configuration.
diff --git a/sites/all/libraries/bigscreen/.gitignore b/sites/all/libraries/bigscreen/.gitignore
deleted file mode 100755
index 6abe0424..00000000
--- a/sites/all/libraries/bigscreen/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.DS_Store
-node_modules
-BigScreen.sublime-workspace
\ No newline at end of file
diff --git a/sites/all/libraries/bigscreen/.jshintrc b/sites/all/libraries/bigscreen/.jshintrc
deleted file mode 100755
index 3886761b..00000000
--- a/sites/all/libraries/bigscreen/.jshintrc
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "evil": true,
- "regexdash": true,
- "browser": true,
- "wsh": true,
- "trailing": true,
- "sub": true,
- "newcap": false,
- "smarttabs": true,
- "devel": true,
- "globals": {
- "Element": true
- }
-}
\ No newline at end of file
diff --git a/sites/all/libraries/bigscreen/BigScreen.sublime-project b/sites/all/libraries/bigscreen/BigScreen.sublime-project
deleted file mode 100755
index 1f02d88e..00000000
--- a/sites/all/libraries/bigscreen/BigScreen.sublime-project
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "settings":
- {
- "detect_indentation": true,
- "tab_size": 4,
- "translate_tabs_to_spaces": false,
- "trim_automatic_white_space": false,
- "trim_trailing_white_space_on_save": true
- },
- "folders":
- [
- {
- "path": "./",
- "folder_exclude_patterns": ["node_modules"],
- "file_exclude_patterns": ["*.sublime-workspace"]
- }
- ]
-}
\ No newline at end of file
diff --git a/sites/all/libraries/bigscreen/Gruntfile.js b/sites/all/libraries/bigscreen/Gruntfile.js
deleted file mode 100755
index 87d0de3b..00000000
--- a/sites/all/libraries/bigscreen/Gruntfile.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*jshint node:true */
-module.exports = function(grunt) {
- 'use strict';
-
- grunt.initConfig({
- pkg: grunt.file.readJSON('package.json'),
-
- jshint: {
- options: grunt.file.readJSON('.jshintrc'),
- dev: {
- src: ['Gruntfile.js', 'src/**/*.js']
- },
- beforeconcat: {
- options: {
- devel: false
- },
- src: ['Gruntfile.js', 'src/**/*.js']
- },
- afterconcat: {
- options: {
- devel: false
- },
- src: ['bigscreen.js']
- }
- },
-
- concat: {
- options: {
- stripBanners: true,
- banner: '/*! <%= pkg.name %>\n * v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n * <%= pkg.homepage %>\n * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>; <%= _.pluck(pkg.licenses, "type").join(", ") %> License\n */\n'
- },
- all: {
- src: ['src/**/*.js'],
- dest: 'bigscreen.js'
- }
- },
-
- uglify: {
- options: {
- banner: '// <%= pkg.name %> v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> - <%= _.pluck(pkg.licenses, "type").join(", ") %> License\n'
- },
- unminified: {
- options: {
- banner: '',
- mangle: false,
- compress: false,
- preserveComments: 'some',
- beautify: true
- },
- src: ['bigscreen.js'],
- dest: 'bigscreen.js'
- },
- minified: {
- src: ['bigscreen.js'],
- dest: 'bigscreen.min.js'
- }
- }
-
- });
-
- grunt.loadNpmTasks('grunt-contrib-concat');
- grunt.loadNpmTasks('grunt-contrib-jshint');
- grunt.loadNpmTasks('grunt-contrib-uglify');
- grunt.loadNpmTasks('grunt-contrib-clean');
-
- grunt.registerTask('default', ['jshint:dev']);
- grunt.registerTask('release', ['jshint:beforeconcat', 'concat', 'jshint:afterconcat', 'uglify:unminified', 'uglify:minified']);
-
-};
\ No newline at end of file
diff --git a/sites/all/libraries/bigscreen/LICENSE b/sites/all/libraries/bigscreen/LICENSE
deleted file mode 100755
index 7a4a3ea2..00000000
--- a/sites/all/libraries/bigscreen/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
diff --git a/sites/all/libraries/bigscreen/README.md b/sites/all/libraries/bigscreen/README.md
deleted file mode 100755
index 1c6efbdb..00000000
--- a/sites/all/libraries/bigscreen/README.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# BigScreen
-
-A simple library for using the JavaScript Fullscreen API.
-
-
-## Why should I use it?
-
-BigScreen makes it easy to use full screen on your site or in your app. It smoothes out browser inconsistencies and bugs, especially if the element you're working with is inside of an ` ');
- });
-
-
- $.supersized = function(options){
-
- /* Variables
- ----------------------------*/
- var el = '#supersized',
- base = this;
- // Access to jQuery and DOM versions of element
- base.$el = $(el);
- base.el = el;
- vars = $.supersized.vars;
- // Add a reverse reference to the DOM object
- base.$el.data("supersized", base);
- api = base.$el.data('supersized');
-
- base.init = function(){
- // Combine options and vars
- $.supersized.vars = $.extend($.supersized.vars, $.supersized.themeVars);
- $.supersized.vars.options = $.extend({},$.supersized.defaultOptions, $.supersized.themeOptions, options);
- base.options = $.supersized.vars.options;
-
- base._build();
- };
-
-
- /* Build Elements
- ----------------------------*/
- base._build = function(){
- // Add in slide markers
- var thisSlide = 0,
- slideSet = '',
- markers = '',
- markerContent,
- thumbMarkers = '',
- thumbImage;
-
- while(thisSlide <= base.options.slides.length-1){
- //Determine slide link content
- switch(base.options.slide_links){
- case 'num':
- markerContent = thisSlide;
- break;
- case 'name':
- markerContent = base.options.slides[thisSlide].title;
- break;
- case 'blank':
- markerContent = '';
- break;
- }
-
- slideSet = slideSet+'
';
-
- if(thisSlide == base.options.start_slide-1){
- // Slide links
- if (base.options.slide_links)markers = markers+'
'+markerContent+' ';
- // Slide Thumbnail Links
- if (base.options.thumb_links){
- base.options.slides[thisSlide].thumb ? thumbImage = base.options.slides[thisSlide].thumb : thumbImage = base.options.slides[thisSlide].image;
- thumbMarkers = thumbMarkers+'
';
- };
- }else{
- // Slide links
- if (base.options.slide_links) markers = markers+'
'+markerContent+' ';
- // Slide Thumbnail Links
- if (base.options.thumb_links){
- base.options.slides[thisSlide].thumb ? thumbImage = base.options.slides[thisSlide].thumb : thumbImage = base.options.slides[thisSlide].image;
- thumbMarkers = thumbMarkers+'
';
- };
- }
- thisSlide++;
- }
-
- if (base.options.slide_links) $(vars.slide_list).html(markers);
- if (base.options.thumb_links && vars.thumb_tray.length){
- $(vars.thumb_tray).append('
');
- }
-
- $(base.el).append(slideSet);
-
- // Add in thumbnails
- if (base.options.thumbnail_navigation){
- // Load previous thumbnail
- vars.current_slide - 1 < 0 ? prevThumb = base.options.slides.length - 1 : prevThumb = vars.current_slide - 1;
- $(vars.prev_thumb).show().html($("
").attr("src", base.options.slides[prevThumb].image));
-
- // Load next thumbnail
- vars.current_slide == base.options.slides.length - 1 ? nextThumb = 0 : nextThumb = vars.current_slide + 1;
- $(vars.next_thumb).show().html($("
").attr("src", base.options.slides[nextThumb].image));
- }
-
- base._start(); // Get things started
- };
-
-
- /* Initialize
- ----------------------------*/
- base._start = function(){
-
- // Determine if starting slide random
- if (base.options.start_slide){
- vars.current_slide = base.options.start_slide - 1;
- }else{
- vars.current_slide = Math.floor(Math.random()*base.options.slides.length); // Generate random slide number
- }
-
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
-
- // Set slideshow quality (Supported only in FF and IE, no Webkit)
- if (base.options.performance == 3){
- base.$el.addClass('speed'); // Faster transitions
- } else if ((base.options.performance == 1) || (base.options.performance == 2)){
- base.$el.addClass('quality'); // Higher image quality
- }
-
- // Shuffle slide order if needed
- if (base.options.random){
- arr = base.options.slides;
- for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i), x = arr[--i], arr[i] = arr[j], arr[j] = x); // Fisher-Yates shuffle algorithm (jsfromhell.com/array/shuffle)
- base.options.slides = arr;
- }
-
- /*-----Load initial set of images-----*/
-
- if (base.options.slides.length > 1){
- if(base.options.slides.length > 2){
- // Set previous image
- vars.current_slide - 1 < 0 ? loadPrev = base.options.slides.length - 1 : loadPrev = vars.current_slide - 1; // If slide is 1, load last slide as previous
- var imageLink = (base.options.slides[loadPrev].url) ? "href='" + base.options.slides[loadPrev].url + "'" : "";
-
- var imgPrev = $('
');
- var slidePrev = base.el+' li:eq('+loadPrev+')';
- imgPrev.appendTo(slidePrev).wrap('
').parent().parent().addClass('image-loading prevslide');
-
- imgPrev.load(function(){
- $(this).data('origWidth', $(this).width()).data('origHeight', $(this).height());
- base.resizeNow(); // Resize background image
- }); // End Load
- }
- } else {
- // Slideshow turned off if there is only one slide
- base.options.slideshow = 0;
- }
-
- // Set current image
- imageLink = (api.getField('url')) ? "href='" + api.getField('url') + "'" : "";
- var img = $('
');
-
- var slideCurrent= base.el+' li:eq('+vars.current_slide+')';
- img.appendTo(slideCurrent).wrap('
').parent().parent().addClass('image-loading activeslide');
-
- img.load(function(){
- base._origDim($(this));
- base.resizeNow(); // Resize background image
- base.launch();
- if( typeof theme != 'undefined' && typeof theme._init == "function" ) theme._init(); // Load Theme
- });
-
- if (base.options.slides.length > 1){
- // Set next image
- vars.current_slide == base.options.slides.length - 1 ? loadNext = 0 : loadNext = vars.current_slide + 1; // If slide is last, load first slide as next
- imageLink = (base.options.slides[loadNext].url) ? "href='" + base.options.slides[loadNext].url + "'" : "";
-
- var imgNext = $('
');
- var slideNext = base.el+' li:eq('+loadNext+')';
- imgNext.appendTo(slideNext).wrap('
').parent().parent().addClass('image-loading');
-
- imgNext.load(function(){
- $(this).data('origWidth', $(this).width()).data('origHeight', $(this).height());
- base.resizeNow(); // Resize background image
- }); // End Load
- }
- /*-----End load initial images-----*/
-
- // Hide elements to be faded in
- base.$el.css('visibility','hidden');
- $('.load-item').hide();
-
- };
-
-
- /* Launch Supersized
- ----------------------------*/
- base.launch = function(){
-
- base.$el.css('visibility','visible');
- $('#supersized-loader').remove(); //Hide loading animation
-
- // Call theme function for before slide transition
- if( typeof theme != 'undefined' && typeof theme.beforeAnimation == "function" ) theme.beforeAnimation('next');
- $('.load-item').show();
-
- // Keyboard Navigation
- if (base.options.keyboard_nav){
- $(document.documentElement).keyup(function (event) {
-
- if(vars.in_animation) return false; // Abort if currently animating
- if($(document.activeElement).is("input, textarea")) return false; // Abort if active element is an input or a textarea.
-
- // Left Arrow or Down Arrow
- if ((event.keyCode == 37) || (event.keyCode == 40)) {
- clearInterval(vars.slideshow_interval); // Stop slideshow, prevent buildup
- base.prevSlide();
-
- // Right Arrow or Up Arrow
- } else if ((event.keyCode == 39) || (event.keyCode == 38)) {
- clearInterval(vars.slideshow_interval); // Stop slideshow, prevent buildup
- base.nextSlide();
-
- // Spacebar
- } else if (event.keyCode == 32 && !vars.hover_pause) {
- clearInterval(vars.slideshow_interval); // Stop slideshow, prevent buildup
- base.playToggle();
- }
-
- });
- }
-
- // Pause when hover on image
- if (base.options.slideshow && base.options.pause_hover){
- $(base.el).hover(function() {
- if(vars.in_animation) return false; // Abort if currently animating
- vars.hover_pause = true; // Mark slideshow paused from hover
- if(!vars.is_paused){
- vars.hover_pause = 'resume'; // It needs to resume afterwards
- base.playToggle();
- }
- }, function() {
- if(vars.hover_pause == 'resume'){
- base.playToggle();
- vars.hover_pause = false;
- }
- });
- }
-
- if (base.options.slide_links){
- // Slide marker clicked
- $(vars.slide_list+'> li').click(function(){
-
- index = $(vars.slide_list+'> li').index(this);
- targetSlide = index + 1;
-
- base.goTo(targetSlide);
- return false;
-
- });
- }
-
- // Thumb marker clicked
- if (base.options.thumb_links){
- $(vars.thumb_list+'> li').click(function(){
-
- index = $(vars.thumb_list+'> li').index(this);
- targetSlide = index + 1;
-
- api.goTo(targetSlide);
- return false;
-
- });
- }
-
- // Start slideshow if enabled
- if (base.options.slideshow && base.options.slides.length > 1){
-
- // Start slideshow if autoplay enabled
- if (base.options.autoplay && base.options.slides.length > 1){
- vars.slideshow_interval = setInterval(base.nextSlide, base.options.slide_interval); // Initiate slide interval
- }else{
- vars.is_paused = true; // Mark as paused
- }
-
- //Prevent navigation items from being dragged
- $('.load-item img').bind("contextmenu mousedown",function(){
- return false;
- });
-
- }
-
- // Adjust image when browser is resized
- $(window).resize(function(){
- base.resizeNow();
- });
-
- };
-
-
- /* Resize Images
- ----------------------------*/
- base.resizeNow = function(){
-
- return base.$el.each(function() {
- // Resize each image seperately
- $('img', base.el).each(function(){
-
- thisSlide = $(this);
- var ratio = (thisSlide.data('origHeight')/thisSlide.data('origWidth')).toFixed(2); // Define image ratio
-
- // Gather browser size
- var browserwidth = base.$el.width(),
- browserheight = base.$el.height(),
- offset;
-
- /*-----Resize Image-----*/
- if (base.options.fit_always){ // Fit always is enabled
- if ((browserheight/browserwidth) > ratio){
- resizeWidth();
- } else {
- resizeHeight();
- }
- }else{ // Normal Resize
- if ((browserheight <= base.options.min_height) && (browserwidth <= base.options.min_width)){ // If window smaller than minimum width and height
-
- if ((browserheight/browserwidth) > ratio){
- base.options.fit_landscape && ratio < 1 ? resizeWidth(true) : resizeHeight(true); // If landscapes are set to fit
- } else {
- base.options.fit_portrait && ratio >= 1 ? resizeHeight(true) : resizeWidth(true); // If portraits are set to fit
- }
-
- } else if (browserwidth <= base.options.min_width){ // If window only smaller than minimum width
-
- if ((browserheight/browserwidth) > ratio){
- base.options.fit_landscape && ratio < 1 ? resizeWidth(true) : resizeHeight(); // If landscapes are set to fit
- } else {
- base.options.fit_portrait && ratio >= 1 ? resizeHeight() : resizeWidth(true); // If portraits are set to fit
- }
-
- } else if (browserheight <= base.options.min_height){ // If window only smaller than minimum height
-
- if ((browserheight/browserwidth) > ratio){
- base.options.fit_landscape && ratio < 1 ? resizeWidth() : resizeHeight(true); // If landscapes are set to fit
- } else {
- base.options.fit_portrait && ratio >= 1 ? resizeHeight(true) : resizeWidth(); // If portraits are set to fit
- }
-
- } else { // If larger than minimums
-
- if ((browserheight/browserwidth) > ratio){
- base.options.fit_landscape && ratio < 1 ? resizeWidth() : resizeHeight(); // If landscapes are set to fit
- } else {
- base.options.fit_portrait && ratio >= 1 ? resizeHeight() : resizeWidth(); // If portraits are set to fit
- }
-
- }
- }
- /*-----End Image Resize-----*/
-
-
- /*-----Resize Functions-----*/
-
- function resizeWidth(minimum){
- if (minimum){ // If minimum height needs to be considered
- if(thisSlide.width() < browserwidth || thisSlide.width() < base.options.min_width ){
- if (thisSlide.width() * ratio >= base.options.min_height){
- thisSlide.width(base.options.min_width);
- thisSlide.height(thisSlide.width() * ratio);
- }else{
- resizeHeight();
- }
- }
- }else{
- if (base.options.min_height >= browserheight && !base.options.fit_landscape){ // If minimum height needs to be considered
- if (browserwidth * ratio >= base.options.min_height || (browserwidth * ratio >= base.options.min_height && ratio <= 1)){ // If resizing would push below minimum height or image is a landscape
- thisSlide.width(browserwidth);
- thisSlide.height(browserwidth * ratio);
- } else if (ratio > 1){ // Else the image is portrait
- thisSlide.height(base.options.min_height);
- thisSlide.width(thisSlide.height() / ratio);
- } else if (thisSlide.width() < browserwidth) {
- thisSlide.width(browserwidth);
- thisSlide.height(thisSlide.width() * ratio);
- }
- }else{ // Otherwise, resize as normal
- thisSlide.width(browserwidth);
- thisSlide.height(browserwidth * ratio);
- }
- }
- };
-
- function resizeHeight(minimum){
- if (minimum){ // If minimum height needs to be considered
- if(thisSlide.height() < browserheight){
- if (thisSlide.height() / ratio >= base.options.min_width){
- thisSlide.height(base.options.min_height);
- thisSlide.width(thisSlide.height() / ratio);
- }else{
- resizeWidth(true);
- }
- }
- }else{ // Otherwise, resized as normal
- if (base.options.min_width >= browserwidth){ // If minimum width needs to be considered
- if (browserheight / ratio >= base.options.min_width || ratio > 1){ // If resizing would push below minimum width or image is a portrait
- thisSlide.height(browserheight);
- thisSlide.width(browserheight / ratio);
- } else if (ratio <= 1){ // Else the image is landscape
- thisSlide.width(base.options.min_width);
- thisSlide.height(thisSlide.width() * ratio);
- }
- }else{ // Otherwise, resize as normal
- thisSlide.height(browserheight);
- thisSlide.width(browserheight / ratio);
- }
- }
- };
-
- /*-----End Resize Functions-----*/
-
- if (thisSlide.parents('li').hasClass('image-loading')){
- $('.image-loading').removeClass('image-loading');
- }
-
- // Horizontally Center
- if (base.options.horizontal_center){
- $(this).css('left', (browserwidth - $(this).width())/2);
- }
-
- // Vertically Center
- if (base.options.vertical_center){
- $(this).css('top', (browserheight - $(this).height())/2);
- }
-
- });
-
- // Basic image drag and right click protection
- if (base.options.image_protect){
-
- $('img', base.el).bind("contextmenu mousedown",function(){
- return false;
- });
-
- }
-
- return false;
-
- });
-
- };
-
-
- /* Next Slide
- ----------------------------*/
- base.nextSlide = function(){
-
- if(vars.in_animation || !api.options.slideshow) return false; // Abort if currently animating
- else vars.in_animation = true; // Otherwise set animation marker
-
- clearInterval(vars.slideshow_interval); // Stop slideshow
-
- var slides = base.options.slides, // Pull in slides array
- liveslide = base.$el.find('.activeslide'); // Find active slide
- $('.prevslide').removeClass('prevslide');
- liveslide.removeClass('activeslide').addClass('prevslide'); // Remove active class & update previous slide
-
- // Get the slide number of new slide
- vars.current_slide + 1 == base.options.slides.length ? vars.current_slide = 0 : vars.current_slide++;
-
- var nextslide = $(base.el+' li:eq('+vars.current_slide+')'),
- prevslide = base.$el.find('.prevslide');
-
- // If hybrid mode is on drop quality for transition
- if (base.options.performance == 1) base.$el.removeClass('quality').addClass('speed');
-
-
- /*-----Load Image-----*/
-
- loadSlide = false;
-
- vars.current_slide == base.options.slides.length - 1 ? loadSlide = 0 : loadSlide = vars.current_slide + 1; // Determine next slide
-
- var targetList = base.el+' li:eq('+loadSlide+')';
- if (!$(targetList).html()){
-
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
-
- imageLink = (base.options.slides[loadSlide].url) ? "href='" + base.options.slides[loadSlide].url + "'" : ""; // If link exists, build it
- var img = $('
');
-
- img.appendTo(targetList).wrap('
').parent().parent().addClass('image-loading').css('visibility','hidden');
-
- img.load(function(){
- base._origDim($(this));
- base.resizeNow();
- }); // End Load
- };
-
- // Update thumbnails (if enabled)
- if (base.options.thumbnail_navigation == 1){
-
- // Load previous thumbnail
- vars.current_slide - 1 < 0 ? prevThumb = base.options.slides.length - 1 : prevThumb = vars.current_slide - 1;
- $(vars.prev_thumb).html($("
").attr("src", base.options.slides[prevThumb].image));
-
- // Load next thumbnail
- nextThumb = loadSlide;
- $(vars.next_thumb).html($("
").attr("src", base.options.slides[nextThumb].image));
-
- }
-
-
-
- /*-----End Load Image-----*/
-
-
- // Call theme function for before slide transition
- if( typeof theme != 'undefined' && typeof theme.beforeAnimation == "function" ) theme.beforeAnimation('next');
-
- //Update slide markers
- if (base.options.slide_links){
- $('.current-slide').removeClass('current-slide');
- $(vars.slide_list +'> li' ).eq(vars.current_slide).addClass('current-slide');
- }
-
- nextslide.css('visibility','hidden').addClass('activeslide'); // Update active slide
-
- switch(base.options.transition){
- case 0: case 'none': // No transition
- nextslide.css('visibility','visible'); vars.in_animation = false; base.afterAnimation();
- break;
- case 1: case 'fade': // Fade
- nextslide.css({opacity : 0, 'visibility': 'visible'}).animate({opacity : 1, avoidTransforms : false}, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 2: case 'slideTop': // Slide Top
- nextslide.css({top : -base.$el.height(), 'visibility': 'visible'}).animate({ top:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 3: case 'slideRight': // Slide Right
- nextslide.css({left : base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 4: case 'slideBottom': // Slide Bottom
- nextslide.css({top : base.$el.height(), 'visibility': 'visible'}).animate({ top:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 5: case 'slideLeft': // Slide Left
- nextslide.css({left : -base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 6: case 'carouselRight': // Carousel Right
- nextslide.css({left : base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- liveslide.animate({ left: -base.$el.width(), avoidTransforms : false }, base.options.transition_speed );
- break;
- case 7: case 'carouselLeft': // Carousel Left
- nextslide.css({left : -base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- liveslide.animate({ left: base.$el.width(), avoidTransforms : false }, base.options.transition_speed );
- break;
- }
- return false;
- };
-
-
- /* Previous Slide
- ----------------------------*/
- base.prevSlide = function(){
-
- if(vars.in_animation || !api.options.slideshow) return false; // Abort if currently animating
- else vars.in_animation = true; // Otherwise set animation marker
-
- clearInterval(vars.slideshow_interval); // Stop slideshow
-
- var slides = base.options.slides, // Pull in slides array
- liveslide = base.$el.find('.activeslide'); // Find active slide
- $('.prevslide').removeClass('prevslide');
- liveslide.removeClass('activeslide').addClass('prevslide'); // Remove active class & update previous slide
-
- // Get current slide number
- vars.current_slide == 0 ? vars.current_slide = base.options.slides.length - 1 : vars.current_slide-- ;
-
- var nextslide = $(base.el+' li:eq('+vars.current_slide+')'),
- prevslide = base.$el.find('.prevslide');
-
- // If hybrid mode is on drop quality for transition
- if (base.options.performance == 1) base.$el.removeClass('quality').addClass('speed');
-
-
- /*-----Load Image-----*/
-
- loadSlide = vars.current_slide;
-
- var targetList = base.el+' li:eq('+loadSlide+')';
- if (!$(targetList).html()){
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
- imageLink = (base.options.slides[loadSlide].url) ? "href='" + base.options.slides[loadSlide].url + "'" : ""; // If link exists, build it
- var img = $('
');
-
- img.appendTo(targetList).wrap('
').parent().parent().addClass('image-loading').css('visibility','hidden');
-
- img.load(function(){
- base._origDim($(this));
- base.resizeNow();
- }); // End Load
- };
-
- // Update thumbnails (if enabled)
- if (base.options.thumbnail_navigation == 1){
-
- // Load previous thumbnail
- //prevThumb = loadSlide;
- loadSlide == 0 ? prevThumb = base.options.slides.length - 1 : prevThumb = loadSlide - 1;
- $(vars.prev_thumb).html($("
").attr("src", base.options.slides[prevThumb].image));
-
- // Load next thumbnail
- vars.current_slide == base.options.slides.length - 1 ? nextThumb = 0 : nextThumb = vars.current_slide + 1;
- $(vars.next_thumb).html($("
").attr("src", base.options.slides[nextThumb].image));
- }
-
- /*-----End Load Image-----*/
-
-
- // Call theme function for before slide transition
- if( typeof theme != 'undefined' && typeof theme.beforeAnimation == "function" ) theme.beforeAnimation('prev');
-
- //Update slide markers
- if (base.options.slide_links){
- $('.current-slide').removeClass('current-slide');
- $(vars.slide_list +'> li' ).eq(vars.current_slide).addClass('current-slide');
- }
-
- nextslide.css('visibility','hidden').addClass('activeslide'); // Update active slide
-
- switch(base.options.transition){
- case 0: case 'none': // No transition
- nextslide.css('visibility','visible'); vars.in_animation = false; base.afterAnimation();
- break;
- case 1: case 'fade': // Fade
- nextslide.css({opacity : 0, 'visibility': 'visible'}).animate({opacity : 1, avoidTransforms : false}, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 2: case 'slideTop': // Slide Top (reverse)
- nextslide.css({top : base.$el.height(), 'visibility': 'visible'}).animate({ top:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 3: case 'slideRight': // Slide Right (reverse)
- nextslide.css({left : -base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 4: case 'slideBottom': // Slide Bottom (reverse)
- nextslide.css({top : -base.$el.height(), 'visibility': 'visible'}).animate({ top:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 5: case 'slideLeft': // Slide Left (reverse)
- nextslide.css({left : base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- break;
- case 6: case 'carouselRight': // Carousel Right (reverse)
- nextslide.css({left : -base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- liveslide.css({left : 0}).animate({ left: base.$el.width(), avoidTransforms : false}, base.options.transition_speed );
- break;
- case 7: case 'carouselLeft': // Carousel Left (reverse)
- nextslide.css({left : base.$el.width(), 'visibility': 'visible'}).animate({ left:0, avoidTransforms : false }, base.options.transition_speed, function(){ base.afterAnimation(); });
- liveslide.css({left : 0}).animate({ left: -base.$el.width(), avoidTransforms : false }, base.options.transition_speed );
- break;
- }
- return false;
- };
-
-
- /* Play/Pause Toggle
- ----------------------------*/
- base.playToggle = function(){
-
- if (vars.in_animation || !api.options.slideshow) return false; // Abort if currently animating
-
- if (vars.is_paused){
-
- vars.is_paused = false;
-
- // Call theme function for play
- if( typeof theme != 'undefined' && typeof theme.playToggle == "function" ) theme.playToggle('play');
-
- // Resume slideshow
- vars.slideshow_interval = setInterval(base.nextSlide, base.options.slide_interval);
-
- }else{
-
- vars.is_paused = true;
-
- // Call theme function for pause
- if( typeof theme != 'undefined' && typeof theme.playToggle == "function" ) theme.playToggle('pause');
-
- // Stop slideshow
- clearInterval(vars.slideshow_interval);
-
- }
-
- return false;
-
- };
-
-
- /* Go to specific slide
- ----------------------------*/
- base.goTo = function(targetSlide){
- if (vars.in_animation || !api.options.slideshow) return false; // Abort if currently animating
-
- var totalSlides = base.options.slides.length;
-
- // If target outside range
- if(targetSlide < 0){
- targetSlide = totalSlides;
- }else if(targetSlide > totalSlides){
- targetSlide = 1;
- }
- targetSlide = totalSlides - targetSlide + 1;
-
- clearInterval(vars.slideshow_interval); // Stop slideshow, prevent buildup
-
- // Call theme function for goTo trigger
- if (typeof theme != 'undefined' && typeof theme.goTo == "function" ) theme.goTo();
-
- if (vars.current_slide == totalSlides - targetSlide){
- if(!(vars.is_paused)){
- vars.slideshow_interval = setInterval(base.nextSlide, base.options.slide_interval);
- }
- return false;
- }
-
- // If ahead of current position
- if(totalSlides - targetSlide > vars.current_slide ){
-
- // Adjust for new next slide
- vars.current_slide = totalSlides-targetSlide-1;
- vars.update_images = 'next';
- base._placeSlide(vars.update_images);
-
- //Otherwise it's before current position
- }else if(totalSlides - targetSlide < vars.current_slide){
-
- // Adjust for new prev slide
- vars.current_slide = totalSlides-targetSlide+1;
- vars.update_images = 'prev';
- base._placeSlide(vars.update_images);
-
- }
-
- // set active markers
- if (base.options.slide_links){
- $(vars.slide_list +'> .current-slide').removeClass('current-slide');
- $(vars.slide_list +'> li').eq((totalSlides-targetSlide)).addClass('current-slide');
- }
-
- if (base.options.thumb_links){
- $(vars.thumb_list +'> .current-thumb').removeClass('current-thumb');
- $(vars.thumb_list +'> li').eq((totalSlides-targetSlide)).addClass('current-thumb');
- }
-
- };
-
-
- /* Place Slide
- ----------------------------*/
- base._placeSlide = function(place){
-
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
-
- loadSlide = false;
-
- if (place == 'next'){
-
- vars.current_slide == base.options.slides.length - 1 ? loadSlide = 0 : loadSlide = vars.current_slide + 1; // Determine next slide
-
- var targetList = base.el+' li:eq('+loadSlide+')';
-
- if (!$(targetList).html()){
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
-
- imageLink = (base.options.slides[loadSlide].url) ? "href='" + base.options.slides[loadSlide].url + "'" : ""; // If link exists, build it
- var img = $('
');
-
- img.appendTo(targetList).wrap('
').parent().parent().addClass('image-loading').css('visibility','hidden');
-
- img.load(function(){
- base._origDim($(this));
- base.resizeNow();
- }); // End Load
- };
-
- base.nextSlide();
-
- }else if (place == 'prev'){
-
- vars.current_slide - 1 < 0 ? loadSlide = base.options.slides.length - 1 : loadSlide = vars.current_slide - 1; // Determine next slide
-
- var targetList = base.el+' li:eq('+loadSlide+')';
-
- if (!$(targetList).html()){
- // If links should open in new window
- var linkTarget = base.options.new_window ? ' target="_blank"' : '';
-
- imageLink = (base.options.slides[loadSlide].url) ? "href='" + base.options.slides[loadSlide].url + "'" : ""; // If link exists, build it
- var img = $('
');
-
- img.appendTo(targetList).wrap('
').parent().parent().addClass('image-loading').css('visibility','hidden');
-
- img.load(function(){
- base._origDim($(this));
- base.resizeNow();
- }); // End Load
- };
- base.prevSlide();
- }
-
- };
-
-
- /* Get Original Dimensions
- ----------------------------*/
- base._origDim = function(targetSlide){
- targetSlide.data('origWidth', targetSlide.width()).data('origHeight', targetSlide.height());
- };
-
-
- /* After Slide Animation
- ----------------------------*/
- base.afterAnimation = function(){
-
- // If hybrid mode is on swap back to higher image quality
- if (base.options.performance == 1){
- base.$el.removeClass('speed').addClass('quality');
- }
-
- // Update previous slide
- if (vars.update_images){
- vars.current_slide - 1 < 0 ? setPrev = base.options.slides.length - 1 : setPrev = vars.current_slide-1;
- vars.update_images = false;
- $('.prevslide').removeClass('prevslide');
- $(base.el+' li:eq('+setPrev+')').addClass('prevslide');
- }
-
- vars.in_animation = false;
-
- // Resume slideshow
- if (!vars.is_paused && base.options.slideshow){
- vars.slideshow_interval = setInterval(base.nextSlide, base.options.slide_interval);
- if (base.options.stop_loop && vars.current_slide == base.options.slides.length - 1 ) base.playToggle();
- }
-
- // Call theme function for after slide transition
- if (typeof theme != 'undefined' && typeof theme.afterAnimation == "function" ) theme.afterAnimation();
-
- return false;
-
- };
-
- base.getField = function(field){
- return base.options.slides[vars.current_slide][field];
- };
-
- // Make it go!
- base.init();
- };
-
-
- /* Global Variables
- ----------------------------*/
- $.supersized.vars = {
-
- // Elements
- thumb_tray : '#thumb-tray', // Thumbnail tray
- thumb_list : '#thumb-list', // Thumbnail list
- slide_list : '#slide-list', // Slide link list
-
- // Internal variables
- current_slide : 0, // Current slide number
- in_animation : false, // Prevents animations from stacking
- is_paused : false, // Tracks paused on/off
- hover_pause : false, // If slideshow is paused from hover
- slideshow_interval : false, // Stores slideshow timer
- update_images : false, // Trigger to update images after slide jump
- options : {} // Stores assembled options list
-
- };
-
-
- /* Default Options
- ----------------------------*/
- $.supersized.defaultOptions = {
-
- // Functionality
- slideshow : 1, // Slideshow on/off
- autoplay : 1, // Slideshow starts playing automatically
- start_slide : 1, // Start slide (0 is random)
- stop_loop : 0, // Stops slideshow on last slide
- random : 0, // Randomize slide order (Ignores start slide)
- slide_interval : 5000, // Length between transitions
- transition : 1, // 0-None, 1-Fade, 2-Slide Top, 3-Slide Right, 4-Slide Bottom, 5-Slide Left, 6-Carousel Right, 7-Carousel Left
- transition_speed : 750, // Speed of transition
- new_window : 1, // Image links open in new window/tab
- pause_hover : 0, // Pause slideshow on hover
- keyboard_nav : 1, // Keyboard navigation on/off
- performance : 1, // 0-Normal, 1-Hybrid speed/quality, 2-Optimizes image quality, 3-Optimizes transition speed // (Only works for Firefox/IE, not Webkit)
- image_protect : 1, // Disables image dragging and right click with Javascript
-
- // Size & Position
- fit_always : 0, // Image will never exceed browser width or height (Ignores min. dimensions)
- fit_landscape : 0, // Landscape images will not exceed browser width
- fit_portrait : 1, // Portrait images will not exceed browser height
- min_width : 0, // Min width allowed (in pixels)
- min_height : 0, // Min height allowed (in pixels)
- horizontal_center : 1, // Horizontally center background
- vertical_center : 1, // Vertically center background
-
-
- // Components
- slide_links : 1, // Individual links for each slide (Options: false, 'num', 'name', 'blank')
- thumb_links : 1, // Individual thumb links for each slide
- thumbnail_navigation : 0 // Thumbnail navigation
-
- };
-
- $.fn.supersized = function(options){
- return this.each(function(){
- (new $.supersized(options));
- });
- };
-
-})(jQuery);
-
diff --git a/sites/all/libraries/supersized/slideshow/js/supersized.3.2.7.min.js b/sites/all/libraries/supersized/slideshow/js/supersized.3.2.7.min.js
deleted file mode 100755
index c8e70814..00000000
--- a/sites/all/libraries/supersized/slideshow/js/supersized.3.2.7.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
-
- Supersized - Fullscreen Slideshow jQuery Plugin
- Version : 3.2.7
- Site : www.buildinternet.com/project/supersized
-
- Author : Sam Dunn
- Company : One Mighty Roar (www.onemightyroar.com)
- License : MIT License / GPL License
-
-*/(function(e){e(document).ready(function(){e("body").append('
')});e.supersized=function(t){var n="#supersized",r=this;r.$el=e(n);r.el=n;vars=e.supersized.vars;r.$el.data("supersized",r);api=r.$el.data("supersized");r.init=function(){e.supersized.vars=e.extend(e.supersized.vars,e.supersized.themeVars);e.supersized.vars.options=e.extend({},e.supersized.defaultOptions,e.supersized.themeOptions,t);r.options=e.supersized.vars.options;r._build()};r._build=function(){var t=0,n="",i="",s,o="",u;while(t<=r.options.slides.length-1){switch(r.options.slide_links){case"num":s=t;break;case"name":s=r.options.slides[t].title;break;case"blank":s=""}n=n+'
';if(t==r.options.start_slide-1){r.options.slide_links&&(i=i+'
'+s+" ");if(r.options.thumb_links){r.options.slides[t].thumb?u=r.options.slides[t].thumb:u=r.options.slides[t].image;o=o+'
'}}else{r.options.slide_links&&(i=i+'
'+s+" ");if(r.options.thumb_links){r.options.slides[t].thumb?u=r.options.slides[t].thumb:u=r.options.slides[t].image;o=o+'
'}}t++}r.options.slide_links&&e(vars.slide_list).html(i);r.options.thumb_links&&vars.thumb_tray.length&&e(vars.thumb_tray).append('
");e(r.el).append(n);if(r.options.thumbnail_navigation){vars.current_slide-1<0?prevThumb=r.options.slides.length-1:prevThumb=vars.current_slide-1;e(vars.prev_thumb).show().html(e("
").attr("src",r.options.slides[prevThumb].image));vars.current_slide==r.options.slides.length-1?nextThumb=0:nextThumb=vars.current_slide+1;e(vars.next_thumb).show().html(e("
").attr("src",r.options.slides[nextThumb].image))}r._start()};r._start=function(){r.options.start_slide?vars.current_slide=r.options.start_slide-1:vars.current_slide=Math.floor(Math.random()*r.options.slides.length);var t=r.options.new_window?' target="_blank"':"";r.options.performance==3?r.$el.addClass("speed"):(r.options.performance==1||r.options.performance==2)&&r.$el.addClass("quality");if(r.options.random){arr=r.options.slides;for(var n,i,s=arr.length;s;n=parseInt(Math.random()*s),i=arr[--s],arr[s]=arr[n],arr[n]=i);r.options.slides=arr}if(r.options.slides.length>1){if(r.options.slides.length>2){vars.current_slide-1<0?loadPrev=r.options.slides.length-1:loadPrev=vars.current_slide-1;var o=r.options.slides[loadPrev].url?"href='"+r.options.slides[loadPrev].url+"'":"",u=e('
'),a=r.el+" li:eq("+loadPrev+")";u.appendTo(a).wrap("
").parent().parent().addClass("image-loading prevslide");u.load(function(){e(this).data("origWidth",e(this).width()).data("origHeight",e(this).height());r.resizeNow()})}}else r.options.slideshow=0;o=api.getField("url")?"href='"+api.getField("url")+"'":"";var f=e('
'),l=r.el+" li:eq("+vars.current_slide+")";f.appendTo(l).wrap("
").parent().parent().addClass("image-loading activeslide");f.load(function(){r._origDim(e(this));r.resizeNow();r.launch();typeof theme!="undefined"&&typeof theme._init=="function"&&theme._init()});if(r.options.slides.length>1){vars.current_slide==r.options.slides.length-1?loadNext=0:loadNext=vars.current_slide+1;o=r.options.slides[loadNext].url?"href='"+r.options.slides[loadNext].url+"'":"";var c=e('
'),h=r.el+" li:eq("+loadNext+")";c.appendTo(h).wrap("
").parent().parent().addClass("image-loading");c.load(function(){e(this).data("origWidth",e(this).width()).data("origHeight",e(this).height());r.resizeNow()})}r.$el.css("visibility","hidden");e(".load-item").hide()};r.launch=function(){r.$el.css("visibility","visible");e("#supersized-loader").remove();typeof theme!="undefined"&&typeof theme.beforeAnimation=="function"&&theme.beforeAnimation("next");e(".load-item").show();r.options.keyboard_nav&&e(document.documentElement).keyup(function(e){if(vars.in_animation)return!1;if(e.keyCode==37||e.keyCode==40){clearInterval(vars.slideshow_interval);r.prevSlide()}else if(e.keyCode==39||e.keyCode==38){clearInterval(vars.slideshow_interval);r.nextSlide()}else if(e.keyCode==32&&!vars.hover_pause){clearInterval(vars.slideshow_interval);r.playToggle()}});r.options.slideshow&&r.options.pause_hover&&e(r.el).hover(function(){if(vars.in_animation)return!1;vars.hover_pause=!0;if(!vars.is_paused){vars.hover_pause="resume";r.playToggle()}},function(){if(vars.hover_pause=="resume"){r.playToggle();vars.hover_pause=!1}});r.options.slide_links&&e(vars.slide_list+"> li").click(function(){index=e(vars.slide_list+"> li").index(this);targetSlide=index+1;r.goTo(targetSlide);return!1});r.options.thumb_links&&e(vars.thumb_list+"> li").click(function(){index=e(vars.thumb_list+"> li").index(this);targetSlide=index+1;api.goTo(targetSlide);return!1});if(r.options.slideshow&&r.options.slides.length>1){r.options.autoplay&&r.options.slides.length>1?vars.slideshow_interval=setInterval(r.nextSlide,r.options.slide_interval):vars.is_paused=!0;e(".load-item img").bind("contextmenu mousedown",function(){return!1})}e(window).resize(function(){r.resizeNow()})};r.resizeNow=function(){return r.$el.each(function(){e("img",r.el).each(function(){function o(e){if(e){if(thisSlide.width()
=r.options.min_height){thisSlide.width(r.options.min_width);thisSlide.height(thisSlide.width()*t)}else u()}else if(r.options.min_height>=i&&!r.options.fit_landscape){if(n*t>=r.options.min_height||n*t>=r.options.min_height&&t<=1){thisSlide.width(n);thisSlide.height(n*t)}else if(t>1){thisSlide.height(r.options.min_height);thisSlide.width(thisSlide.height()/t)}else if(thisSlide.width()=r.options.min_width){thisSlide.height(r.options.min_height);thisSlide.width(thisSlide.height()/t)}else o(!0)}else if(r.options.min_width>=n){if(i/t>=r.options.min_width||t>1){thisSlide.height(i);thisSlide.width(i/t)}else if(t<=1){thisSlide.width(r.options.min_width);thisSlide.height(thisSlide.width()*t)}}else{thisSlide.height(i);thisSlide.width(i/t)}}thisSlide=e(this);var t=(thisSlide.data("origHeight")/thisSlide.data("origWidth")).toFixed(2),n=r.$el.width(),i=r.$el.height(),s;r.options.fit_always?i/n>t?o():u():i<=r.options.min_height&&n<=r.options.min_width?i/n>t?r.options.fit_landscape&&t<1?o(!0):u(!0):r.options.fit_portrait&&t>=1?u(!0):o(!0):n<=r.options.min_width?i/n>t?r.options.fit_landscape&&t<1?o(!0):u():r.options.fit_portrait&&t>=1?u():o(!0):i<=r.options.min_height?i/n>t?r.options.fit_landscape&&t<1?o():u(!0):r.options.fit_portrait&&t>=1?u(!0):o():i/n>t?r.options.fit_landscape&&t<1?o():u():r.options.fit_portrait&&t>=1?u():o();thisSlide.parents("li").hasClass("image-loading")&&e(".image-loading").removeClass("image-loading");r.options.horizontal_center&&e(this).css("left",(n-e(this).width())/2);r.options.vertical_center&&e(this).css("top",(i-e(this).height())/2)});r.options.image_protect&&e("img",r.el).bind("contextmenu mousedown",function(){return!1});return!1})};r.nextSlide=function(){if(vars.in_animation||!api.options.slideshow)return!1;vars.in_animation=!0;clearInterval(vars.slideshow_interval);var t=r.options.slides,n=r.$el.find(".activeslide");e(".prevslide").removeClass("prevslide");n.removeClass("activeslide").addClass("prevslide");vars.current_slide+1==r.options.slides.length?vars.current_slide=0:vars.current_slide++;var i=e(r.el+" li:eq("+vars.current_slide+")"),s=r.$el.find(".prevslide");r.options.performance==1&&r.$el.removeClass("quality").addClass("speed");loadSlide=!1;vars.current_slide==r.options.slides.length-1?loadSlide=0:loadSlide=vars.current_slide+1;var o=r.el+" li:eq("+loadSlide+")";if(!e(o).html()){var u=r.options.new_window?' target="_blank"':"";imageLink=r.options.slides[loadSlide].url?"href='"+r.options.slides[loadSlide].url+"'":"";var a=e(' ');a.appendTo(o).wrap(" ").parent().parent().addClass("image-loading").css("visibility","hidden");a.load(function(){r._origDim(e(this));r.resizeNow()})}if(r.options.thumbnail_navigation==1){vars.current_slide-1<0?prevThumb=r.options.slides.length-1:prevThumb=vars.current_slide-1;e(vars.prev_thumb).html(e(" ").attr("src",r.options.slides[prevThumb].image));nextThumb=loadSlide;e(vars.next_thumb).html(e(" ").attr("src",r.options.slides[nextThumb].image))}typeof theme!="undefined"&&typeof theme.beforeAnimation=="function"&&theme.beforeAnimation("next");if(r.options.slide_links){e(".current-slide").removeClass("current-slide");e(vars.slide_list+"> li").eq(vars.current_slide).addClass("current-slide")}i.css("visibility","hidden").addClass("activeslide");switch(r.options.transition){case 0:case"none":i.css("visibility","visible");vars.in_animation=!1;r.afterAnimation();break;case 1:case"fade":i.css({opacity:0,visibility:"visible"}).animate({opacity:1,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 2:case"slideTop":i.css({top:-r.$el.height(),visibility:"visible"}).animate({top:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 3:case"slideRight":i.css({left:r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 4:case"slideBottom":i.css({top:r.$el.height(),visibility:"visible"}).animate({top:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 5:case"slideLeft":i.css({left:-r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 6:case"carouselRight":i.css({left:r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});n.animate({left:-r.$el.width(),avoidTransforms:!1},r.options.transition_speed);break;case 7:case"carouselLeft":i.css({left:-r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});n.animate({left:r.$el.width(),avoidTransforms:!1},r.options.transition_speed)}return!1};r.prevSlide=function(){if(vars.in_animation||!api.options.slideshow)return!1;vars.in_animation=!0;clearInterval(vars.slideshow_interval);var t=r.options.slides,n=r.$el.find(".activeslide");e(".prevslide").removeClass("prevslide");n.removeClass("activeslide").addClass("prevslide");vars.current_slide==0?vars.current_slide=r.options.slides.length-1:vars.current_slide--;var i=e(r.el+" li:eq("+vars.current_slide+")"),s=r.$el.find(".prevslide");r.options.performance==1&&r.$el.removeClass("quality").addClass("speed");loadSlide=vars.current_slide;var o=r.el+" li:eq("+loadSlide+")";if(!e(o).html()){var u=r.options.new_window?' target="_blank"':"";imageLink=r.options.slides[loadSlide].url?"href='"+r.options.slides[loadSlide].url+"'":"";var a=e(' ');a.appendTo(o).wrap(" ").parent().parent().addClass("image-loading").css("visibility","hidden");a.load(function(){r._origDim(e(this));r.resizeNow()})}if(r.options.thumbnail_navigation==1){loadSlide==0?prevThumb=r.options.slides.length-1:prevThumb=loadSlide-1;e(vars.prev_thumb).html(e(" ").attr("src",r.options.slides[prevThumb].image));vars.current_slide==r.options.slides.length-1?nextThumb=0:nextThumb=vars.current_slide+1;e(vars.next_thumb).html(e(" ").attr("src",r.options.slides[nextThumb].image))}typeof theme!="undefined"&&typeof theme.beforeAnimation=="function"&&theme.beforeAnimation("prev");if(r.options.slide_links){e(".current-slide").removeClass("current-slide");e(vars.slide_list+"> li").eq(vars.current_slide).addClass("current-slide")}i.css("visibility","hidden").addClass("activeslide");switch(r.options.transition){case 0:case"none":i.css("visibility","visible");vars.in_animation=!1;r.afterAnimation();break;case 1:case"fade":i.css({opacity:0,visibility:"visible"}).animate({opacity:1,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 2:case"slideTop":i.css({top:r.$el.height(),visibility:"visible"}).animate({top:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 3:case"slideRight":i.css({left:-r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 4:case"slideBottom":i.css({top:-r.$el.height(),visibility:"visible"}).animate({top:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 5:case"slideLeft":i.css({left:r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});break;case 6:case"carouselRight":i.css({left:-r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});n.css({left:0}).animate({left:r.$el.width(),avoidTransforms:!1},r.options.transition_speed);break;case 7:case"carouselLeft":i.css({left:r.$el.width(),visibility:"visible"}).animate({left:0,avoidTransforms:!1},r.options.transition_speed,function(){r.afterAnimation()});n.css({left:0}).animate({left:-r.$el.width(),avoidTransforms:!1},r.options.transition_speed)}return!1};r.playToggle=function(){if(vars.in_animation||!api.options.slideshow)return!1;if(vars.is_paused){vars.is_paused=!1;typeof theme!="undefined"&&typeof theme.playToggle=="function"&&theme.playToggle("play");vars.slideshow_interval=setInterval(r.nextSlide,r.options.slide_interval)}else{vars.is_paused=!0;typeof theme!="undefined"&&typeof theme.playToggle=="function"&&theme.playToggle("pause");clearInterval(vars.slideshow_interval)}return!1};r.goTo=function(t){if(vars.in_animation||!api.options.slideshow)return!1;var n=r.options.slides.length;t<0?t=n:t>n&&(t=1);t=n-t+1;clearInterval(vars.slideshow_interval);typeof theme!="undefined"&&typeof theme.goTo=="function"&&theme.goTo();if(vars.current_slide==n-t){vars.is_paused||(vars.slideshow_interval=setInterval(r.nextSlide,r.options.slide_interval));return!1}if(n-t>vars.current_slide){vars.current_slide=n-t-1;vars.update_images="next";r._placeSlide(vars.update_images)}else if(n-t .current-slide").removeClass("current-slide");e(vars.slide_list+"> li").eq(n-t).addClass("current-slide")}if(r.options.thumb_links){e(vars.thumb_list+"> .current-thumb").removeClass("current-thumb");e(vars.thumb_list+"> li").eq(n-t).addClass("current-thumb")}};r._placeSlide=function(t){var n=r.options.new_window?' target="_blank"':"";loadSlide=!1;if(t=="next"){vars.current_slide==r.options.slides.length-1?loadSlide=0:loadSlide=vars.current_slide+1;var i=r.el+" li:eq("+loadSlide+")";if(!e(i).html()){var n=r.options.new_window?' target="_blank"':"";imageLink=r.options.slides[loadSlide].url?"href='"+r.options.slides[loadSlide].url+"'":"";var s=e(' ');s.appendTo(i).wrap(" ").parent().parent().addClass("image-loading").css("visibility","hidden");s.load(function(){r._origDim(e(this));r.resizeNow()})}r.nextSlide()}else if(t=="prev"){vars.current_slide-1<0?loadSlide=r.options.slides.length-1:loadSlide=vars.current_slide-1;var i=r.el+" li:eq("+loadSlide+")";if(!e(i).html()){var n=r.options.new_window?' target="_blank"':"";imageLink=r.options.slides[loadSlide].url?"href='"+r.options.slides[loadSlide].url+"'":"";var s=e(' ');s.appendTo(i).wrap(" ").parent().parent().addClass("image-loading").css("visibility","hidden");s.load(function(){r._origDim(e(this));r.resizeNow()})}r.prevSlide()}};r._origDim=function(e){e.data("origWidth",e.width()).data("origHeight",e.height())};r.afterAnimation=function(){r.options.performance==1&&r.$el.removeClass("speed").addClass("quality");if(vars.update_images){vars.current_slide-1<0?setPrev=r.options.slides.length-1:setPrev=vars.current_slide-1;vars.update_images=!1;e(".prevslide").removeClass("prevslide");e(r.el+" li:eq("+setPrev+")").addClass("prevslide")}vars.in_animation=!1;if(!vars.is_paused&&r.options.slideshow){vars.slideshow_interval=setInterval(r.nextSlide,r.options.slide_interval);r.options.stop_loop&&vars.current_slide==r.options.slides.length-1&&r.playToggle()}typeof theme!="undefined"&&typeof theme.afterAnimation=="function"&&theme.afterAnimation();return!1};r.getField=function(e){return r.options.slides[vars.current_slide][e]};r.init()};e.supersized.vars={thumb_tray:"#thumb-tray",thumb_list:"#thumb-list",slide_list:"#slide-list",current_slide:0,in_animation:!1,is_paused:!1,hover_pause:!1,slideshow_interval:!1,update_images:!1,options:{}};e.supersized.defaultOptions={slideshow:1,autoplay:1,start_slide:1,stop_loop:0,random:0,slide_interval:5e3,transition:1,transition_speed:750,new_window:1,pause_hover:0,keyboard_nav:1,performance:1,image_protect:1,fit_always:0,fit_landscape:0,fit_portrait:1,min_width:0,min_height:0,horizontal_center:1,vertical_center:1,slide_links:1,thumb_links:1,thumbnail_navigation:0};e.fn.supersized=function(t){return this.each(function(){new e.supersized(t)})}})(jQuery);
\ No newline at end of file
diff --git a/sites/all/libraries/supersized/slideshow/slide.html b/sites/all/libraries/supersized/slideshow/slide.html
deleted file mode 100755
index 727db9a5..00000000
--- a/sites/all/libraries/supersized/slideshow/slide.html
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
-
-
-
- Supersized - Full Screen Background Slideshow jQuery Plugin
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.css b/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.css
deleted file mode 100755
index fa12aa6c..00000000
--- a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.css
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-
- Supersized - Fullscreen Slideshow jQuery Plugin
- Version : 3.2.7
- Site : www.buildinternet.com/project/supersized
-
- Theme : Shutter 1.2
- Author : Sam Dunn
- Company : One Mighty Roar (www.onemightyroar.com)
- License : MIT License / GPL License
-
-*/
-
- /* Controls Bar
- ----------------------------*/
- #controls-wrapper { margin:0 auto; height:42px; width:100%; bottom:0px; left:0; z-index:4; background:url(../img/nav-bg.png) repeat-x; position:fixed; }
- #controls { overflow:hidden; height:100%; position:relative; text-align:left; z-index:5; }
- #slidecounter { float:left; color:#999; font:14px "Helvetica Neue", Helvetica, Arial, sans-serif; text-shadow:#000 0 -1px 0; margin:0px 10px 0 15px; line-height:42px; }
- #slidecaption { overflow:hidden; float:left; color:#FFF; font:400 14px "Helvetica Neue", Helvetica, Arial, sans-serif; text-shadow:#000 1px 1px 2px; margin:0 20px 0 0; line-height:42px; }
-
- #navigation { float:right; margin:0px 20px 0 0; }
- #play-button{ float:left; margin-top:1px;border-right:1px solid #333; background:url('../img/bg-hover.png') repeat-x 0 44px; }
- #play-button:hover{ background-position:0 1px; cursor:pointer; }
-
- #prevslide, #nextslide{ position:absolute; height:43px; width:43px; top:50%; margin-top:-21px; opacity:0.6; }
- #prevslide{ left:10px; background:url('../img/back.png'); }
- #nextslide{ right:10px; background:url('../img/forward.png'); }
- #prevslide:active, #nextslide:active{ margin-top:-19px; }
- #prevslide:hover, #nextslide:hover{ cursor:pointer; }
-
- ul#slide-list{ padding:15px 0; float:left; position:absolute; left:50%; }
- ul#slide-list li{ list-style:none; width:12px; height:12px; float:left; margin:0 5px 0 0; }
- ul#slide-list li.current-slide a, ul#slide-list li.current-slide a:hover{ background-position:0 0px; }
- ul#slide-list li a{ display:block; width:12px; height:12px; background:url('../img/nav-dot.png') no-repeat 0 -24px; }
- ul#slide-list li a:hover{ background-position:0 -12px; cursor:pointer; }
-
- #tray-button{ float:right; margin-top:1px; border-left:1px solid #333; background:url('../img/bg-hover.png') repeat-x 0 44px; }
- #tray-button:hover{ background-position:0 1px; cursor:pointer; }
-
-
- /* Progress Bar
- ----------------------------*/
- #progress-back{ z-index:5; position:fixed; bottom:42px; left:0; height:8px; width:100%; background:url('../img/progress-back.png') repeat-x; }
- #progress-bar{ position:relative; height:8px; width:100%; background:url('../img/progress-bar.png') repeat-x; }
-
-
- /* Thumbnail Navigation
- ----------------------------*/
- #nextthumb,#prevthumb { z-index:2; display:none; position:fixed; bottom:61px; height:75px; width:100px; overflow:hidden; background:#ddd; border:1px solid #fff; -webkit-box-shadow:0 0 5px #000; }
- #nextthumb { right:12px; }
- #prevthumb { left:12px; }
- #nextthumb img, #prevthumb img { width:150px; height:auto; }
- #nextthumb:active, #prevthumb:active { bottom:59px; }
- #nextthumb:hover, #prevthumb:hover { cursor:pointer; }
-
-
- /* Thumbnail Tray
- ----------------------------*/
- #thumb-tray{ position:fixed; z-index:3; bottom:0; left:0; background:url(../img/bg-black.png); height:150px; width:100%; overflow:hidden; text-align:center; -moz-box-shadow: 0px 0px 4px #000; -webkit-box-shadow: 0px 0px 4px #000; box-shadow: 0px 0px 4px #000; }
-
- #thumb-back, #thumb-forward{ position:absolute; z-index:5; bottom:42px; height:108px; width:40px; }
- #thumb-back{ left:0; background: url('../img/thumb-back.png') no-repeat center center;}
- #thumb-forward{ right:0; background:url('../img/thumb-forward.png') no-repeat center center;}
- #thumb-back:hover, #thumb-forward:hover{ cursor:pointer; background-color:rgba(256,256,256, 0.1); }
- #thumb-back:hover{ border-right:1px solid rgba(256,256,256, 0.2); }
- #thumb-forward:hover{ border-left:1px solid rgba(256,256,256, 0.2); }
-
-
- ul#thumb-list{ display:inline-block; list-style:none; position:relative; left:0px; padding:0 0px; }
- ul#thumb-list li{ background:#111; list-style:none; display:inline; width:150px; height:108px; overflow:hidden; float:left; margin:0; }
- ul#thumb-list li img { width:200px; height:auto; opacity:0.5; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; filter:alpha(opacity=60); -webkit-transition: all 100ms ease-in-out; -moz-transition: all 100ms ease-in-out; -o-transition: all 100ms ease-in-out; -ms-transition: all 100ms ease-in-out; transition: all 100ms ease-in-out; }
- ul#thumb-list li.current-thumb img, ul#thumb-list li:hover img{ opacity:1; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); }
- ul#thumb-list li:hover{ cursor:pointer; }
-
\ No newline at end of file
diff --git a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.js b/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.js
deleted file mode 100755
index 218c15b5..00000000
--- a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.js
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
-
- Supersized - Fullscreen Slideshow jQuery Plugin
- Version : 3.2.7
- Theme : Shutter 1.1
-
- Site : www.buildinternet.com/project/supersized
- Author : Sam Dunn
- Company : One Mighty Roar (www.onemightyroar.com)
- License : MIT License / GPL License
-
-*/
-
-(function($){
-
- theme = {
-
-
- /* Initial Placement
- ----------------------------*/
- _init : function(){
-
- // Center Slide Links
- if (api.options.slide_links) $(vars.slide_list).css('margin-left', -$(vars.slide_list).width()/2);
-
- // Start progressbar if autoplay enabled
- if (api.options.autoplay){
- if (api.options.progress_bar) theme.progressBar();
- }else{
- if ($(vars.play_button).attr('src')) $(vars.play_button).attr("src", vars.image_path + "play.png"); // If pause play button is image, swap src
- if (api.options.progress_bar) $(vars.progress_bar).stop().css({left : -$(window).width()}); // Place progress bar
- }
-
-
- /* Thumbnail Tray
- ----------------------------*/
- // Hide tray off screen
- $(vars.thumb_tray).css({bottom : -$(vars.thumb_tray).height()});
-
- // Thumbnail Tray Toggle
- $(vars.tray_button).toggle(function(){
- $(vars.thumb_tray).stop().animate({bottom : 0, avoidTransforms : true}, 300 );
- if ($(vars.tray_arrow).attr('src')) $(vars.tray_arrow).attr("src", vars.image_path + "button-tray-down.png");
- return false;
- }, function() {
- $(vars.thumb_tray).stop().animate({bottom : -$(vars.thumb_tray).height(), avoidTransforms : true}, 300 );
- if ($(vars.tray_arrow).attr('src')) $(vars.tray_arrow).attr("src", vars.image_path + "button-tray-up.png");
- return false;
- });
-
- // Make thumb tray proper size
- $(vars.thumb_list).width($('> li', vars.thumb_list).length * $('> li', vars.thumb_list).outerWidth(true)); //Adjust to true width of thumb markers
-
- // Display total slides
- if ($(vars.slide_total).length){
- $(vars.slide_total).html(api.options.slides.length);
- }
-
-
- /* Thumbnail Tray Navigation
- ----------------------------*/
- if (api.options.thumb_links){
- //Hide thumb arrows if not needed
- if ($(vars.thumb_list).width() <= $(vars.thumb_tray).width()){
- $(vars.thumb_back +','+vars.thumb_forward).fadeOut(0);
- }
-
- // Thumb Intervals
- vars.thumb_interval = Math.floor($(vars.thumb_tray).width() / $('> li', vars.thumb_list).outerWidth(true)) * $('> li', vars.thumb_list).outerWidth(true);
- vars.thumb_page = 0;
-
- // Cycle thumbs forward
- $(vars.thumb_forward).click(function(){
- if (vars.thumb_page - vars.thumb_interval <= -$(vars.thumb_list).width()){
- vars.thumb_page = 0;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }else{
- vars.thumb_page = vars.thumb_page - vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }
- });
-
- // Cycle thumbs backwards
- $(vars.thumb_back).click(function(){
- if (vars.thumb_page + vars.thumb_interval > 0){
- vars.thumb_page = Math.floor($(vars.thumb_list).width() / vars.thumb_interval) * -vars.thumb_interval;
- if ($(vars.thumb_list).width() <= -vars.thumb_page) vars.thumb_page = vars.thumb_page + vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }else{
- vars.thumb_page = vars.thumb_page + vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }
- });
-
- }
-
-
- /* Navigation Items
- ----------------------------*/
- $(vars.next_slide).click(function() {
- api.nextSlide();
- });
-
- $(vars.prev_slide).click(function() {
- api.prevSlide();
- });
-
- // Full Opacity on Hover
- if(jQuery.support.opacity){
- $(vars.prev_slide +','+vars.next_slide).mouseover(function() {
- $(this).stop().animate({opacity:1},100);
- }).mouseout(function(){
- $(this).stop().animate({opacity:0.6},100);
- });
- }
-
- if (api.options.thumbnail_navigation){
- // Next thumbnail clicked
- $(vars.next_thumb).click(function() {
- api.nextSlide();
- });
- // Previous thumbnail clicked
- $(vars.prev_thumb).click(function() {
- api.prevSlide();
- });
- }
-
- $(vars.play_button).click(function() {
- api.playToggle();
- });
-
-
- /* Thumbnail Mouse Scrub
- ----------------------------*/
- if (api.options.mouse_scrub){
- $(vars.thumb_tray).mousemove(function(e) {
- var containerWidth = $(vars.thumb_tray).width(),
- listWidth = $(vars.thumb_list).width();
- if (listWidth > containerWidth){
- var mousePos = 1,
- diff = e.pageX - mousePos;
- if (diff > 10 || diff < -10) {
- mousePos = e.pageX;
- newX = (containerWidth - listWidth) * (e.pageX/containerWidth);
- diff = parseInt(Math.abs(parseInt($(vars.thumb_list).css('left'))-newX )).toFixed(0);
- $(vars.thumb_list).stop().animate({'left':newX}, {duration:diff*3, easing:'easeOutExpo'});
- }
- }
- });
- }
-
-
- /* Window Resize
- ----------------------------*/
- $(window).resize(function(){
-
- // Delay progress bar on resize
- if (api.options.progress_bar && !vars.in_animation){
- if (vars.slideshow_interval) clearInterval(vars.slideshow_interval);
- if (api.options.slides.length - 1 > 0) clearInterval(vars.slideshow_interval);
-
- $(vars.progress_bar).stop().css({left : -$(window).width()});
-
- if (!vars.progressDelay && api.options.slideshow){
- // Delay slideshow from resuming so Chrome can refocus images
- vars.progressDelay = setTimeout(function() {
- if (!vars.is_paused){
- theme.progressBar();
- vars.slideshow_interval = setInterval(api.nextSlide, api.options.slide_interval);
- }
- vars.progressDelay = false;
- }, 1000);
- }
- }
-
- // Thumb Links
- if (api.options.thumb_links && vars.thumb_tray.length){
- // Update Thumb Interval & Page
- vars.thumb_page = 0;
- vars.thumb_interval = Math.floor($(vars.thumb_tray).width() / $('> li', vars.thumb_list).outerWidth(true)) * $('> li', vars.thumb_list).outerWidth(true);
-
- // Adjust thumbnail markers
- if ($(vars.thumb_list).width() > $(vars.thumb_tray).width()){
- $(vars.thumb_back +','+vars.thumb_forward).fadeIn('fast');
- $(vars.thumb_list).stop().animate({'left':0}, 200);
- }else{
- $(vars.thumb_back +','+vars.thumb_forward).fadeOut('fast');
- }
-
- }
- });
-
-
- },
-
-
- /* Go To Slide
- ----------------------------*/
- goTo : function(){
- if (api.options.progress_bar && !vars.is_paused){
- $(vars.progress_bar).stop().css({left : -$(window).width()});
- theme.progressBar();
- }
- },
-
- /* Play & Pause Toggle
- ----------------------------*/
- playToggle : function(state){
-
- if (state =='play'){
- // If image, swap to pause
- if ($(vars.play_button).attr('src')) $(vars.play_button).attr("src", vars.image_path + "pause.png");
- if (api.options.progress_bar && !vars.is_paused) theme.progressBar();
- }else if (state == 'pause'){
- // If image, swap to play
- if ($(vars.play_button).attr('src')) $(vars.play_button).attr("src", vars.image_path + "play.png");
- if (api.options.progress_bar && vars.is_paused)$(vars.progress_bar).stop().css({left : -$(window).width()});
- }
-
- },
-
-
- /* Before Slide Transition
- ----------------------------*/
- beforeAnimation : function(direction){
- if (api.options.progress_bar && !vars.is_paused) $(vars.progress_bar).stop().css({left : -$(window).width()});
-
- /* Update Fields
- ----------------------------*/
- // Update slide caption
- if ($(vars.slide_caption).length){
- (api.getField('title')) ? $(vars.slide_caption).html(api.getField('title')) : $(vars.slide_caption).html('');
- }
- // Update slide number
- if (vars.slide_current.length){
- $(vars.slide_current).html(vars.current_slide + 1);
- }
-
-
- // Highlight current thumbnail and adjust row position
- if (api.options.thumb_links){
-
- $('.current-thumb').removeClass('current-thumb');
- $('li', vars.thumb_list).eq(vars.current_slide).addClass('current-thumb');
-
- // If thumb out of view
- if ($(vars.thumb_list).width() > $(vars.thumb_tray).width()){
- // If next slide direction
- if (direction == 'next'){
- if (vars.current_slide == 0){
- vars.thumb_page = 0;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- } else if ($('.current-thumb').offset().left - $(vars.thumb_tray).offset().left >= vars.thumb_interval){
- vars.thumb_page = vars.thumb_page - vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }
- // If previous slide direction
- }else if(direction == 'prev'){
- if (vars.current_slide == api.options.slides.length - 1){
- vars.thumb_page = Math.floor($(vars.thumb_list).width() / vars.thumb_interval) * -vars.thumb_interval;
- if ($(vars.thumb_list).width() <= -vars.thumb_page) vars.thumb_page = vars.thumb_page + vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- } else if ($('.current-thumb').offset().left - $(vars.thumb_tray).offset().left < 0){
- if (vars.thumb_page + vars.thumb_interval > 0) return false;
- vars.thumb_page = vars.thumb_page + vars.thumb_interval;
- $(vars.thumb_list).stop().animate({'left': vars.thumb_page}, {duration:500, easing:'easeOutExpo'});
- }
- }
- }
-
-
- }
-
- },
-
-
- /* After Slide Transition
- ----------------------------*/
- afterAnimation : function(){
- if (api.options.progress_bar && !vars.is_paused) theme.progressBar(); // Start progress bar
- },
-
-
- /* Progress Bar
- ----------------------------*/
- progressBar : function(){
- $(vars.progress_bar).stop().css({left : -$(window).width()}).animate({ left:0 }, api.options.slide_interval);
- }
-
-
- };
-
-
- /* Theme Specific Variables
- ----------------------------*/
- $.supersized.themeVars = {
-
- // Internal Variables
- progress_delay : false, // Delay after resize before resuming slideshow
- thumb_page : false, // Thumbnail page
- thumb_interval : false, // Thumbnail interval
- image_path : 'img/', // Default image path
-
- // General Elements
- play_button : '#pauseplay', // Play/Pause button
- next_slide : '#nextslide', // Next slide button
- prev_slide : '#prevslide', // Prev slide button
- next_thumb : '#nextthumb', // Next slide thumb button
- prev_thumb : '#prevthumb', // Prev slide thumb button
-
- slide_caption : '#slidecaption', // Slide caption
- slide_current : '.slidenumber', // Current slide number
- slide_total : '.totalslides', // Total Slides
- slide_list : '#slide-list', // Slide jump list
-
- thumb_tray : '#thumb-tray', // Thumbnail tray
- thumb_list : '#thumb-list', // Thumbnail list
- thumb_forward : '#thumb-forward', // Cycles forward through thumbnail list
- thumb_back : '#thumb-back', // Cycles backwards through thumbnail list
- tray_arrow : '#tray-arrow', // Thumbnail tray button arrow
- tray_button : '#tray-button', // Thumbnail tray button
-
- progress_bar : '#progress-bar' // Progress bar
-
- };
-
- /* Theme Specific Options
- ----------------------------*/
- $.supersized.themeOptions = {
-
- progress_bar : 0, // Timer for each slide
- mouse_scrub : 0 // Thumbnails move with mouse
-
- };
-
-
-})(jQuery);
diff --git a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.min.js b/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.min.js
deleted file mode 100755
index 62cdf847..00000000
--- a/sites/all/libraries/supersized/slideshow/theme/supersized.shutter.min.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
-
- Supersized - Fullscreen Slideshow jQuery Plugin
- Version : 3.2.7
- Theme : Shutter 1.1
-
- Site : www.buildinternet.com/project/supersized
- Author : Sam Dunn
- Company : One Mighty Roar (www.onemightyroar.com)
- License : MIT License / GPL License
-
-*/(function(e){theme={_init:function(){api.options.slide_links&&e(vars.slide_list).css("margin-left",-e(vars.slide_list).width()/2);if(api.options.autoplay)api.options.progress_bar&&theme.progressBar();else{e(vars.play_button).attr("src")&&e(vars.play_button).attr("src",vars.image_path+"play.png");api.options.progress_bar&&e(vars.progress_bar).stop().css({left:-e(window).width()})}e(vars.thumb_tray).css({bottom:-e(vars.thumb_tray).height()});e(vars.tray_button).toggle(function(){e(vars.thumb_tray).stop().animate({bottom:0,avoidTransforms:!0},300);e(vars.tray_arrow).attr("src")&&e(vars.tray_arrow).attr("src",vars.image_path+"button-tray-down.png");return!1},function(){e(vars.thumb_tray).stop().animate({bottom:-e(vars.thumb_tray).height(),avoidTransforms:!0},300);e(vars.tray_arrow).attr("src")&&e(vars.tray_arrow).attr("src",vars.image_path+"button-tray-up.png");return!1});e(vars.thumb_list).width(e("> li",vars.thumb_list).length*e("> li",vars.thumb_list).outerWidth(!0));e(vars.slide_total).length&&e(vars.slide_total).html(api.options.slides.length);if(api.options.thumb_links){e(vars.thumb_list).width()<=e(vars.thumb_tray).width()&&e(vars.thumb_back+","+vars.thumb_forward).fadeOut(0);vars.thumb_interval=Math.floor(e(vars.thumb_tray).width()/e("> li",vars.thumb_list).outerWidth(!0))*e("> li",vars.thumb_list).outerWidth(!0);vars.thumb_page=0;e(vars.thumb_forward).click(function(){if(vars.thumb_page-vars.thumb_interval<=-e(vars.thumb_list).width()){vars.thumb_page=0;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}else{vars.thumb_page=vars.thumb_page-vars.thumb_interval;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}});e(vars.thumb_back).click(function(){if(vars.thumb_page+vars.thumb_interval>0){vars.thumb_page=Math.floor(e(vars.thumb_list).width()/vars.thumb_interval)*-vars.thumb_interval;e(vars.thumb_list).width()<=-vars.thumb_page&&(vars.thumb_page=vars.thumb_page+vars.thumb_interval);e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}else{vars.thumb_page=vars.thumb_page+vars.thumb_interval;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}})}e(vars.next_slide).click(function(){api.nextSlide()});e(vars.prev_slide).click(function(){api.prevSlide()});jQuery.support.opacity&&e(vars.prev_slide+","+vars.next_slide).mouseover(function(){e(this).stop().animate({opacity:1},100)}).mouseout(function(){e(this).stop().animate({opacity:.6},100)});if(api.options.thumbnail_navigation){e(vars.next_thumb).click(function(){api.nextSlide()});e(vars.prev_thumb).click(function(){api.prevSlide()})}e(vars.play_button).click(function(){api.playToggle()});api.options.mouse_scrub&&e(vars.thumb_tray).mousemove(function(t){var n=e(vars.thumb_tray).width(),r=e(vars.thumb_list).width();if(r>n){var i=1,s=t.pageX-i;if(s>10||s<-10){i=t.pageX;newX=(n-r)*(t.pageX/n);s=parseInt(Math.abs(parseInt(e(vars.thumb_list).css("left"))-newX)).toFixed(0);e(vars.thumb_list).stop().animate({left:newX},{duration:s*3,easing:"easeOutExpo"})}}});e(window).resize(function(){if(api.options.progress_bar&&!vars.in_animation){vars.slideshow_interval&&clearInterval(vars.slideshow_interval);api.options.slides.length-1>0&&clearInterval(vars.slideshow_interval);e(vars.progress_bar).stop().css({left:-e(window).width()});!vars.progressDelay&&api.options.slideshow&&(vars.progressDelay=setTimeout(function(){if(!vars.is_paused){theme.progressBar();vars.slideshow_interval=setInterval(api.nextSlide,api.options.slide_interval)}vars.progressDelay=!1},1e3))}if(api.options.thumb_links&&vars.thumb_tray.length){vars.thumb_page=0;vars.thumb_interval=Math.floor(e(vars.thumb_tray).width()/e("> li",vars.thumb_list).outerWidth(!0))*e("> li",vars.thumb_list).outerWidth(!0);if(e(vars.thumb_list).width()>e(vars.thumb_tray).width()){e(vars.thumb_back+","+vars.thumb_forward).fadeIn("fast");e(vars.thumb_list).stop().animate({left:0},200)}else e(vars.thumb_back+","+vars.thumb_forward).fadeOut("fast")}})},goTo:function(){if(api.options.progress_bar&&!vars.is_paused){e(vars.progress_bar).stop().css({left:-e(window).width()});theme.progressBar()}},playToggle:function(t){if(t=="play"){e(vars.play_button).attr("src")&&e(vars.play_button).attr("src",vars.image_path+"pause.png");api.options.progress_bar&&!vars.is_paused&&theme.progressBar()}else if(t=="pause"){e(vars.play_button).attr("src")&&e(vars.play_button).attr("src",vars.image_path+"play.png");api.options.progress_bar&&vars.is_paused&&e(vars.progress_bar).stop().css({left:-e(window).width()})}},beforeAnimation:function(t){api.options.progress_bar&&!vars.is_paused&&e(vars.progress_bar).stop().css({left:-e(window).width()});e(vars.slide_caption).length&&(api.getField("title")?e(vars.slide_caption).html(api.getField("title")):e(vars.slide_caption).html(""));vars.slide_current.length&&e(vars.slide_current).html(vars.current_slide+1);if(api.options.thumb_links){e(".current-thumb").removeClass("current-thumb");e("li",vars.thumb_list).eq(vars.current_slide).addClass("current-thumb");if(e(vars.thumb_list).width()>e(vars.thumb_tray).width())if(t=="next"){if(vars.current_slide==0){vars.thumb_page=0;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}else if(e(".current-thumb").offset().left-e(vars.thumb_tray).offset().left>=vars.thumb_interval){vars.thumb_page=vars.thumb_page-vars.thumb_interval;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}}else if(t=="prev")if(vars.current_slide==api.options.slides.length-1){vars.thumb_page=Math.floor(e(vars.thumb_list).width()/vars.thumb_interval)*-vars.thumb_interval;e(vars.thumb_list).width()<=-vars.thumb_page&&(vars.thumb_page=vars.thumb_page+vars.thumb_interval);e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}else if(e(".current-thumb").offset().left-e(vars.thumb_tray).offset().left<0){if(vars.thumb_page+vars.thumb_interval>0)return!1;vars.thumb_page=vars.thumb_page+vars.thumb_interval;e(vars.thumb_list).stop().animate({left:vars.thumb_page},{duration:500,easing:"easeOutExpo"})}}},afterAnimation:function(){api.options.progress_bar&&!vars.is_paused&&theme.progressBar()},progressBar:function(){e(vars.progress_bar).stop().css({left:-e(window).width()}).animate({left:0},api.options.slide_interval)}};e.supersized.themeVars={progress_delay:!1,thumb_page:!1,thumb_interval:!1,image_path:"img/",play_button:"#pauseplay",next_slide:"#nextslide",prev_slide:"#prevslide",next_thumb:"#nextthumb",prev_thumb:"#prevthumb",slide_caption:"#slidecaption",slide_current:".slidenumber",slide_total:".totalslides",slide_list:"#slide-list",thumb_tray:"#thumb-tray",thumb_list:"#thumb-list",thumb_forward:"#thumb-forward",thumb_back:"#thumb-back",tray_arrow:"#tray-arrow",tray_button:"#tray-button",progress_bar:"#progress-bar"};e.supersized.themeOptions={progress_bar:1,mouse_scrub:0}})(jQuery);
\ No newline at end of file
diff --git a/sites/all/modules/README.txt b/sites/all/modules/README.txt
deleted file mode 100644
index c72b43e4..00000000
--- a/sites/all/modules/README.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-Place downloaded and custom modules that extend your site functionality beyond
-Drupal core in this directory to ensure clean separation from core modules and
-to facilitate safe, self-contained code updates. Contributed modules from the
-Drupal community may be downloaded at http://drupal.org/project/modules.
-
-It is safe to organize modules into subdirectories, such as "contrib" for
-contributed modules, and "custom" for custom modules. Note that if you move a
-module to a subdirectory after it has been enabled, you may need to clear the
-Drupal cache so that it can be found.
-
-In multisite configuration, modules found in this directory are available to
-all sites. Alternatively, the sites/your_site_name/modules directory pattern may
-be used to restrict modules to a specific site instance.
-
-Refer to the "Developing for Drupal" section of the README.txt in the Drupal
-root directory for further information on extending Drupal with custom modules.
diff --git a/sites/all/modules/contrib/admin_menu/CHANGELOG.txt b/sites/all/modules/contrib/admin_menu/CHANGELOG.txt
deleted file mode 100644
index b2dcdfef..00000000
--- a/sites/all/modules/contrib/admin_menu/CHANGELOG.txt
+++ /dev/null
@@ -1,366 +0,0 @@
-
-Admin Menu 7.x-3.x, xxxx-xx-xx
-------------------------------
-#1177202 by das-peter, dereine, sun: Fixed copying and re-injection of child
- router items breaks badly. Change them by reference instead.
- Requires latest Views 3.x code.
-#1212064 by sun: Updated admin_views default views for VBO 3.x.
-#1196590 by sun: Fixed errors and notices for admin_views with Views 3.
-#1144768 by idlewilder, sun: Fixed devel modules to skip are not displayed.
-#1079374 by WillHall: Fixed JS Error: unrecognized expression: [href=/].
-#1114132 by joelstein, sun: Added Field UI to list of developer modules.
-#1008380 by bdragon, sun: Updated admin_views for D7.
-#1146644 by sun: Fixed PHP 5.3 compability in tests.
-#442560 by sun: Fixed 'defer' script attribute breaks Drupal.behaviors in FF3.6.
-#1022902 by matglas86, sun: Updated for changed core Toolbar styles.
-
-
-Admin Menu 7.x-3.0-RC1, 2010-01-07
-----------------------------------
-#990774 by sun: Updated for $closure renamed to $page_bottom.
-#991906 by johnv, sun: Added configure to .info file.
-#947198 by sun: Added hint about disabling Toolbar.
-by sun: Updated administrative settings form for D7 UX guidelines.
-by sun: Disabled "Rebuild system links" button on settings form.
-#420816 by sun, smk-ka: Improved on-demand loading of dynamic paths.
-#420816 by tim.plunkett: Fixed dynamic Field UI paths for vocabularies.
-#871774 by swentel: Fixed developer modules toggle still uses referer_uri().
-#671760 by sun: Updated for new preprocess defaults.
-#731462 by sun: Updated for system_rebuild_theme_data().
-by sun: Re-added a "Rebuild system links" button to settings form.
-#420816 by tim.plunkett: Updated taxonomy path map for machine names.
-#857688 by sun: Updated for reverted system_settings_form().
-#420816 by smk-ka, sun: Added merging of menu trees containing dynamic paths.
-by sun: Fixed tests and minor admin_menu_toolbar styling issues.
-by sun: Fixed various styling issues for admin_menu and admin_menu_toolbar.
-by sun: Updated for Schema API, DBTNG, coding standards.
-by sun: Updated for new admin/modules path.
-#701424 by hutch: Updated for new admin/people/people path.
-by sun: Removed orphan menu rewrite function.
-#667858 by sun: Don't remove the current user from the switch user list.
-#631550 by sun: Updated for fixed MENU_VISIBLE_IN_BREADCRUMB behavior.
-#658344 by dereine, sun: Updated for removed drupal_session_count().
-by sun: Added separate permission to flush cashes.
-by sun: Updated for changed Devel settings form.
-by sun: Updated for new {system}.info module data.
-#614730 by azriprajwala, sun: Updated for hook_theme() key changes.
-by sun: Updated for all theme functions should take a single argument.
-by sun: Reverted removal of registry cache flushing option.
-#578520 by sun: Fixed destination query parameter is processed wrongly.
-#578520 by sun: Updated for $query in url() should always be an array.
-by Dave Reid: Updated for PHP 5 date constants.
-by sun: Updated for new database API.
-by smk-ka: Removed remnants of the registry. Fixed flush admin menu cache
- command.
-#567618 by smk-ka: Revised test cases. Abstracted out base web test class.
-by sun: Updated for removed registry, new admin paths.
-#326539 by sun: Updated for class attribute array.
-#519782 by sun: Updated for hook_footer() replaced by hook_page_alter().
-#525638 by Razorraser: Updated for admin/build renamed to admin/structure.
-by Dave Reid: Updated for hook_permission().
-#482314 by Dave Reid: Updated for node_type_get_types().
-#437506 by yched, Dave Reid: Updated for menu_router_build().
-#376816 by sun: Updated for compatibility for other JavaScript libraries.
-#337820 by Dave Reid: Updated for new user/logout path.
-#340546 by Dave Reid: Updated for drupal_add_js().
-#340531 by Dave Reid: Updated for module_list().
-#266358 by sun: Updated for drupal_add_css().
-#320526 by yettyn, sun: Updated to UNSTABLE-2 (DBTNG queries, permissions, etc).
-by sun: Changed admin_menu_wipe() to admin_menu_flush_caches().
-by sun: Updated content-type edit menu item locations.
-by sun: Fixed sess_count() changed to drupal_session_count().
-
-
-Admin Menu 6.x-3.x, xxxx-xx-xx
-------------------------------
-#588936 by fenstrat: Fixed Toolbar shortcuts not visible.
-#860390 by Kevin Rogers: Fixed .info file parsing error on uncertain platform.
-#551484 by sun: Fixed stale hook_admin_menu_output_alter() docs.
-
-
-Admin Menu 6.x-3.0-ALPHA4, 2010-03-11
--------------------------------------
-#730156 by sun: Fixed Administration views.
-by sun: Fixed missing .element-hidden style in D6 for permissions tweak.
-#645526 by TravisCarden: Fixed stale local tasks markup after moving them.
-#366442 by sun: Added tweak to collapse modules on permissions page.
-#655926 by donquixote, sun: Improved performance of delayed mouseout.
-#557062 by sun: Fixed admin_menu_toolbar JS/CSS loaded before admin_menu's.
-#599462 by sun, koyama: Added background-color to avoid unintentional override.
-#601918 by BWPanda: Fixed admin_menu.css overrides admin_menu_toolbar.css.
-#586228 by Island Usurper: Fixed for PHP 5.3.
-#554124 by Dave Reid: Added missing toolbar.png.
-#557062 by Dave Reid: Fixed undefined Drupal.admin error when including
- admin_menu_toolbar.js before admin_menu.js.
-#511744 by smk-ka, sun: Fixed /admin page links are broken.
-by smk-ka: Added missing variables to hook_uninstall().
-#571038 by smk-ka: Removed call to admin_menu_wipe() and cleaned install file.
-#552190 by Bartezz: Fixed missing t() for user logout link.
-
-
-Admin Menu 6.x-3.0-ALPHA3, 2009-08-16
--------------------------------------
-#502500 by sun: Added "Create content" menu.
-#538714 by sun: Fixed wrong re-parenting in Drupal's menu system.
-#550132 by sun: Fixed (temporarily) admin_views menu items.
-by sun: Added Administration views sub-module, converting all administrative
- listing pages in Drupal core into real, ajaxified, and alterable views.
-#547206 by sun: Fixed menu link descriptions lead to mouseover clashes.
-#540954 by Rob Loach: Added String Overrides to list of developer modules.
-#540762 by Deslack: Added Malay translation.
-
-
-Admin Menu 6.x-3.0-ALPHA2, 2009-08-02
--------------------------------------
-#527908 by sun: Changed theme_admin_menu_links() to use $element['#children'].
-#527908 by markus_petrux, sun: Changed admin menu into a renderable array.
-#420812 by sun, smk-ka: Added support for hook_js().
-by sun: Fixed destination query string of current page not applied to links.
-by sun: Changed Drupal.admin.attachBehaviors() to accept local JS settings.
-#276751 by sun: Revamped rendering of menu additions/widgets.
-#500866 by sun: Updated for removed t() from getInfo() in tests.
-#402058 by sun: Added Administration menu toolbar module.
-by markus_petrux, sun: Added API documentation.
-#461264 by sun: Added site/domain as CSS class.
-#451270 by smk-ka, sun: Changed visual indication for uid1.
-by sun: Minor code clean-up.
-#490670 by sun: Fixed missing menu after installation/upgrade.
-#515718 by joelstein, sun: Added rules_admin module to developer modules list.
-#352065 by sun: Added setting to select developer modules to keep enabled.
-#511854 by psynaptic: Fixed logout link.
-#424960 by markus_petrux, sun: Fixed gzip compression for cached output.
-by sun: Fixed opacity of links in sub-menus.
-#479922 by sun: Fixed fieldsets not collapsed on admin/build/modules/list*.
-#495148 by sun: Fixed MENU_NORMAL_ITEMs do not appear in administration menu.
-by sun: Fixed tests for new content-type locations.
-#345984 by markus_petrux, sun: Fixed old menu links not removed on upgrade.
-#276751 by sun: Major rewrite. Fixed menu items cannot be moved, altered, or
- added as well as various performance issues.
-by sun: Added variable to allow to disable caching (rewrite).
-
-
-Admin Menu 6.x-3.0-ALPHA1, 2009-06-10
--------------------------------------
-#236657 by sun: Updated for corrected arguments of system_clear_cache_submit().
-#483870 by sun: Fixed compatibility with new Admin module.
-#483152 by sun: Fixed admin_menu caches not flushed when clean URLs are toggled.
-#479922 by danep: Fixed fieldsets not collapsed on admin/build/modules/list.
-#469716 by sun: Fixed wrong AJAX callback URL under various conditions.
-#471504 by wulff: Updated Danish translation.
-by sun: Fixed admin_menu_suppress() does not suppress margin-top.
-#451270 by sun: Added visual indication when working as uid 1.
-by Dave Reid: Updated for getInfo() in tests.
-#420828 by sun: Added dynamic replacements for cached administration menu.
-#420840 by sun: Fixed Drupal.behaviors.adminMenu must be only executed once.
-#345984 by markus_petrux, sun: Added client-side caching of administration menu.
- Attention: A new era of Drupal user experience starts here. This is the very
- first issue of a series of improvements targeting plain awesomeness.
-#349169 by sun: Fixed Devel switch user links contain multiple path prefixes.
-#345984 by sun: Code clean-up in preparation for client-side caching.
-#415196 by psynaptic: Updated for CSS coding standards.
-#406672 by mr.j, sun: Fixed "Move local tasks" option leaves stale UL.
-by sun: Major code clean-up and sync across 3.x branches.
-#349505 by smk-ka, sun: Performance: Added caching of entire menu output.
-#315342 by wulff: Added "My account" link (by splitting the "Log out" item).
-#384100 by kepol, sun: Fixed content-type items displayed in wrong place.
-#373339 by sun: Fixed double-escaped 'Edit ' link titles.
-#373372 by sun: Turned procedural JavaScript into admin menu behaviors.
-by sun: Fixed admin menu tests (and updated to 6.x for SimpleTest 2.x).
-#359158 by nitrospectide, sun: Fixed Devel Themer breaks admin menu.
-#365335 by sun: Fixed not all variables removed after uninstall.
-
-
-Admin Menu 6.x-1.3, 2009-01-24
-------------------------------
-#362454 by sun: Fixed Drupal.settings.admin_menu is undefined JS error in some
- browsers.
-
-
-Admin Menu 6.x-1.2, 2009-01-20
-------------------------------
-#358697 by sun: Added docs about admin_menu_suppress() to README.txt.
-#342684 by darumaki, sun: Added notice about Opera configuration to README.txt.
-#350932 by sun: Fixed "Run updates" link repeated per language/site.
-#342298 by gustz: Updated Spanish translation.
-#346106 by sun: Fixed XHTML-Strict validation for admin menu icon.
-#287448 by sun: Fixed unnecessary menu rebuild for users without permission to
- use admin menu.
-#342002 by AltaVida: Fixed improper test for node/add paths.
-#272920 by keith.smith: Changed all text strings throughout the module.
-#322731 by sun: Fixed improper use of t() in module install file.
-#282030 by sun: Fixed "Run updates" item visible for unprivileged users.
-#322877 by sun: Added tweak to move page tabs into administration menu.
-#287468 by sun: Fixed module paths directly below "admin" get the wrong parent.
-#310423 by sun: Added optional position: fixed configuration setting.
-#292657 by smk-ka: Improved rendering performance.
-#234149 by yhager, sun: Fixed RTL support for IE.
-#323726 by danez1972: Added Spanish translation.
-#325057 by sun: Updated README.txt.
-#234149 by yhager, levavie, sun: Added RTL support.
-#325057 by sun: Added links to flush specific caches.
-#324334 by AltaVida: Fixed usernames with spaces not in Devel user switch links.
-#319382 by betz: Added Dutch translation.
-
-
-Admin Menu 6.x-1.1, 2008-09-12
-------------------------------
-#295476 by pwolanin, use for icon path to fix front-page path-change
- bug and pathauto conflict, add wipe button to admin form.
-#301370 by sun: Disabled module fieldset collapsing behavior by default.
-#288672 by sun: Fixed JS hover behavior not working in IE.
-#290803 by sun: Fixed missing devel_themer in devel modules; added some others.
-#286636 by sun: Fixed menus do not drop down in IE6.
-#249537 by pwolanin, sun: Added admin_menu_suppress() to allow other modules to
- disable the display of admin_menu on certain pages (f.e. popups).
-#268211 by sun: Fixed invalid issue queue links for custom modules and
- sub-modules of projects.
-#261461 by sun: Added FAQ entry for displaying other menus like admin_menu.
-#264067 by sun: Added FAQ entry for huge amount of anonymous users displayed.
-#280002 by pwolanin: Clean up .test setUp function.
-#242377 by sun: Fixed sub-level menu items exceed total document height.
-
-
-Admin Menu 6.x-1.0, 2008-06-26
-------------------------------
-#266308 by sun: Fixed jQuery 1.0.x incompatible selector for collapsing modules.
-#268373 by sun: Added hook_update to cleanup for alpha/beta testers.
-#268373 by sun: Added menu callback to disable/enable developer modules.
-#132524 by pwolanin: Fixed admin_menu links are re-inserted each time menu links
- are rebuilt.
-by smk-ka: Performance: Use 'defer' attribute for JavaScript to delay execution.
-#266099 by sun: Fixed description of "Apply margin-top" configuration setting.
-#266308 by sun: Usability: Added Utility module features to collapse module
- fieldsets on Modules page.
-#251341 by sun: Added docs about display drupal links permission.
-
-
-Admin Menu 6.x-1.0-BETA, 2008-06-08
------------------------------------
-#132524 by sun: Fixed support for sub-content-types below node/add.
-#132524 by pwolanin: Added support for localizable menu links.
-#132524 by pwolanin, sun: Fixed menu links adjustments.
-#132524 by pwolanin: Added simpletest.
-#132524 by pwolanin: Major rewrite to better use Drupal 6 menu system.
-#132524 by sun: Moved gettext translation files into translations.
-#132524 by sun: Committing pre-alpha code for D6 due to public demand.
-
-
-Admin Menu 5.x-2.x, xxxx-xx-xx
-------------------------------
-#246221 by sun: Fixed user counter displays different values than Who's online
- block.
-#239022 by mikl: Added Danish translation.
-#234444 by smk-ka: Fixed admin_menu icon does not respect theme settings.
-#198240 by sun: Fixed admin_menu displayed in print output.
-
-
-Admin Menu 5.x-2.4, 2008-02-24
-------------------------------
-#214740 by sun: Regression: Fixed directly applied marginTop not supported by IE.
-#214725 by sun: Fixed wrong CSS id in admin_menu.js (missed in 5.x-2.3).
-
-
-Admin Menu 5.x-2.3, 2008-02-24
-------------------------------
-#214725 by sun: Fixed CSS id and classes should not contain underscores.
-#209390 by sun: Added note about interaction with user role permissions.
-#214740 by jjeff, sun: Added module settings to configure margin-top CSS.
-#200737 by sun: Changed admin_menu (fav)icon to use theme setting, if defined.
-#203116 by smk-ka: Improved performance of non-cached admin_menu by storing
- already processed URLs in the cache.
-#224605 by sun: 'Add ' items do not appear without 'administer
- nodes' permission.
-#210615 by robertgarrigos: Fixed Mozilla Mac: Collapsible fieldsets display
- error.
-
-
-Admin Menu 5.x-2.2, 2007-01-08
-------------------------------
-#204884 by jjeff: Usability: Override theme font family declaration.
-#204935 by jjeff: Added mouseout delay for hovered menus (yay!).
-#193941 by downgang: Fixed margin in IE6 using Garland theme.
-#197306 by sun: Fixed 'Run updates' leads to wrong url with clean URLs disabled.
-Moved images into sub-folder.
-by smk-ka: Fixed icon title for user counter not displayed & coding style.
-Fixed user count not displayed without 'administer users' permission.
-
-
-Admin Menu 5.x-2.1, 2007-12-02
-------------------------------
-Fixed adding menu items with negative weight not always working.
-Fixed admin_menu_copy_items() is overwriting already existing items.
-Fixed display menu item ids in devel settings does not work.
-
-
-Admin Menu 5.x-2.0, 2007-12-02
-------------------------------
-Added devel_admin_menu() for fast access to clear-cache, variable editor and
- switch_user.
-Added username to logout button.
-Added hook_admin_menu() to allow other modules to alter admin_menu.
-#194189 by sun: Added counter for current anonymous/authenticated users.
-Added Drupal.org project issue queue links for all enabled contrib modules.
-#189701 by sun: Changed admin_menu icon to be a menu.
-#193925 by sun: Removed obsolete menu slicing code.
-#193669 by smk-ka: Moved admin_menu builder functions into include file.
-
-
-Admin Menu 5.x-1.2, 2007-11-18
-------------------------------
-#176969 by smk-ka: Fixed performance issues with path(auto) module by
- introducing a menu cache for admin_menu.
-#179648 by sun: Inject admin_menu into theme.
- Fixes several CSS bugs in various themes and also activation of admin_menu
- immediately after installation.
-#191213 by Standard: Fixed block info shouldn't contain the word "block".
-#187816 by sun: Fixed "Add" not translatable.
-#186218 by sun: Fixed admin menu icon too big in Safari.
-#182563 by sun: Fixed wrong datatype for array_search in _admin_menu_get_children().
-#183496 by sun: Fixed invalid argument supplied for foreach in admin_menu_copy_items().
-
-
-Admin Menu 5.x-1.1, 2007-10-10
-------------------------------
-#178876 by sun: Fixed 3rd-level submenus expand without hover over.
-#153455 by sun: Fixed add product node sub-elements are empty.
-Fixed path_to_theme() call breaking blocks page.
-#177582 by sun: Fixed bluebreeze theme compatibility.
-
-
-Admin Menu 5.x-1.0, 2007-09-06
-------------------------------
-#156952 by sun: Fixed admin menu inaccessible due to margins.
-#149229 by sun: Fixed admin menu not expanding in IE7.
-#172545 by sun: Use opacity instead of -moz-opacity.
-#132867 Fixed z-index too low.
-- Fixed admin menu block selectors to override any other theme styles.
-#155589 by sun: Added permission to access administration menu.
-- Fixed a PHP warning when there are no content types defined in the system, as
- node/add then has no child menu items.
-#155312 by sun: Fixed menu item tooltip clashes.
-Added support for custom stylesheets per theme.
-Removed 4.7.x compatibility.
-
-
-Admin Menu 4.7-1.3, 2007-03-30
-------------------------------
-#126601 Fixed Users can see inaccessible items.
-#121027 Fixed Page not found entries for menu-collapsed.png.
-
-
-Admin Menu 4.7-1.2, 2007-03-04
-------------------------------
-- Fixed menu item adjustments
-- Fixed IE / Safari support
-- Fixed base_path for IE support
-- Added create content options to content management menu
-
-
-Admin Menu 4.7-1.1, 2007-01-24
-------------------------------
-First stable release, compatible to Drupal 4.7.x and 5.x.
-
-
-Admin Menu 4.7-1.0, 2007-01-16
-------------------------------
-Initial release of admin_menu module. Already supporting Drupal 5.0.
diff --git a/sites/all/modules/contrib/admin_menu/LICENSE.txt b/sites/all/modules/contrib/admin_menu/LICENSE.txt
deleted file mode 100644
index d159169d..00000000
--- a/sites/all/modules/contrib/admin_menu/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/admin_menu/README.txt b/sites/all/modules/contrib/admin_menu/README.txt
deleted file mode 100644
index f66a61e3..00000000
--- a/sites/all/modules/contrib/admin_menu/README.txt
+++ /dev/null
@@ -1,188 +0,0 @@
-
--- SUMMARY --
-
-The Administration menu module displays the entire administrative menu tree (and
-most local tasks) in a drop-down menu, providing administrators one- or
-two-click access to most pages. Other modules may also add menu links to the
-menu using hook_admin_menu_output_alter().
-
-For a full description of the module, visit the project page:
- http://drupal.org/project/admin_menu
-
-To submit bug reports and feature suggestions, or to track changes:
- http://drupal.org/project/issues/admin_menu
-
-
--- REQUIREMENTS --
-
-None.
-
-
--- INSTALLATION --
-
-* Install as usual, see http://drupal.org/node/70151 for further information.
-
-* You likely want to disable Toolbar module, since its output clashes with
- Administration menu.
-
-
--- CONFIGURATION --
-
-* Configure user permissions in Administration » People » Permissions:
-
- - Use the administration pages and help (System module)
-
- The top-level administration categories require this permission to be
- accessible. The administration menu will be empty unless this permission is
- granted.
-
- - Access administration menu
-
- Users in roles with the "Access administration menu" permission will see
- the administration menu at the top of each page.
-
- - Display Drupal links
-
- Users in roles with the "Display drupal links" permission will receive
- links to drupal.org issue queues for all enabled contributed modules. The
- issue queue links appear under the administration menu icon.
-
- Note that the menu items displayed in the administration menu depend on the
- actual permissions of the viewing user. For example, the "People" menu item
- is not displayed to a user who is not a member of a role with the "Administer
- users" permission.
-
-* Customize the menu settings in Administration » Configuration and modules »
- Administration » Administration menu.
-
-* To prevent administrative menu items from appearing twice, you may hide the
- "Management" menu block.
-
-
--- CUSTOMIZATION --
-
-* To override the default administration menu icon, you may:
-
- 1) Disable it via CSS in your theme:
-
- body #admin-menu-icon { display: none; }
-
- 2) Alter the image by overriding the theme function:
-
- Copy the entire theme_admin_menu_icon() function into your template.php,
- rename it to phptemplate_admin_menu_icon() or THEMENAME_admin_menu_icon(),
- and customize the output according to your needs.
-
- Remember that the output of the administration menu is cached. To see changes
- from your theme override function, you must clear your site cache (via
- the "Flush all caches" link on the menu).
-
-* To override the font size, add the following line to your theme's stylesheet:
-
- body #admin-menu { font-size: 10px; }
-
-
--- TROUBLESHOOTING --
-
-* If the menu does not display, check the following:
-
- - Are the "Access administration menu" and "Use the administration pages and help"
- permissions enabled for the appropriate roles?
-
- - Does html.tpl.php of your theme output the $page_bottom variable?
-
-* If the menu is rendered behind a Flash movie object, add this property to your
- Flash object(s):
-
-
-
- See http://drupal.org/node/195386 for further information.
-
-
--- FAQ --
-
-Q: When the administration menu module is enabled, blank space is added to the
- bottom of my theme. Why?
-
-A: This is caused by a long list of links to module issue queues at Drupal.org.
- Use Administer >> User management >> Permissions to disable the "display
- drupal links" permission for all appropriate roles. Note that since UID 1
- automatically receives all permissions, the list of issue queue links cannot
- be disabled for UID 1.
-
-
-Q: After upgrading to 6.x-1.x, the menu disappeared. Why?
-
-A: You may need to regenerate your menu. Visit
- http://example.com/admin/build/modules to regenerate your menu (substitute
- your site name for example.com).
-
-
-Q: Can I configure the administration menu module to display another menu (like
- the Navigation menu, for instance)?
-
-A: No. As the name implies, administration menu module is for administrative
- menu links only. However, you can copy and paste the contents of
- admin_menu.css into your theme's stylesheet and replace #admin-menu with any
- other menu block id (#block-menu-1, for example).
-
-
-Q: Sometimes, the user counter displays a lot of anonymous users, but no spike
- of users or requests appear in Google Analytics or other tracking tools.
-
-A: If your site was concurrently spidered by search-engine robots, it may have
- a significant number of anonymous users for a short time. Most web tracking
- tools like Google Analytics automatically filter out these requests.
-
-
-Q: I enabled "Aggregate and compress CSS files", but admin_menu.css is still
- there. Is this normal?
-
-A: Yes, this is the intended behavior. the administration menu module only loads
- its stylesheet as needed (i.e., on page requests by logged-on, administrative
- users).
-
-
-Q: Why are sub-menus not visible in Opera?
-
-A: In the Opera browser preferences under "web pages" there is an option to fit
- to width. By disabling this option, sub-menus in the administration menu
- should appear.
-
-
-Q: How can the administration menu be hidden on certain pages?
-
-A: You can suppress it by simply calling the following function in PHP:
-
- module_invoke('admin_menu', 'suppress');
-
- However, this needs to happen as early as possible in the page request, so
- placing it in the theming layer (resp. a page template file) is too late.
- Ideally, the function is called in hook_init() in a custom module. If you do
- not have a custom module, placing it into some conditional code at the top of
- template.php may work out, too.
-
-
--- CONTACT --
-
-Current maintainers:
-* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
-* Peter Wolanin (pwolanin) - http://drupal.org/user/49851
-* Stefan M. Kudwien (smk-ka) - http://drupal.org/user/48898
-* Dave Reid (Dave Reid) - http://drupal.org/user/53892
-
-Major rewrite for Drupal 6 by Peter Wolanin (pwolanin).
-
-This project has been sponsored by:
-* UNLEASHED MIND
- Specialized in consulting and planning of Drupal powered sites, UNLEASHED
- MIND offers installation, development, theming, customization, and hosting
- to get you started. Visit http://www.unleashedmind.com for more information.
-
-* Lullabot
- Friendly Drupal experts providing professional consulting & education
- services. Visit http://www.lullabot.com for more information.
-
-* Acquia
- Commercially Supported Drupal. Visit http://acquia.com for more information.
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.info b/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.info
deleted file mode 100644
index 6408a1bb..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = Administration Development tools
-description = Administration and debugging functionality for developers and site builders.
-package = Administration
-core = 7.x
-scripts[] = admin_devel.js
-
-; Information added by drupal.org packaging script on 2013-01-31
-version = "7.x-3.0-rc4"
-core = "7.x"
-project = "admin_menu"
-datestamp = "1359651687"
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.js b/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.js
deleted file mode 100644
index 833197a1..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function($) {
-
-/**
- * jQuery debugging helper.
- *
- * Invented for Dreditor.
- *
- * @usage
- * $.debug(var [, name]);
- * $variable.debug( [name] );
- */
-jQuery.extend({
- debug: function () {
- // Setup debug storage in global window. We want to look into it.
- window.debug = window.debug || [];
-
- args = jQuery.makeArray(arguments);
- // Determine data source; this is an object for $variable.debug().
- // Also determine the identifier to store data with.
- if (typeof this == 'object') {
- var name = (args.length ? args[0] : window.debug.length);
- var data = this;
- }
- else {
- var name = (args.length > 1 ? args.pop() : window.debug.length);
- var data = args[0];
- }
- // Store data.
- window.debug[name] = data;
- // Dump data into Firebug console.
- if (typeof console != 'undefined') {
- console.log(name, data);
- }
- return this;
- }
-});
-// @todo Is this the right way?
-jQuery.fn.debug = jQuery.debug;
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.module b/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.module
deleted file mode 100644
index 5884f54e..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_devel/admin_devel.module
+++ /dev/null
@@ -1,33 +0,0 @@
- 'submit',
- '#value' => t('Rebuild system links'),
- '#submit' => array('admin_devel_form_admin_menu_theme_settings_alter_rebuild_submit'),
- // @todo Not necessarily ready for mass-consumption yet.
- '#access' => FALSE,
- );
-}
-
-/**
- * Form submit handler to wipe and rebuild all 'module' = 'system' menu links.
- */
-function admin_devel_form_admin_menu_theme_settings_alter_rebuild_submit($form, &$form_state) {
- // Delete all auto-generated menu links derived from menu router items.
- db_delete('menu_links')
- ->condition('module', 'system')
- ->execute();
- // Rebuild menu links from current menu router items.
- menu_rebuild();
-
- drupal_set_message(t('System links derived from menu router paths have been rebuilt.'));
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu-rtl.css b/sites/all/modules/contrib/admin_menu/admin_menu-rtl.css
deleted file mode 100644
index 9414dcf9..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu-rtl.css
+++ /dev/null
@@ -1,64 +0,0 @@
-
-#admin-menu {
- text-align: right;
-}
-#admin-menu .dropdown .admin-menu-users a {
- background-position: 10% center;
- padding-left: 22px;
- padding-right: 0;
-}
-#admin-menu .dropdown .admin-menu-action,
-#admin-menu .dropdown .admin-menu-search {
- float: left;
-}
-#admin-menu .dropdown .admin-menu-action a {
- border-left: none;
- border-right: 1px solid #323232;
-}
-
-/* All lists */
-#admin-menu a {
- text-align: right;
-}
-#admin-menu .dropdown a {
- border-left: 1px solid #323232;
- border-right: 0;
-}
-#admin-menu .dropdown .admin-menu-tab a {
- border-left: 1px solid #52565E;
- border-right: 0;
-}
-#admin-menu .dropdown li li a {
- border-left: 0;
-}
-
-/* All list items */
-#admin-menu .dropdown li {
- float: right;
-}
-#admin-menu .dropdown li li {
-}
-
-/* Second-level lists */
-#admin-menu .dropdown li ul {
- left: auto;
- right: -999em;
-}
-
-/* Third-and-above-level lists */
-#admin-menu .dropdown li li.expandable ul {
- margin-left: 0;
- margin-right: 160px;
-}
-
-/* Lists nested under hovered list items */
-#admin-menu .dropdown li.admin-menu-action:hover ul {
- left: 0 !important;
- right: auto;
-}
-
-/* Second-and-more-level hovering */
-#admin-menu .dropdown li li.expandable {
- background-image: url(images/arrow-rtl.png);
- background-position: 5px 6px;
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.admin.js b/sites/all/modules/contrib/admin_menu/admin_menu.admin.js
deleted file mode 100644
index 9ee9f36f..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.admin.js
+++ /dev/null
@@ -1,62 +0,0 @@
-(function($) {
-
-/**
- * Live preview of Administration menu components.
- */
-Drupal.behaviors.adminMenuLivePreview = {
- attach: function (context, settings) {
- $('input[name^="admin_menu_components"]', context).once('admin-menu-live-preview')
- .change(function () {
- var target = $(this).attr('rel');
- $(target).toggle(this.checked);
- })
- .trigger('change');
- }
-};
-
-/**
- * Automatically enables required permissions on demand.
- *
- * Many users do not understand that two permissions are required for the
- * administration menu to appear. Since Drupal core provides no facility for
- * this, we implement a simple manual confirmation for automatically enabling
- * the "other" permission.
- */
-Drupal.behaviors.adminMenuPermissionsSetupHelp = {
- attach: function (context, settings) {
- $('#permissions', context).once('admin-menu-permissions-setup', function () {
- // Retrieve matrix/mapping - these need to use the same indexes for the
- // same permissions and roles.
- var $roles = $(this).find('th:not(:first)');
- var $admin = $(this).find('input[name$="[access administration pages]"]');
- var $menu = $(this).find('input[name$="[access administration menu]"]');
-
- // Retrieve the permission label - without description.
- var adminPermission = $.trim($admin.eq(0).parents('td').prev().children().get(0).firstChild.textContent);
- var menuPermission = $.trim($menu.eq(0).parents('td').prev().children().get(0).firstChild.textContent);
-
- $admin.each(function (index) {
- // Only proceed if both are not enabled already.
- if (!(this.checked && $menu[index].checked)) {
- // Stack both checkboxes and attach a click event handler to both.
- $(this).add($menu[index]).click(function () {
- // Do nothing when disabling a permission.
- if (this.checked) {
- // Figure out which is the other, check whether it still disabled,
- // and if so, ask whether to auto-enable it.
- var other = (this == $admin[index] ? $menu[index] : $admin[index]);
- if (!other.checked && confirm(Drupal.t('Also allow !name role to !permission?', {
- '!name': $roles[index].textContent,
- '!permission': (this == $admin[index] ? menuPermission : adminPermission)
- }))) {
- other.checked = 'checked';
- }
- }
- });
- }
- });
- });
- }
-};
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.api.php b/sites/all/modules/contrib/admin_menu/admin_menu.api.php
deleted file mode 100644
index 2d212fbc..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.api.php
+++ /dev/null
@@ -1,164 +0,0 @@
- Content types.
- // The key denotes the dynamic path to expand to multiple menu items.
- $map['admin/structure/types/manage/%node_type'] = array(
- // Link generated items directly to the "Content types" item.
- 'parent' => 'admin/structure/types',
- // Create expansion arguments for the '%node_type' placeholder.
- 'arguments' => array(
- array(
- '%node_type' => array_keys(node_type_get_types()),
- ),
- ),
- );
- return $map;
-}
-
-/**
- * Add to the administration menu content before it is rendered.
- *
- * Only use this hook to add new data to the menu structure. Use
- * hook_admin_menu_output_alter() to *alter* existing data.
- *
- * @param array $content
- * A structured array suitable for drupal_render(), potentially containing:
- * - menu: The administrative menu of links below the path 'admin/*'.
- * - icon: The icon menu.
- * - account: The user account name and log out link.
- * - users: The user counter.
- * Additionally, these special properties:
- * - #components: The actual components contained in $content are configurable
- * and depend on the 'admin_menu_components' configuration value. #components
- * holds a copy of that for convenience.
- * - #complete: A Boolean indicating whether the complete menu should be built,
- * ignoring the current configuration in #components.
- * Passed by reference.
- *
- * @see hook_admin_menu_output_alter()
- * @see admin_menu_links_menu()
- * @see admin_menu_links_icon()
- * @see admin_menu_links_user()
- * @see theme_admin_menu_links()
- */
-function hook_admin_menu_output_build(&$content) {
- // In case your implementation provides a configurable component, check
- // whether the component should be displayed:
- if (empty($content['#components']['shortcut.links']) && !$content['#complete']) {
- return;
- }
-
- // Add new top-level item to the menu.
- if (isset($content['menu'])) {
- $content['menu']['myitem'] = array(
- '#title' => t('My item'),
- // #attributes are used for list items (LI).
- '#attributes' => array('class' => array('mymodule-myitem')),
- '#href' => 'mymodule/path',
- // #options are passed to l().
- '#options' => array(
- 'query' => drupal_get_destination(),
- // Apply a class on the link (anchor).
- 'attributes' => array('class' => array('myitem-link-anchor')),
- ),
- // #weight controls the order of links in the resulting item list.
- '#weight' => 50,
- );
- }
- // Add link to the icon menu to manually run cron.
- if (isset($content['icon'])) {
- $content['icon']['myitem']['cron'] = array(
- '#title' => t('Run cron'),
- '#access' => user_access('administer site configuration'),
- '#href' => 'admin/reports/status/run-cron',
- );
- }
-}
-
-/**
- * Change the administration menu content before it is rendered.
- *
- * Only use this hook to alter existing data in the menu structure. Use
- * hook_admin_menu_output_build() to *add* new data.
- *
- * @param array $content
- * A structured array suitable for drupal_render(). Passed by reference.
- *
- * @see hook_admin_menu_output_build()
- */
-function hook_admin_menu_output_alter(&$content) {
-}
-
-/**
- * Return content to be replace via JS in the cached menu output.
- *
- * @param bool $complete
- * A Boolean indicating whether all available components of the menu will be
- * output and the cache will be skipped.
- *
- * @return array
- * An associative array whose keys are jQuery selectors and whose values are
- * strings containing the replacement content.
- */
-function hook_admin_menu_replacements($complete) {
- $items = array();
- // If the complete menu is output, then it is uncached and will contain the
- // current counts already.
- if (!$complete) {
- // Check whether the users count component is enabled.
- $components = variable_get('admin_menu_components', array());
- if (!empty($components['admin_menu.users']) && ($user_count = admin_menu_get_user_count())) {
- // Replace the counters in the cached menu output with current counts.
- $items['.admin-menu-users a'] = $user_count;
- }
- }
- return $items;
-}
-
-/**
- * Inform about additional module-specific caches that can be cleared.
- *
- * Administration menu uses this hook to gather information about available
- * caches that can be flushed individually. Each returned item forms a separate
- * menu link below the "Flush all caches" link in the icon menu.
- *
- * @return array
- * An associative array whose keys denote internal identifiers for a
- * particular caches (which can be freely defined, but should be in a module's
- * namespace) and whose values are associative arrays containing:
- * - title: The name of the cache, without "cache" suffix. This label is
- * output as link text, but also for the "!title cache cleared."
- * confirmation message after flushing the cache; make sure it works and
- * makes sense to users in both locations.
- * - callback: The name of a function to invoke to flush the individual cache.
- */
-function hook_admin_menu_cache_info() {
- $caches['update'] = array(
- 'title' => t('Update data'),
- 'callback' => '_update_cache_clear',
- );
- return $caches;
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.color.css b/sites/all/modules/contrib/admin_menu/admin_menu.color.css
deleted file mode 100644
index f2491cd5..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.color.css
+++ /dev/null
@@ -1,46 +0,0 @@
-
-/**
- * @file
- * Administration menu color override.
- */
-
-#admin-menu {
- background-color: #911;
- background-image: url(images/bkg-red.png);
-}
-#admin-menu li.admin-menu-action a {
- border-left-color: #a91f1f;
-}
-
-/* All lists */
-#admin-menu ul a {
- border-right-color: #a91f1f;
-}
-#admin-menu ul li.admin-menu-tab a {
- border-right-color: #52565E;
-}
-#admin-menu li li a {
- border-top-color: #801f1f;
-}
-
-/* All list items */
-#admin-menu li li {
- background-color: #991f1f;
-}
-
-/* Second-and-more-level hovering */
-#admin-menu li li.expandable {
- background-color: #b93f3f;
-}
-#admin-menu li li:hover,
-#admin-menu li li.iehover {
- background-color: #690f0f;
-}
-#admin-menu li li.expandable:hover a,
-#admin-menu li li.expandable:hover li.expandable:hover a {
- border-color: #801f1f;
-}
-#admin-menu li li.expandable:hover li a,
-#admin-menu li li.expandable:hover li.expandable:hover li a {
- border-color: #801f1f;
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.css b/sites/all/modules/contrib/admin_menu/admin_menu.css
deleted file mode 100644
index fd86dd79..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.css
+++ /dev/null
@@ -1,250 +0,0 @@
-
-/**
- * @file
- * Administration menu.
- *
- * Implementation of Sons of Suckerfish Dropdowns.
- *
- * @see www.htmldog.com/articles/suckerfish
- */
-
-#admin-menu {
- background: #101010 url(images/bkg.png) bottom left repeat-x;
- font-size: 9px;
- font-family: "lucida grande", tahoma, verdana, arial, sans-serif;
- left: 0;
- position: absolute;
- text-align: left;
- top: 0;
- width: 100%;
-}
-#admin-menu-wrapper {
- overflow: hidden;
-}
-#admin-menu .dropdown .admin-menu-icon a {
- padding: 1px 8px 4px;
-}
-#admin-menu .dropdown .admin-menu-icon ul a {
- padding: 4px 8px;
-}
-#admin-menu .dropdown .admin-menu-icon img {
- vertical-align: bottom;
-}
-#admin-menu .dropdown .admin-menu-users a {
- background: transparent url(images/icon_users.png) 90% center no-repeat;
- padding-right: 22px;
-}
-#admin-menu .dropdown .admin-menu-action,
-#admin-menu .dropdown .admin-menu-search {
- float: right;
-}
-#admin-menu .dropdown .admin-menu-action a {
- border-left: 1px solid #323232;
- border-right: none;
-}
-body.admin-menu {
- margin-top: 20px !important;
-}
-
-/* All lists */
-#admin-menu,
-#admin-menu .dropdown {
- line-height: 1.4em;
- list-style: none;
- margin: 0;
- padding: 0;
- z-index: 999;
-}
-#admin-menu .dropdown {
- position: static;
-}
-#admin-menu a,
-#admin-menu li > span {
- background: transparent none;
- border: none;
- color: #EEE;
- font-weight: normal;
- text-align: left; /* LTR */
- text-decoration: none;
-}
-#admin-menu .dropdown a,
-#admin-menu .dropdown li > span {
- border-right: 1px solid #323232; /* LTR */
- display: block;
- padding: 4px 8px;
-}
-#admin-menu .dropdown .admin-menu-tab a {
- border-right: 1px solid #52565E; /* LTR */
-}
-#admin-menu .dropdown li li a {
- border-right: none; /* LTR */
- border-top: 1px solid #323232;
-}
-
-/* All list items */
-#admin-menu .dropdown li {
- background-image: none;
- float: left; /* LTR */
- height: 100%;
- list-style-image: none;
- list-style-type: none;
- margin: 0 !important;
- padding: 0;
-}
-#admin-menu .dropdown .admin-menu-tab {
- background: url(images/bkg_tab.png) repeat-x left bottom;
- padding-bottom: 1px;
-}
-#admin-menu .dropdown li li {
- background: #202020;
- filter: Alpha(opacity=88);
- opacity: 0.88;
- width: 160px; /* Required for Opera */
-}
-#admin-menu .dropdown li li li {
- filter: Alpha(opacity=100);
- opacity: 1;
-}
-
-/* Second-level lists */
-/* Note: We must hide sub-lists or scrollbars might appear (display: none is not read by screen readers). */
-#admin-menu .dropdown li ul {
- background: none;
- display: none;
- left: -999em; /* LTR */
- line-height: 1.2em;
- margin: 0;
- position: absolute;
- width: 160px;
-}
-
-/* Third-and-above-level lists */
-#admin-menu .dropdown li li.expandable ul {
- margin: -20px 0 0 160px; /* LTR */
-}
-
-#admin-menu .dropdown li:hover ul ul,
-#admin-menu .dropdown li:hover ul ul ul,
-#admin-menu .dropdown li:hover ul ul ul ul,
-#admin-menu .dropdown li:hover ul ul ul ul ul,
-#admin-menu .dropdown li.iehover ul ul,
-#admin-menu .dropdown li.iehover ul ul ul,
-#admin-menu .dropdown li.iehover ul ul ul ul,
-#admin-menu .dropdown li.iehover ul ul ul ul ul {
- display: none;
- left: -999em; /* LTR */
-}
-
-/* Lists nested under hovered list items */
-#admin-menu .dropdown li:hover ul,
-#admin-menu .dropdown li li:hover ul,
-#admin-menu .dropdown li li li:hover ul,
-#admin-menu .dropdown li li li li:hover ul,
-#admin-menu .dropdown li li li li li:hover ul,
-#admin-menu .dropdown li.iehover ul,
-#admin-menu .dropdown li li.iehover ul,
-#admin-menu .dropdown li li li.iehover ul,
-#admin-menu .dropdown li li li li.iehover ul,
-#admin-menu .dropdown li li li li li.iehover ul {
- display: block;
- left: auto; /* LTR */
-}
-#admin-menu .dropdown li.admin-menu-action:hover ul {
- right: 0; /* LTR */
-}
-
-/* Second-and-more-level hovering */
-#admin-menu .dropdown li li.expandable {
- background: #45454A url(images/arrow.png) no-repeat 145px 6px;
-}
-#admin-menu .dropdown li li:hover,
-#admin-menu .dropdown li li.iehover {
- background-color: #111;
-}
-#admin-menu .dropdown li li:hover a,
-#admin-menu .dropdown li li:hover li:hover a,
-#admin-menu .dropdown li li:hover li:hover li:hover a {
- color: #FFF;
-}
-#admin-menu .dropdown li li.expandable:hover a,
-#admin-menu .dropdown li li.expandable:hover li.expandable:hover a {
- border-color: #444;
- color: #EEE;
-}
-#admin-menu .dropdown li li.expandable:hover li a,
-#admin-menu .dropdown li li.expandable:hover li.expandable:hover li a {
- border-color: #323232;
-}
-#admin-menu .dropdown li li:hover li a,
-#admin-menu .dropdown li li.iehover li a,
-#admin-menu .dropdown li li.iehover li.iehover li a {
- color: #EEE;
-}
-#admin-menu .dropdown li li.iehover a,
-#admin-menu .dropdown li li.iehover li.iehover a,
-#admin-menu .dropdown li li.iehover li.iehover li.iehover a {
- color: #FFF;
- width: 90%; /* IE */
-}
-
-/* Search form */
-#admin-menu .admin-menu-search .form-item {
- margin: 0;
- padding: 0;
-}
-#admin-menu .admin-menu-search input {
- background: #fff none center right no-repeat;
- border: none;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
- font-size: 10px;
- margin: 1px 0;
- outline: none;
- padding: 2px 22px 2px 4px;
- width: 158px;
-}
-
-#admin-menu .dropdown .admin-menu-search-results {
- display: block !important;
- left: auto !important;
- top: 100%;
-}
-#admin-menu .admin-menu-search-results,
-#admin-menu .admin-menu-search-results li {
- width: 186px;
-}
-
-#admin-menu li.highlight {
- background-color: #eee !important;
-}
-#admin-menu li.highlight > a {
- border-color: #ccc !important;
- color: #111 !important;
-}
-
-/* #210615: Mozilla on Mac fix */
-html.js fieldset.collapsible div.fieldset-wrapper {
- overflow: visible;
-}
-
-/* Hide the menu on print output. */
-@media print {
- #admin-menu {
- display: none !important;
- }
- body.admin-menu {
- margin-top: 0 !important;
- }
-}
-
-/**
- * Tweaks permissions, if enabled.
- */
-tr.admin-menu-tweak-permissions-processed {
- cursor: pointer;
- cursor: hand;
-}
-tr.admin-menu-tweak-permissions-processed td.module {
- border-top: 0;
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.inc b/sites/all/modules/contrib/admin_menu/admin_menu.inc
deleted file mode 100644
index e212970c..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.inc
+++ /dev/null
@@ -1,1033 +0,0 @@
- $data) {
- // Convert named placeholders to anonymous placeholders, since the menu
- // system stores paths using anonymous placeholders.
- $replacements = array_fill_keys(array_keys($data['arguments'][0]), '%');
- $data['parent'] = strtr($data['parent'], $replacements);
- $new_map[strtr($path, $replacements)] = $data;
- }
- $expand_map = $new_map;
- unset($new_map);
-
- // Retrieve dynamic menu link tree for the expansion mappings.
- // @todo Skip entire processing if initial $expand_map is empty and directly
- // return $tree?
- if (!empty($expand_map)) {
- $tree_dynamic = admin_menu_tree_dynamic($expand_map);
- }
- else {
- $tree_dynamic = array();
- }
-
- // Merge local tasks with static menu tree.
- $tree = menu_tree_all_data($menu_name);
- admin_menu_merge_tree($tree, $tree_dynamic, array());
-
- return $tree;
-}
-
-/**
- * Load menu link trees for router paths containing dynamic arguments.
- *
- * @param $expand_map
- * An array containing menu router path placeholder expansion argument
- * mappings.
- *
- * @return
- * An associative array whose keys are the parent paths of the menu router
- * paths given in $expand_map as well as the parent paths of any child link
- * deeper down the tree. The parent paths are used in admin_menu_merge_tree()
- * to check whether anything needs to be merged.
- *
- * @see hook_admin_menu_map()
- */
-function admin_menu_tree_dynamic(array $expand_map) {
- $p_columns = array();
- for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
- $p_columns[] = 'p' . $i;
- }
-
- // Fetch p* columns for all router paths to expand.
- $router_paths = array_keys($expand_map);
- $plids = db_select('menu_links', 'ml')
- ->fields('ml', $p_columns)
- ->condition('router_path', $router_paths)
- ->execute()
- ->fetchAll(PDO::FETCH_ASSOC);
-
- // Unlikely, but possible.
- if (empty($plids)) {
- return array();
- }
-
- // Use queried plid columns to query sub-trees for the router paths.
- $query = db_select('menu_links', 'ml');
- $query->join('menu_router', 'm', 'ml.router_path = m.path');
- $query
- ->fields('ml')
- ->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), drupal_schema_fields_sql('menu_links')));
-
- // The retrieved menu link trees have to be ordered by depth, so parents
- // always come before their children for the storage logic below.
- foreach ($p_columns as $column) {
- $query->orderBy($column, 'ASC');
- }
-
- $db_or = db_or();
- foreach ($plids as $path_plids) {
- $db_and = db_and();
- // plids with value 0 may be ignored.
- foreach (array_filter($path_plids) as $column => $plid) {
- $db_and->condition($column, $plid);
- }
- $db_or->condition($db_and);
- }
- $query->condition($db_or);
- $result = $query
- ->execute()
- ->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
-
- // Store dynamic links grouped by parent path for later merging and assign
- // placeholder expansion arguments.
- $tree_dynamic = array();
- foreach ($result as $mlid => $link) {
- // If contained in $expand_map, then this is a (first) parent, and we need
- // to store by the defined 'parent' path for later merging, as well as
- // provide the expansion map arguments to apply to the dynamic tree.
- if (isset($expand_map[$link['path']])) {
- $parent_path = $expand_map[$link['path']]['parent'];
- $link['expand_map'] = $expand_map[$link['path']]['arguments'];
- }
- // Otherwise, just store this link keyed by its parent path; the expand_map
- // is automatically derived from parent paths.
- else {
- $parent_path = $result[$link['plid']]['path'];
- }
-
- $tree_dynamic[$parent_path][] = $link;
- }
-
- return $tree_dynamic;
-}
-
-/**
- * Walk through the entire menu tree and merge in expanded dynamic menu links.
- *
- * @param &$tree
- * A menu tree structure as returned by menu_tree_all_data().
- * @param $tree_dynamic
- * A dynamic menu tree structure as returned by admin_menu_tree_dynamic().
- * @param $expand_map
- * An array containing menu router path placeholder expansion argument
- * mappings.
- *
- * @see hook_admin_menu_map()
- * @see admin_menu_tree_dynamic()
- * @see menu_tree_all_data()
- */
-function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_map) {
- foreach ($tree as $key => $data) {
- $path = $data['link']['router_path'];
-
- // Recurse into regular menu tree.
- if ($tree[$key]['below']) {
- admin_menu_merge_tree($tree[$key]['below'], $tree_dynamic, $expand_map);
- }
- // Nothing to merge, if this parent path is not in our dynamic tree.
- if (!isset($tree_dynamic[$path])) {
- continue;
- }
-
- // Add expanded dynamic items.
- foreach ($tree_dynamic[$path] as $link) {
- // If the dynamic item has custom placeholder expansion parameters set,
- // use them, otherwise keep current.
- if (isset($link['expand_map'])) {
- // If there are currently no expansion parameters, we may use the new
- // set immediately.
- if (empty($expand_map)) {
- $current_expand_map = $link['expand_map'];
- }
- else {
- // Otherwise we need to filter out elements that differ from the
- // current set, i.e. that are not in the same path.
- $current_expand_map = array();
- foreach ($expand_map as $arguments) {
- foreach ($arguments as $placeholder => $value) {
- foreach ($link['expand_map'] as $new_arguments) {
- // Skip the new argument if it doesn't contain the current
- // replacement placeholders or if their values differ.
- if (!isset($new_arguments[$placeholder]) || $new_arguments[$placeholder] != $value) {
- continue;
- }
- $current_expand_map[] = $new_arguments;
- }
- }
- }
- }
- }
- else {
- $current_expand_map = $expand_map;
- }
-
- // Skip dynamic items without expansion parameters.
- if (empty($current_expand_map)) {
- continue;
- }
-
- // Expand anonymous to named placeholders.
- // @see _menu_load_objects()
- $path_args = explode('/', $link['path']);
- $load_functions = unserialize($link['load_functions']);
- if (is_array($load_functions)) {
- foreach ($load_functions as $index => $function) {
- if ($function) {
- if (is_array($function)) {
- list($function,) = each($function);
- }
- // Add the loader function name minus "_load".
- $placeholder = '%' . substr($function, 0, -5);
- $path_args[$index] = $placeholder;
- }
- }
- }
- $path_dynamic = implode('/', $path_args);
-
- // Create new menu items using expansion arguments.
- foreach ($current_expand_map as $arguments) {
- // Create the cartesian product for all arguments and create new
- // menu items for each generated combination thereof.
- foreach (admin_menu_expand_args($arguments) as $replacements) {
- $newpath = strtr($path_dynamic, $replacements);
- // Skip this item, if any placeholder could not be replaced.
- // Faster than trying to invoke _menu_translate().
- if (strpos($newpath, '%') !== FALSE) {
- continue;
- }
- $map = explode('/', $newpath);
- $item = admin_menu_translate($link, $map);
- // Skip this item, if the current user does not have access.
- if (empty($item)) {
- continue;
- }
- // Build subtree using current replacement arguments.
- $new_expand_map = array();
- foreach ($replacements as $placeholder => $value) {
- $new_expand_map[$placeholder] = array($value);
- }
- admin_menu_merge_tree($item, $tree_dynamic, array($new_expand_map));
- $tree[$key]['below'] += $item;
- }
- }
- }
- // Sort new subtree items.
- ksort($tree[$key]['below']);
- }
-}
-
-/**
- * Translate an expanded router item into a menu link suitable for rendering.
- *
- * @param $router_item
- * A menu router item.
- * @param $map
- * A path map with placeholders replaced.
- */
-function admin_menu_translate($router_item, $map) {
- _menu_translate($router_item, $map, TRUE);
-
- // Run through hook_translated_menu_link_alter() to add devel information,
- // if configured.
- $router_item['menu_name'] = 'management';
- // @todo Invoke as usual like _menu_link_translate().
- admin_menu_translated_menu_link_alter($router_item, NULL);
-
- if ($router_item['access']) {
- // Override mlid to make this item unique; since these items are expanded
- // from dynamic items, the mlid is always the same, so each item would
- // replace any other.
- // @todo Doing this instead leads to plenty of duplicate links below
- // admin/structure/menu; likely a hidden recursion problem.
- // $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];
- $router_item['mlid'] = $router_item['href'];
- // Turn menu callbacks into regular menu items to make them visible.
- if ($router_item['type'] == MENU_CALLBACK) {
- $router_item['type'] = MENU_NORMAL_ITEM;
- }
-
- // @see _menu_tree_check_access()
- $key = (50000 + $router_item['weight']) . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
- return array($key => array(
- 'link' => $router_item,
- 'below' => array(),
- ));
- }
-
- return array();
-}
-
-/**
- * Create the cartesian product of multiple varying sized argument arrays.
- *
- * @param $arguments
- * A two dimensional array of arguments.
- *
- * @see hook_admin_menu_map()
- */
-function admin_menu_expand_args($arguments) {
- $replacements = array();
-
- // Initialize line cursors, move out array keys (placeholders) and assign
- // numeric keys instead.
- $i = 0;
- $placeholders = array();
- $new_arguments = array();
- foreach ($arguments as $placeholder => $values) {
- // Skip empty arguments.
- if (empty($values)) {
- continue;
- }
- $cursor[$i] = 0;
- $placeholders[$i] = $placeholder;
- $new_arguments[$i] = $values;
- $i++;
- }
- $arguments = $new_arguments;
- unset($new_arguments);
-
- if ($rows = count($arguments)) {
- do {
- // Collect current argument from each row.
- $row = array();
- for ($i = 0; $i < $rows; ++$i) {
- $row[$placeholders[$i]] = $arguments[$i][$cursor[$i]];
- }
- $replacements[] = $row;
-
- // Increment cursor position.
- $j = $rows - 1;
- $cursor[$j]++;
- while (!array_key_exists($cursor[$j], $arguments[$j])) {
- // No more arguments left: reset cursor, go to next line and increment
- // that cursor instead. Repeat until argument found or out of rows.
- $cursor[$j] = 0;
- if (--$j < 0) {
- // We're done.
- break 2;
- }
- $cursor[$j]++;
- }
- } while (1);
- }
-
- return $replacements;
-}
-
-/**
- * Build the administration menu as renderable menu links.
- *
- * @param $tree
- * A data structure representing the administration menu tree as returned from
- * menu_tree_all_data().
- *
- * @return
- * The complete administration menu, suitable for theme_admin_menu_links().
- *
- * @see theme_admin_menu_links()
- * @see admin_menu_menu_alter()
- */
-function admin_menu_links_menu($tree) {
- $links = array();
- foreach ($tree as $data) {
- // Skip items that are inaccessible, invisible, or link to their parent.
- // (MENU_DEFAULT_LOCAL_TASK), and MENU_CALLBACK-alike items that should only
- // appear in the breadcrumb.
- if (!$data['link']['access'] || $data['link']['type'] & MENU_LINKS_TO_PARENT || $data['link']['type'] == MENU_VISIBLE_IN_BREADCRUMB || $data['link']['hidden'] == 1) {
- continue;
- }
- // Hide 'Administer' and make child links appear on this level.
- // @todo Make this configurable.
- if ($data['link']['router_path'] == 'admin') {
- if ($data['below']) {
- $links = array_merge($links, admin_menu_links_menu($data['below']));
- }
- continue;
- }
- // Omit alias lookups.
- $data['link']['localized_options']['alias'] = TRUE;
- // Remove description to prevent mouseover tooltip clashes.
- unset($data['link']['localized_options']['attributes']['title']);
-
- // Make action links (typically "Add ...") appear first in dropdowns.
- // They might appear first already, but only as long as there is no link
- // that comes alphabetically first (e.g., a node type with label "Ad").
- if ($data['link']['type'] & MENU_IS_LOCAL_ACTION) {
- $data['link']['weight'] -= 1000;
- }
-
- $links[$data['link']['href']] = array(
- '#title' => $data['link']['title'],
- '#href' => $data['link']['href'],
- '#options' => $data['link']['localized_options'],
- '#weight' => $data['link']['weight'],
- );
-
- // Recurse to add any child links.
- $children = array();
- if ($data['below']) {
- $children = admin_menu_links_menu($data['below']);
- $links[$data['link']['href']] += $children;
- }
-
- // Handle links pointing to category/overview pages.
- if ($data['link']['page_callback'] == 'system_admin_menu_block_page' || $data['link']['page_callback'] == 'system_admin_config_page') {
- // Apply a marker for others to consume.
- $links[$data['link']['href']]['#is_category'] = TRUE;
- // Automatically hide empty categories.
- // Check for empty children first for performance. Only when non-empty
- // (typically 'admin/config'), check whether children are accessible.
- if (empty($children) || !element_get_visible_children($children)) {
- $links[$data['link']['href']]['#access'] = FALSE;
- }
- }
- }
- return $links;
-}
-
-/**
- * Build icon menu links; mostly containing maintenance helpers.
- *
- * @see theme_admin_menu_links()
- */
-function admin_menu_links_icon() {
- $destination = drupal_get_destination();
-
- $links = array(
- '#theme' => 'admin_menu_links',
- '#wrapper_attributes' => array('id' => 'admin-menu-icon'),
- '#weight' => -100,
- );
- $links['icon'] = array(
- '#title' => theme('admin_menu_icon'),
- '#attributes' => array('class' => array('admin-menu-icon')),
- '#href' => '',
- '#options' => array(
- 'html' => TRUE,
- ),
- );
- // Add link to manually run cron.
- $links['icon']['cron'] = array(
- '#title' => t('Run cron'),
- '#weight' => 50,
- '#access' => user_access('administer site configuration'),
- '#href' => 'admin/reports/status/run-cron',
- );
- // Add link to run update.php.
- $links['icon']['update'] = array(
- '#title' => t('Run updates'),
- '#weight' => 50,
- // @see update_access_allowed()
- '#access' => $GLOBALS['user']->uid == 1 || !empty($GLOBALS['update_free_access']) || user_access('administer software updates'),
- '#href' => base_path() . 'update.php',
- '#options' => array(
- 'external' => TRUE,
- ),
- );
- // Add link to drupal.org.
- $links['icon']['drupal.org'] = array(
- '#title' => 'Drupal.org',
- '#weight' => 100,
- '#access' => user_access('display drupal links'),
- '#href' => 'http://drupal.org',
- );
- // Add links to project issue queues.
- foreach (module_list(FALSE, TRUE) as $module) {
- $info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info');
- if (!isset($info['project']) || isset($links['icon']['drupal.org'][$info['project']])) {
- continue;
- }
- $links['icon']['drupal.org'][$info['project']] = array(
- '#title' => t('@project issue queue', array('@project' => $info['name'])),
- '#weight' => ($info['project'] == 'drupal' ? -10 : 0),
- '#href' => 'http://drupal.org/project/issues/' . $info['project'],
- '#options' => array(
- 'query' => array('version' => (isset($info['core']) ? $info['core'] : 'All')),
- ),
- );
- }
- // Add items to flush caches.
- $links['icon']['flush-cache'] = array(
- '#title' => t('Flush all caches'),
- '#weight' => 20,
- '#access' => user_access('flush caches'),
- '#href' => 'admin_menu/flush-cache',
- '#options' => array(
- 'query' => $destination + array('token' => drupal_get_token('admin_menu/flush-cache')),
- ),
- );
- $caches = module_invoke_all('admin_menu_cache_info');
- foreach ($caches as $name => $cache) {
- $links['icon']['flush-cache'][$name] = array(
- '#title' => $cache['title'],
- '#href' => 'admin_menu/flush-cache/' . $name,
- '#options' => array(
- 'query' => $destination + array('token' => drupal_get_token('admin_menu/flush-cache/' . $name)),
- ),
- );
- }
-
- // Add link to toggle developer modules (performance).
- $saved_state = variable_get('admin_menu_devel_modules_enabled', NULL);
- $links['icon']['toggle-modules'] = array(
- '#title' => isset($saved_state) ? t('Enable developer modules') : t('Disable developer modules'),
- '#weight' => 88,
- '#access' => user_access('administer modules'),
- '#href' => 'admin_menu/toggle-modules',
- '#options' => array(
- 'query' => $destination + array('token' => drupal_get_token('admin_menu/toggle-modules')),
- ),
- );
-
- // Add Devel module menu links.
- if (module_exists('devel')) {
- $devel_tree = menu_build_tree('devel');
- $devel_links = admin_menu_links_menu($devel_tree);
- if (element_get_visible_children($devel_links)) {
- $links['icon']['devel'] = array(
- '#title' => t('Development'),
- '#weight' => 30,
- ) + $devel_links;
- }
- }
-
- return $links;
-}
-
-/**
- * Builds the account links.
- *
- * @see theme_admin_menu_links()
- */
-function admin_menu_links_account() {
- $links = array(
- '#theme' => 'admin_menu_links',
- '#wrapper_attributes' => array('id' => 'admin-menu-account'),
- '#weight' => 100,
- );
- $links['account'] = array(
- '#title' => format_username($GLOBALS['user']),
- '#weight' => -99,
- '#attributes' => array('class' => array('admin-menu-action', 'admin-menu-account')),
- '#href' => 'user/' . $GLOBALS['user']->uid,
- );
- $links['logout'] = array(
- '#title' => t('Log out'),
- '#weight' => -100,
- '#attributes' => array('class' => array('admin-menu-action')),
- '#href' => 'user/logout',
- );
- // Add Devel module switch user links.
- $switch_links = module_invoke('devel', 'switch_user_list');
- if (!empty($switch_links) && count($switch_links) > 1) {
- foreach ($switch_links as $uid => $link) {
- $links['account'][$link['title']] = array(
- '#title' => $link['title'],
- '#description' => $link['attributes']['title'],
- '#href' => $link['href'],
- '#options' => array(
- 'query' => $link['query'],
- 'html' => !empty($link['html']),
- ),
- );
- }
- }
- return $links;
-}
-
-/**
- * Builds user counter.
- *
- * @see theme_admin_menu_links()
- */
-function admin_menu_links_users() {
- $links = array(
- '#theme' => 'admin_menu_links',
- '#wrapper_attributes' => array('id' => 'admin-menu-users'),
- '#weight' => 150,
- );
- // Add link to show current authenticated/anonymous users.
- $links['user-counter'] = array(
- '#title' => admin_menu_get_user_count(),
- '#description' => t('Current anonymous / authenticated users'),
- '#weight' => -90,
- '#attributes' => array('class' => array('admin-menu-action', 'admin-menu-users')),
- '#href' => (user_access('administer users') ? 'admin/people/people' : 'user'),
- );
- return $links;
-}
-
-/**
- * Build search widget.
- *
- * @see theme_admin_menu_links()
- */
-function admin_menu_links_search() {
- $links = array(
- '#theme' => 'admin_menu_links',
- '#wrapper_attributes' => array('id' => 'admin-menu-search'),
- '#weight' => 180,
- );
- $links['search'] = array(
- '#type' => 'textfield',
- '#title' => t('Search'),
- '#title_display' => 'attribute',
- '#attributes' => array(
- 'placeholder' => t('Search'),
- 'class' => array('admin-menu-search'),
- ),
- );
- return $links;
-}
-
-/**
- * Form builder function for module settings.
- */
-function admin_menu_theme_settings() {
- $form['admin_menu_margin_top'] = array(
- '#type' => 'checkbox',
- '#title' => t('Adjust top margin'),
- '#default_value' => variable_get('admin_menu_margin_top', 1),
- '#description' => t('Shifts the site output down by approximately 20 pixels from the top of the viewport. If disabled, absolute- or fixed-positioned page elements may be covered by the administration menu.'),
- );
- $form['admin_menu_position_fixed'] = array(
- '#type' => 'checkbox',
- '#title' => t('Keep menu at top of page'),
- '#default_value' => variable_get('admin_menu_position_fixed', 1),
- '#description' => t('Displays the administration menu always at the top of the browser viewport (even when scrolling the page).'),
- );
- // @todo Re-confirm this with latest browser versions.
- $form['admin_menu_position_fixed']['#description'] .= '' . t('In some browsers, this setting may result in a malformed page, an invisible cursor, non-selectable elements in forms, or other issues.') . ' ';
-
- $form['advanced'] = array(
- '#type' => 'vertical_tabs',
- '#title' => t('Advanced settings'),
- );
-
- $form['plugins'] = array(
- '#type' => 'fieldset',
- '#title' => t('Plugins'),
- '#group' => 'advanced',
- );
- $form['plugins']['admin_menu_components'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Enabled components'),
- '#options' => array(
- 'admin_menu.icon' => t('Icon menu'),
- 'admin_menu.menu' => t('Administration menu'),
- 'admin_menu.search' => t('Search bar'),
- 'admin_menu.users' => t('User counts'),
- 'admin_menu.account' => t('Account links'),
- ),
- );
- $form['plugins']['admin_menu_components']['#default_value'] = array_keys(array_filter(variable_get('admin_menu_components', $form['plugins']['admin_menu_components']['#options'])));
-
- $process = element_info_property('checkboxes', '#process', array());
- $form['plugins']['admin_menu_components']['#process'] = array_merge(array('admin_menu_settings_process_components'), $process);
- $form['#attached']['js'][] = drupal_get_path('module', 'admin_menu') . '/admin_menu.admin.js';
-
- $form['tweaks'] = array(
- '#type' => 'fieldset',
- '#title' => t('System tweaks'),
- '#group' => 'advanced',
- );
- $form['tweaks']['admin_menu_tweak_modules'] = array(
- '#type' => 'checkbox',
- '#title' => t('Collapse module groups on the %modules page', array(
- '%modules' => t('Modules'),
- '!modules-url' => url('admin/modules'),
- )),
- '#default_value' => variable_get('admin_menu_tweak_modules', 0),
- );
- if (module_exists('util')) {
- $form['tweaks']['admin_menu_tweak_modules']['#description'] .= '' . t('If the Utility module was installed for this purpose, it can be safely disabled and uninstalled.') . ' ';
- }
- $form['tweaks']['admin_menu_tweak_permissions'] = array(
- '#type' => 'checkbox',
- '#title' => t('Collapse module groups on the %permissions page', array(
- '%permissions' => t('Permissions'),
- '@permissions-url' => url('admin/people/permissions'),
- )),
- '#default_value' => variable_get('admin_menu_tweak_permissions', 0),
- );
- $form['tweaks']['admin_menu_tweak_tabs'] = array(
- '#type' => 'checkbox',
- '#title' => t('Move local tasks into menu'),
- '#default_value' => variable_get('admin_menu_tweak_tabs', 0),
- '#description' => t('Moves the tabs on all pages into the administration menu. Only possible for themes using the CSS classes tabs primary and tabs secondary.'),
- );
-
- $form['performance'] = array(
- '#type' => 'fieldset',
- '#title' => t('Performance'),
- '#group' => 'advanced',
- );
- $form['performance']['admin_menu_cache_client'] = array(
- '#type' => 'checkbox',
- '#title' => t('Cache menu in client-side browser'),
- '#default_value' => variable_get('admin_menu_cache_client', 1),
- );
- // Fetch all available modules manually, since module_list() only returns
- // currently enabled modules, which makes this setting pointless if developer
- // modules are currently disabled.
- $all_modules = array();
- $result = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' ORDER BY name ASC");
- foreach ($result as $module) {
- if (file_exists($module->filename)) {
- $info = unserialize($module->info);
- $all_modules[$module->name] = $info['name'];
- }
- }
- $devel_modules = variable_get('admin_menu_devel_modules', _admin_menu_developer_modules());
- $devel_modules = array_intersect_key($all_modules, array_flip($devel_modules));
- $form['performance']['admin_menu_devel_modules_skip'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Developer modules to keep enabled'),
- '#default_value' => variable_get('admin_menu_devel_modules_skip', array()),
- '#options' => $devel_modules,
- '#access' => !empty($devel_modules),
- '#description' => t('The selected modules will not be disabled when the link %disable-developer-modules below the icon in the menu is invoked.', array(
- '%disable-developer-modules' => t('Disable developer modules'),
- )),
- );
-
- return system_settings_form($form);
-}
-
-/**
- * #process callback for component plugin form element in admin_menu_theme_settings().
- */
-function admin_menu_settings_process_components($element) {
- // Assign 'rel' attributes to all options to achieve a live preview.
- // Unfortunately, #states relies on wrapping .form-wrapper classes, so it
- // cannot be used here.
- foreach ($element['#options'] as $key => $label) {
- if (!isset($element[$key]['#attributes']['rel'])) {
- $id = preg_replace('/[^a-z]/', '-', $key);
- $element[$key]['#attributes']['rel'] = '#' . $id;
- }
- }
- return $element;
-}
-
-/**
- * Form validation handler for admin_menu_theme_settings().
- */
-function admin_menu_theme_settings_validate(&$form, &$form_state) {
- // Change the configured components to Boolean values.
- foreach ($form_state['values']['admin_menu_components'] as $component => &$enabled) {
- $enabled = (bool) $enabled;
- }
-}
-
-/**
- * Implementation of hook_form_FORM_ID_alter().
- *
- * Extends Devel module with Administration menu developer settings.
- */
-function _admin_menu_form_devel_admin_settings_alter(&$form, $form_state) {
- // Shift system_settings_form buttons.
- $weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0;
- $form['buttons']['#weight'] = $weight + 1;
-
- $form['admin_menu'] = array(
- '#type' => 'fieldset',
- '#title' => t('Administration menu settings'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $display_options = array('mid', 'weight', 'pid');
- $display_options = array(0 => t('None'), 'mlid' => t('Menu link ID'), 'weight' => t('Weight'), 'plid' => t('Parent link ID'));
- $form['admin_menu']['admin_menu_display'] = array(
- '#type' => 'radios',
- '#title' => t('Display additional data for each menu item'),
- '#default_value' => variable_get('admin_menu_display', 0),
- '#options' => $display_options,
- '#description' => t('Display the selected items next to each menu item link.'),
- );
- $form['admin_menu']['admin_menu_show_all'] = array(
- '#type' => 'checkbox',
- '#title' => t('Display all menu items'),
- '#default_value' => variable_get('admin_menu_show_all', 0),
- '#description' => t('If enabled, all menu items are displayed regardless of your site permissions. Note: Do not enable on a production site. '),
- );
-}
-
-/**
- * Menu callback; Enable/disable developer modules.
- *
- * This can save up to 150ms on each uncached page request.
- */
-function admin_menu_toggle_modules() {
- if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], current_path())) {
- return MENU_ACCESS_DENIED;
- }
-
- $rebuild = FALSE;
- $saved_state = variable_get('admin_menu_devel_modules_enabled', NULL);
- if (isset($saved_state)) {
- // Re-enable modules that were enabled before.
- module_enable($saved_state);
- variable_del('admin_menu_devel_modules_enabled');
- drupal_set_message(t('Enabled these modules: !module-list.', array('!module-list' => implode(', ', $saved_state))));
- $rebuild = TRUE;
- }
- else {
- // Allow site admins to override this variable via settings.php.
- $devel_modules = variable_get('admin_menu_devel_modules', _admin_menu_developer_modules());
- // Store currently enabled modules in a variable.
- $devel_modules = array_intersect(module_list(FALSE, FALSE), $devel_modules);
- $devel_modules = array_diff($devel_modules, variable_get('admin_menu_devel_modules_skip', array()));
- if (!empty($devel_modules)) {
- variable_set('admin_menu_devel_modules_enabled', $devel_modules);
- // Disable developer modules.
- module_disable($devel_modules);
- drupal_set_message(t('Disabled these modules: !module-list.', array('!module-list' => implode(', ', $devel_modules))));
- $rebuild = TRUE;
- }
- else {
- drupal_set_message(t('No developer modules are enabled.'));
- }
- }
- if ($rebuild) {
- // Make sure everything is rebuilt, basically a combination of the calls
- // from system_modules() and system_modules_submit().
- drupal_theme_rebuild();
- menu_rebuild();
- cache_clear_all('schema', 'cache');
- cache_clear_all();
- drupal_clear_css_cache();
- drupal_clear_js_cache();
- // Synchronize to catch any actions that were added or removed.
- actions_synchronize();
- // Finally, flush admin_menu's cache.
- admin_menu_flush_caches();
- }
- drupal_goto();
-}
-
-/**
- * Helper function to return a default list of developer modules.
- */
-function _admin_menu_developer_modules() {
- return array(
- 'admin_devel',
- 'cache_disable',
- 'coder',
- 'content_copy',
- 'context_ui',
- 'debug',
- 'delete_all',
- 'demo',
- 'devel',
- 'devel_node_access',
- 'devel_themer',
- 'field_ui',
- 'fontyourface_ui',
- 'form_controller',
- 'imagecache_ui',
- 'journal',
- 'l10n_client',
- 'l10n_update',
- 'macro',
- 'rules_admin',
- 'stringoverrides',
- 'trace',
- 'upgrade_status',
- 'user_display_ui',
- 'util',
- 'views_ui',
- 'views_theme_wizard',
- );
-}
-
-/**
- * Flush all caches or a specific one.
- *
- * @param $name
- * (optional) Name of cache to flush.
- */
-function admin_menu_flush_cache($name = NULL) {
- if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], current_path())) {
- return MENU_ACCESS_DENIED;
- }
- if (isset($name)) {
- $caches = module_invoke_all('admin_menu_cache_info');
- if (!isset($caches[$name])) {
- return MENU_NOT_FOUND;
- }
- }
- else {
- $caches[$name] = array(
- 'title' => t('Every'),
- 'callback' => 'drupal_flush_all_caches',
- );
- }
- // Pass the cache to flush forward to the callback.
- $function = $caches[$name]['callback'];
- $function($name);
-
- drupal_set_message(t('!title cache cleared.', array('!title' => $caches[$name]['title'])));
-
- // The JavaScript injects a destination request parameter pointing to the
- // originating page, so the user is redirected back to that page. Without
- // destination parameter, the redirect ends on the front page.
- drupal_goto();
-}
-
-/**
- * Implements hook_admin_menu_cache_info().
- */
-function admin_menu_admin_menu_cache_info() {
- $caches['admin_menu'] = array(
- 'title' => t('Administration menu'),
- 'callback' => '_admin_menu_flush_cache',
- );
- return $caches;
-}
-
-/**
- * Implements hook_admin_menu_cache_info() on behalf of System module.
- */
-function system_admin_menu_cache_info() {
- $caches = array(
- 'assets' => t('CSS and JavaScript'),
- 'cache' => t('Page and else'),
- 'menu' => t('Menu'),
- 'registry' => t('Class registry'),
- 'theme' => t('Theme registry'),
- );
- foreach ($caches as $name => $cache) {
- $caches[$name] = array(
- 'title' => $cache,
- 'callback' => '_admin_menu_flush_cache',
- );
- }
- return $caches;
-}
-
-/**
- * Implements hook_admin_menu_cache_info() on behalf of Update module.
- */
-function update_admin_menu_cache_info() {
- $caches['update'] = array(
- 'title' => t('Update data'),
- 'callback' => '_update_cache_clear',
- );
- return $caches;
-}
-
-/**
- * Flush all caches or a specific one.
- *
- * @param $name
- * (optional) Name of cache to flush.
- *
- * @see system_admin_menu_cache_info()
- */
-function _admin_menu_flush_cache($name = NULL) {
- switch ($name) {
- case 'admin_menu':
- admin_menu_flush_caches();
- break;
-
- case 'menu':
- menu_rebuild();
- break;
-
- case 'registry':
- registry_rebuild();
- // Fall-through to clear cache tables, since registry information is
- // usually the base for other data that is cached (e.g. SimpleTests).
- case 'cache':
- // Don't clear cache_form - in-progress form submissions may break.
- // Ordered so clearing the page cache will always be the last action.
- // @see drupal_flush_all_caches()
- $core = array('cache', 'cache_bootstrap', 'cache_filter', 'cache_page');
- $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
- foreach ($cache_tables as $table) {
- cache_clear_all('*', $table, TRUE);
- }
- break;
-
- case 'assets':
- // Change query-strings on css/js files to enforce reload for all users.
- _drupal_flush_css_js();
-
- drupal_clear_css_cache();
- drupal_clear_js_cache();
-
- // Clear the page cache, since cached HTML pages might link to old CSS and
- // JS aggregates.
- cache_clear_all('*', 'cache_page', TRUE);
- break;
-
- case 'theme':
- system_rebuild_theme_data();
- drupal_theme_rebuild();
- break;
- }
-}
-
-/**
- * Preprocesses variables for theme_admin_menu_icon().
- */
-function template_preprocess_admin_menu_icon(&$variables) {
- // Image source might have been passed in as theme variable.
- if (!isset($variables['src'])) {
- if (theme_get_setting('toggle_favicon')) {
- $variables['src'] = theme_get_setting('favicon');
- }
- else {
- $variables['src'] = base_path() . 'misc/favicon.ico';
- }
- }
- // Strip the protocol without delimiters for transient HTTP/HTTPS support.
- // Since the menu is cached on the server-side and client-side, the cached
- // version might contain a HTTP link, whereas the actual page is on HTTPS.
- // Relative paths will work fine, but theme_get_setting() returns an
- // absolute URI.
- $variables['src'] = preg_replace('@^https?:@', '', $variables['src']);
- $variables['src'] = check_plain($variables['src']);
- $variables['alt'] = t('Home');
-}
-
-/**
- * Renders an icon to display in the administration menu.
- *
- * @ingroup themeable
- */
-function theme_admin_menu_icon($variables) {
- return '';
-}
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.info b/sites/all/modules/contrib/admin_menu/admin_menu.info
deleted file mode 100644
index ee58c66c..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.info
+++ /dev/null
@@ -1,16 +0,0 @@
-name = Administration menu
-description = "Provides a dropdown menu to most administrative tasks and other common destinations (to users with the proper permissions)."
-package = Administration
-core = 7.x
-configure = admin/config/administration/admin_menu
-; Requires menu_build_tree() conditions; available after 7.10.
-; @see http://drupal.org/node/1025582
-dependencies[] = system (>7.10)
-files[] = tests/admin_menu.test
-
-; Information added by drupal.org packaging script on 2013-01-31
-version = "7.x-3.0-rc4"
-core = "7.x"
-project = "admin_menu"
-datestamp = "1359651687"
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.install b/sites/all/modules/contrib/admin_menu/admin_menu.install
deleted file mode 100644
index 70e31c6c..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.install
+++ /dev/null
@@ -1,122 +0,0 @@
-fields(array('weight' => 100))
- ->condition('type', 'module')
- ->condition('name', 'admin_menu')
- ->execute();
-}
-
-/**
- * Implements hook_uninstall().
- */
-function admin_menu_uninstall() {
- // Delete variables.
- variable_del('admin_menu_components');
- variable_del('admin_menu_devel_modules');
- variable_del('admin_menu_devel_modules_enabled');
- variable_del('admin_menu_devel_modules_skip');
- variable_del('admin_menu_margin_top');
- variable_del('admin_menu_position_fixed');
- variable_del('admin_menu_tweak_modules');
- variable_del('admin_menu_tweak_tabs');
- variable_del('admin_menu_show_all');
- variable_del('admin_menu_display');
- variable_del('admin_menu_cache_server');
- variable_del('admin_menu_cache_client');
-}
-
-/**
- * Ensure that admin_menu is rebuilt after upgrading to D6.
- */
-function admin_menu_update_6000() {
- // Drop the {admin_menu} table in admin_menu_update_6000() on sites that used
- // one of the later patches in #132524.
- if (db_table_exists('admin_menu')) {
- db_drop_table('admin_menu');
- }
-}
-
-/**
- * Wipe and rebuild so we can switch the icon path to .
- */
-function admin_menu_update_6001() {
- db_delete('menu_links')->condition('module', 'admin_menu')->execute();
- menu_cache_clear('admin_menu');
-}
-
-/**
- * Add {cache_admin_menu} table.
- */
-function admin_menu_update_7300() {
- if (!db_table_exists('cache_admin_menu')) {
- $schema = drupal_get_schema_unprocessed('system', 'cache');
- db_create_table('cache_admin_menu', $schema);
- }
-}
-
-/**
- * Increase the module weight.
- *
- * @see admin_menu_install()
- */
-function admin_menu_update_7302() {
- db_update('system')
- ->fields(array('weight' => 100))
- ->condition('type', 'module')
- ->condition('name', 'admin_menu')
- ->execute();
-}
-
-/**
- * Remove local tasks from {menu_links} table.
- */
-function admin_menu_update_7303() {
- db_delete('menu_router')
- ->condition('path', 'admin/%', 'LIKE')
- ->condition('type', MENU_IS_LOCAL_TASK, '&')
- ->execute();
-}
-
-/**
- * Remove obsolete 'admin_menu' menu and all orphan links in it.
- */
-function admin_menu_update_7304() {
- // Remove the custom menu used by 6.x-1.x.
- if (db_table_exists('menu_custom')) {
- db_delete('menu_custom')->condition('menu_name', 'admin_menu')->execute();
- }
-
- // 6.x-1.x cloned the entire link structure below the path 'admin' into a
- // separate 'menu_name' "admin_menu" with 'module' "admin_menu". 6.x-3.x and
- // early alpha versions of 7.x-3.x still did something similar. All of these
- // records are obsolete. Removal of the 'module' records (without different
- // menu_name) is particularly important, since they would otherwise appear
- // as duplicate links.
- db_delete('menu_links')
- ->condition(db_or()
- ->condition('module', 'admin_menu')
- ->condition('menu_name', 'admin_menu')
- )
- ->execute();
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.js b/sites/all/modules/contrib/admin_menu/admin_menu.js
deleted file mode 100644
index de0bb906..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.js
+++ /dev/null
@@ -1,397 +0,0 @@
-(function($) {
-
-Drupal.admin = Drupal.admin || {};
-Drupal.admin.behaviors = Drupal.admin.behaviors || {};
-Drupal.admin.hashes = Drupal.admin.hashes || {};
-
-/**
- * Core behavior for Administration menu.
- *
- * Test whether there is an administration menu is in the output and execute all
- * registered behaviors.
- */
-Drupal.behaviors.adminMenu = {
- attach: function (context, settings) {
- // Initialize settings.
- settings.admin_menu = $.extend({
- suppress: false,
- margin_top: false,
- position_fixed: false,
- tweak_modules: false,
- tweak_permissions: false,
- tweak_tabs: false,
- destination: '',
- basePath: settings.basePath,
- hash: 0,
- replacements: {}
- }, settings.admin_menu || {});
- // Check whether administration menu should be suppressed.
- if (settings.admin_menu.suppress) {
- return;
- }
- var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
- // Client-side caching; if administration menu is not in the output, it is
- // fetched from the server and cached in the browser.
- if (!$adminMenu.length && settings.admin_menu.hash) {
- Drupal.admin.getCache(settings.admin_menu.hash, function (response) {
- if (typeof response == 'string' && response.length > 0) {
- $('body', context).append(response);
- }
- var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
- // Apply our behaviors.
- Drupal.admin.attachBehaviors(context, settings, $adminMenu);
- // Allow resize event handlers to recalculate sizes/positions.
- $(window).triggerHandler('resize');
- });
- }
- // If the menu is in the output already, this means there is a new version.
- else {
- // Apply our behaviors.
- Drupal.admin.attachBehaviors(context, settings, $adminMenu);
- }
- }
-};
-
-/**
- * Collapse fieldsets on Modules page.
- */
-Drupal.behaviors.adminMenuCollapseModules = {
- attach: function (context, settings) {
- if (settings.admin_menu.tweak_modules) {
- $('#system-modules fieldset:not(.collapsed)', context).addClass('collapsed');
- }
- }
-};
-
-/**
- * Collapse modules on Permissions page.
- */
-Drupal.behaviors.adminMenuCollapsePermissions = {
- attach: function (context, settings) {
- if (settings.admin_menu.tweak_permissions) {
- // Freeze width of first column to prevent jumping.
- $('#permissions th:first', context).css({ width: $('#permissions th:first', context).width() });
- // Attach click handler.
- $modules = $('#permissions tr:has(td.module)', context).once('admin-menu-tweak-permissions', function () {
- var $module = $(this);
- $module.bind('click.admin-menu', function () {
- // @todo Replace with .nextUntil() in jQuery 1.4.
- $module.nextAll().each(function () {
- var $row = $(this);
- if ($row.is(':has(td.module)')) {
- return false;
- }
- $row.toggleClass('element-hidden');
- });
- });
- });
- // Collapse all but the targeted permission rows set.
- if (window.location.hash.length) {
- $modules = $modules.not(':has(' + window.location.hash + ')');
- }
- $modules.trigger('click.admin-menu');
- }
- }
-};
-
-/**
- * Apply margin to page.
- *
- * Note that directly applying marginTop does not work in IE. To prevent
- * flickering/jumping page content with client-side caching, this is a regular
- * Drupal behavior.
- */
-Drupal.behaviors.adminMenuMarginTop = {
- attach: function (context, settings) {
- if (!settings.admin_menu.suppress && settings.admin_menu.margin_top) {
- $('body:not(.admin-menu)', context).addClass('admin-menu');
- }
- }
-};
-
-/**
- * Retrieve content from client-side cache.
- *
- * @param hash
- * The md5 hash of the content to retrieve.
- * @param onSuccess
- * A callback function invoked when the cache request was successful.
- */
-Drupal.admin.getCache = function (hash, onSuccess) {
- if (Drupal.admin.hashes.hash !== undefined) {
- return Drupal.admin.hashes.hash;
- }
- $.ajax({
- cache: true,
- type: 'GET',
- dataType: 'text', // Prevent auto-evaluation of response.
- global: false, // Do not trigger global AJAX events.
- url: Drupal.settings.admin_menu.basePath.replace(/admin_menu/, 'js/admin_menu/cache/' + hash),
- success: onSuccess,
- complete: function (XMLHttpRequest, status) {
- Drupal.admin.hashes.hash = status;
- }
- });
-};
-
-/**
- * TableHeader callback to determine top viewport offset.
- *
- * @see toolbar.js
- */
-Drupal.admin.height = function() {
- var $adminMenu = $('#admin-menu');
- var height = $adminMenu.outerHeight();
- // In IE, Shadow filter adds some extra height, so we need to remove it from
- // the returned height.
- if ($adminMenu.css('filter') && $adminMenu.css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) {
- height -= $adminMenu.get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength;
- }
- return height;
-};
-
-/**
- * @defgroup admin_behaviors Administration behaviors.
- * @{
- */
-
-/**
- * Attach administrative behaviors.
- */
-Drupal.admin.attachBehaviors = function (context, settings, $adminMenu) {
- if ($adminMenu.length) {
- $adminMenu.addClass('admin-menu-processed');
- $.each(Drupal.admin.behaviors, function() {
- this(context, settings, $adminMenu);
- });
- }
-};
-
-/**
- * Apply 'position: fixed'.
- */
-Drupal.admin.behaviors.positionFixed = function (context, settings, $adminMenu) {
- if (settings.admin_menu.position_fixed) {
- $adminMenu.addClass('admin-menu-position-fixed');
- $adminMenu.css('position', 'fixed');
- }
-};
-
-/**
- * Move page tabs into administration menu.
- */
-Drupal.admin.behaviors.pageTabs = function (context, settings, $adminMenu) {
- if (settings.admin_menu.tweak_tabs) {
- var $tabs = $(context).find('ul.tabs.primary');
- $adminMenu.find('#admin-menu-wrapper > ul').eq(1)
- .append($tabs.find('li').addClass('admin-menu-tab'));
- $(context).find('ul.tabs.secondary')
- .appendTo('#admin-menu-wrapper > ul > li.admin-menu-tab.active')
- .removeClass('secondary');
- $tabs.remove();
- }
-};
-
-/**
- * Perform dynamic replacements in cached menu.
- */
-Drupal.admin.behaviors.replacements = function (context, settings, $adminMenu) {
- for (var item in settings.admin_menu.replacements) {
- $(item, $adminMenu).html(settings.admin_menu.replacements[item]);
- }
-};
-
-/**
- * Inject destination query strings for current page.
- */
-Drupal.admin.behaviors.destination = function (context, settings, $adminMenu) {
- if (settings.admin_menu.destination) {
- $('a.admin-menu-destination', $adminMenu).each(function() {
- this.search += (!this.search.length ? '?' : '&') + Drupal.settings.admin_menu.destination;
- });
- }
-};
-
-/**
- * Apply JavaScript-based hovering behaviors.
- *
- * @todo This has to run last. If another script registers additional behaviors
- * it will not run last.
- */
-Drupal.admin.behaviors.hover = function (context, settings, $adminMenu) {
- // Hover emulation for IE 6.
- if ($.browser.msie && parseInt(jQuery.browser.version) == 6) {
- $('li', $adminMenu).hover(
- function () {
- $(this).addClass('iehover');
- },
- function () {
- $(this).removeClass('iehover');
- }
- );
- }
-
- // Delayed mouseout.
- $('li.expandable', $adminMenu).hover(
- function () {
- // Stop the timer.
- clearTimeout(this.sfTimer);
- // Display child lists.
- $('> ul', this)
- .css({left: 'auto', display: 'block'})
- // Immediately hide nephew lists.
- .parent().siblings('li').children('ul').css({left: '-999em', display: 'none'});
- },
- function () {
- // Start the timer.
- var uls = $('> ul', this);
- this.sfTimer = setTimeout(function () {
- uls.css({left: '-999em', display: 'none'});
- }, 400);
- }
- );
-};
-
-/**
- * Apply the search bar functionality.
- */
-Drupal.admin.behaviors.search = function (context, settings, $adminMenu) {
- // @todo Add a HTML ID.
- var $input = $('input.admin-menu-search', $adminMenu);
- // Initialize the current search needle.
- var needle = $input.val();
- // Cache of all links that can be matched in the menu.
- var links;
- // Minimum search needle length.
- var needleMinLength = 2;
- // Append the results container.
- var $results = $('
').insertAfter($input);
-
- /**
- * Executes the search upon user input.
- */
- function keyupHandler() {
- var matches, $html, value = $(this).val();
- // Only proceed if the search needle has changed.
- if (value !== needle) {
- needle = value;
- // Initialize the cache of menu links upon first search.
- if (!links && needle.length >= needleMinLength) {
- // @todo Limit to links in dropdown menus; i.e., skip menu additions.
- links = buildSearchIndex($adminMenu.find('li:not(.admin-menu-action, .admin-menu-action li) > a'));
- }
- // Empty results container when deleting search text.
- if (needle.length < needleMinLength) {
- $results.empty();
- }
- // Only search if the needle is long enough.
- if (needle.length >= needleMinLength && links) {
- matches = findMatches(needle, links);
- // Build the list in a detached DOM node.
- $html = buildResultsList(matches);
- // Display results.
- $results.empty().append($html);
- }
- }
- }
-
- /**
- * Builds the search index.
- */
- function buildSearchIndex($links) {
- return $links
- .map(function () {
- var text = (this.textContent || this.innerText);
- // Skip menu entries that do not contain any text (e.g., the icon).
- if (typeof text === 'undefined') {
- return;
- }
- return {
- text: text,
- textMatch: text.toLowerCase(),
- element: this
- };
- });
- }
-
- /**
- * Searches the index for a given needle and returns matching entries.
- */
- function findMatches(needle, links) {
- var needleMatch = needle.toLowerCase();
- // Select matching links from the cache.
- return $.grep(links, function (link) {
- return link.textMatch.indexOf(needleMatch) !== -1;
- });
- }
-
- /**
- * Builds the search result list in a detached DOM node.
- */
- function buildResultsList(matches) {
- var $html = $('');
- $.each(matches, function () {
- var result = this.text;
- var $element = $(this.element);
-
- // Check whether there is a top-level category that can be prepended.
- var $category = $element.closest('#admin-menu-wrapper > ul > li');
- var categoryText = $category.find('> a').text()
- if ($category.length && categoryText) {
- result = categoryText + ': ' + result;
- }
-
- var $result = $('' + result + ' ');
- $result.data('original-link', $(this.element).parent());
- $html.append($result);
- });
- return $html;
- }
-
- /**
- * Highlights selected result.
- */
- function resultsHandler(e) {
- var $this = $(this);
- var show = e.type === 'mouseenter' || e.type === 'focusin';
- $this.trigger(show ? 'showPath' : 'hidePath', [this]);
- }
-
- /**
- * Closes the search results and clears the search input.
- */
- function resultsClickHandler(e, link) {
- var $original = $(this).data('original-link');
- $original.trigger('mouseleave');
- $input.val('').trigger('keyup');
- }
-
- /**
- * Shows the link in the menu that corresponds to a search result.
- */
- function highlightPathHandler(e, link) {
- if (link) {
- var $original = $(link).data('original-link');
- var show = e.type === 'showPath';
- // Toggle an additional CSS class to visually highlight the matching link.
- // @todo Consider using same visual appearance as regular hover.
- $original.toggleClass('highlight', show);
- $original.trigger(show ? 'mouseenter' : 'mouseleave');
- }
- }
-
- // Attach showPath/hidePath handler to search result entries.
- $results.delegate('li', 'mouseenter mouseleave focus blur', resultsHandler);
- // Hide the result list after a link has been clicked, useful for overlay.
- $results.delegate('li', 'click', resultsClickHandler);
- // Attach hover/active highlight behavior to search result entries.
- $adminMenu.delegate('.admin-menu-search-results li', 'showPath hidePath', highlightPathHandler);
- // Attach the search input event handler.
- $input.bind('keyup search', keyupHandler);
-};
-
-/**
- * @} End of "defgroup admin_behaviors".
- */
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.map.inc b/sites/all/modules/contrib/admin_menu/admin_menu.map.inc
deleted file mode 100644
index 72a89602..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.map.inc
+++ /dev/null
@@ -1,164 +0,0 @@
- 'admin/config/content/formats',
- 'arguments' => array(
- array('%filter_format' => array_keys(filter_formats())),
- ),
- );
- return $map;
-}
-
-/**
- * Implements hook_admin_menu_map() on behalf of Menu module.
- */
-function menu_admin_menu_map() {
- if (!user_access('administer menu')) {
- return;
- }
- $map['admin/structure/menu/manage/%menu'] = array(
- 'parent' => 'admin/structure/menu',
- 'arguments' => array(
- array('%menu' => array_keys(menu_get_menus())),
- ),
- );
- return $map;
-}
-
-/**
- * Implements hook_admin_menu_map() on behalf of Node module.
- */
-function node_admin_menu_map() {
- if (!user_access('administer content types')) {
- return;
- }
- $map['admin/structure/types/manage/%node_type'] = array(
- 'parent' => 'admin/structure/types',
- 'arguments' => array(
- array('%node_type' => array_keys(node_type_get_types())),
- ),
- );
- return $map;
-}
-
-/**
- * Implements hook_admin_menu_map() on behalf of Field UI module.
- */
-function field_ui_admin_menu_map() {
- $map = array();
- foreach (entity_get_info() as $obj_type => $info) {
- foreach ($info['bundles'] as $bundle_name => $bundle_info) {
- if (isset($bundle_info['admin'])) {
- $arguments = array();
- switch ($obj_type) {
- case 'comment':
- $fields = array();
- foreach (field_info_instances($obj_type, $bundle_name) as $field) {
- $fields[] = $field['field_name'];
- }
- // @todo Make Comment module expose the original node type bundle,
- // pretty please.
- if (drupal_substr($bundle_name, 0, 13) == 'comment_node_') {
- $bundle_name = drupal_substr($bundle_name, 13);
- }
- // @todo Doesn't work yet. Why?
- $arguments = array(
- '%comment_node_type' => array($bundle_name),
- '%field_ui_menu' => $fields,
- );
- break;
-
- case 'node':
- $fields = array();
- foreach (field_info_instances($obj_type, $bundle_name) as $field) {
- $fields[] = $field['field_name'];
- }
- $arguments = array(
- '%node_type' => array($bundle_name),
- '%field_ui_menu' => $fields,
- );
- break;
-
- case 'taxonomy_term':
- $fields = array();
- foreach (field_info_instances($obj_type, $bundle_name) as $field) {
- $fields[] = $field['field_name'];
- }
- // Map machine_name to vid.
- $arguments = array(
- '%taxonomy_vocabulary_machine_name' => array($bundle_name),
- '%field_ui_menu' => $fields,
- );
- break;
-
- case 'user':
- $arguments = array(
- '%field_ui_menu' => array_keys(field_info_fields('user')),
- );
- break;
- }
- if (!empty($arguments)) {
- $path = $bundle_info['admin']['path'];
- $map["$path/fields/%field_ui_menu"]['parent'] = "$path/fields";
- $map["$path/fields/%field_ui_menu"]['arguments'][] = $arguments;
- }
- }
- }
- }
- return $map;
-}
-
-/**
- * Implements hook_admin_menu_map() on behalf of Taxonomy module.
- */
-function taxonomy_admin_menu_map() {
- if (!user_access('administer taxonomy')) {
- return;
- }
- $map['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array(
- 'parent' => 'admin/structure/taxonomy',
- 'arguments' => array(
- array('%taxonomy_vocabulary_machine_name' => array_keys(taxonomy_vocabulary_get_names())),
- ),
- );
- return $map;
-}
-
-/**
- * Implements hook_admin_menu_map() on behalf of Views UI module.
- */
-function views_ui_admin_menu_map() {
- if (!user_access('administer views')) {
- return;
- }
- $views = array();
- foreach (views_get_enabled_views() as $name => $view) {
- $views[] = $name;
- }
- if (empty($views)) {
- return;
- }
- $map['admin/structure/views/view/%views_ui_cache'] = array(
- 'parent' => 'admin/structure/views',
- 'arguments' => array(
- array('%views_ui_cache' => $views),
- ),
- );
- return $map;
-}
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.module b/sites/all/modules/contrib/admin_menu/admin_menu.module
deleted file mode 100644
index 8a8dee14..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.module
+++ /dev/null
@@ -1,858 +0,0 @@
-' . t('The administration menu module provides a dropdown menu arranged for one- or two-click access to most administrative tasks and other common destinations (to users with the proper permissions). Use the settings below to customize the appearance of the menu.') . '';
-
- case 'admin/help#admin_menu':
- $output = '';
- $output .= '' . t('The administration menu module provides a dropdown menu arranged for one- or two-click access to most administrative tasks and other common destinations (to users with the proper permissions). Administration menu also displays the number of anonymous and authenticated users, and allows modules to add their own custom menu items. Integration with the menu varies from module to module; the contributed module Devel , for instance, makes strong use of the administration menu module to provide quick access to development tools.', array('@drupal' => 'http://drupal.org/project/devel')) . '
';
- $output .= '' . t('The administration menu settings page allows you to modify some elements of the menu\'s behavior and appearance. Since the appearance of the menu is dependent on your site theme, substantial customizations require modifications to your site\'s theme and CSS files. See the advanced module README.txt file for more information on theme and CSS customizations.', array('@settings' => url('admin/config/administration/admin_menu'))) . '
';
- $output .= '' . t('The menu items displayed in the administration menu depend upon the actual permissions of the viewer. First, the administration menu is only displayed to users in roles with the Access administration menu (admin_menu module) permission. Second, a user must be a member of a role with the Access administration pages (system module) permission to view administrative links. And, third, only currently permitted links are displayed; for example, if a user is not a member of a role with the permissions Administer permissions (user module) and Administer users (user module), the User management menu item is not displayed.') . '
';
- return $output;
- }
-}
-
-/**
- * Implements hook_permission().
- */
-function admin_menu_permission() {
- return array(
- 'access administration menu' => array(
- 'title' => t('Access administration menu'),
- 'description' => t('Display the administration menu at the top of each page.'),
- ),
- 'flush caches' => array(
- 'title' => t('Flush caches'),
- 'description' => t('Access links to flush caches in the administration menu.'),
- ),
- 'display drupal links' => array(
- 'title' => t('Display Drupal links'),
- 'description' => t('Provide Drupal.org links in the administration menu.'),
- ),
- );
-}
-
-/**
- * Implements hook_theme().
- */
-function admin_menu_theme() {
- return array(
- 'admin_menu_links' => array(
- 'render element' => 'elements',
- ),
- 'admin_menu_icon' => array(
- 'variables' => array('src' => NULL, 'alt' => NULL),
- 'file' => 'admin_menu.inc',
- ),
- );
-}
-
-/**
- * Implements hook_menu().
- */
-function admin_menu_menu() {
- // AJAX callback.
- // @see http://drupal.org/project/js
- $items['js/admin_menu/cache'] = array(
- 'page callback' => 'admin_menu_js_cache',
- 'delivery callback' => 'admin_menu_deliver',
- 'access arguments' => array('access administration menu'),
- 'type' => MENU_CALLBACK,
- );
- // Module settings.
- $items['admin/config/administration'] = array(
- 'title' => 'Administration',
- 'description' => 'Administration tools.',
- 'page callback' => 'system_admin_menu_block_page',
- 'access arguments' => array('access administration pages'),
- 'file' => 'system.admin.inc',
- 'file path' => drupal_get_path('module', 'system'),
- );
- $items['admin/config/administration/admin_menu'] = array(
- 'title' => 'Administration menu',
- 'description' => 'Adjust administration menu settings.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('admin_menu_theme_settings'),
- 'access arguments' => array('administer site configuration'),
- 'file' => 'admin_menu.inc',
- );
- // Menu link callbacks.
- $items['admin_menu/toggle-modules'] = array(
- 'page callback' => 'admin_menu_toggle_modules',
- 'access arguments' => array('administer modules'),
- 'type' => MENU_CALLBACK,
- 'file' => 'admin_menu.inc',
- );
- $items['admin_menu/flush-cache'] = array(
- 'page callback' => 'admin_menu_flush_cache',
- 'access arguments' => array('flush caches'),
- 'type' => MENU_CALLBACK,
- 'file' => 'admin_menu.inc',
- );
- return $items;
-}
-
-/**
- * Implements hook_menu_alter().
- */
-function admin_menu_menu_alter(&$items) {
- // Flush client-side caches whenever the menu is rebuilt.
- admin_menu_flush_caches();
-}
-
-/**
- * Implements hook_menu_link_insert().
- */
-function admin_menu_menu_link_insert($link) {
- // Flush all of our caches to pick up the link.
- admin_menu_flush_caches();
-}
-
-/**
- * Implements hook_menu_link_update().
- */
-function admin_menu_menu_link_update($link) {
- // Flush all of our caches to pick up the link.
- admin_menu_flush_caches();
-}
-
-/**
- * Implements hook_menu_link_delete().
- */
-function admin_menu_menu_link_delete($link) {
- // Flush all of our caches to pick up the link.
- admin_menu_flush_caches();
-}
-
-/**
- * Implements hook_system_info_alter().
- *
- * Indicate that the 'page_bottom' region (in which the administration menu
- * is displayed) is an overlay supplemental region that should be refreshed
- * whenever its content is updated.
- *
- * @see toolbar_system_info_alter()
- */
-function admin_menu_system_info_alter(&$info, $file, $type) {
- if ($type == 'theme') {
- $info['overlay_supplemental_regions'][] = 'page_bottom';
- }
-}
-
-/**
- * Implements hook_page_build().
- */
-function admin_menu_page_build(&$page) {
- if (!user_access('access administration menu') || admin_menu_suppress(FALSE)) {
- return;
- }
- // Performance: Skip this entirely for AJAX requests.
- if (strpos($_GET['q'], 'js/') === 0) {
- return;
- }
- global $user, $language;
- $path = drupal_get_path('module', 'admin_menu');
-
- $page['page_bottom']['admin_menu'] = array(
- '#attached' => array(),
- );
- $attached = &$page['page_bottom']['admin_menu']['#attached'];
- $options = array('every_page' => TRUE);
-
- $attached['css'][$path . '/admin_menu.css'] = $options;
- if ($user->uid == 1) {
- $attached['css'][$path . '/admin_menu.uid1.css'] = $options;
- }
- // Previous versions used the 'defer' attribute to increase browser rendering
- // performance. At least starting with Firefox 3.6, deferred .js files are
- // loaded, but Drupal.behaviors are not contained in the DOM when drupal.js
- // executes Drupal.attachBehaviors().
- $attached['js'][$path . '/admin_menu.js'] = $options;
-
- // Destination query strings are applied via JS.
- $settings['destination'] = drupal_http_build_query(drupal_get_destination());
-
- // Determine whether we need to show all components and disable all caches.
- $complete = FALSE;
- if (current_path() == 'admin/config/administration/admin_menu' && $_SERVER['REQUEST_METHOD'] == 'GET') {
- $complete = TRUE;
- }
-
- // If the client supports JavaScript and we have a cached menu for the current
- // user, only output the hash for the client-side HTTP cache callback URL.
- $cid = 'admin_menu:' . $user->uid . ':' . session_id() . ':' . $language->language;
- if (!$complete && !empty($_COOKIE['has_js']) && ($hash = admin_menu_cache_get($cid))) {
- $settings['hash'] = $hash;
- // The base path to use for cache requests depends on whether clean URLs
- // are enabled, whether Drupal runs in a sub-directory, and on the language
- // system configuration. url() already provides us the proper path and also
- // invokes potentially existing custom_url_rewrite() functions, which may
- // add further required components to the URL to provide context. Due to
- // those components, and since url('') returns only base_path() when clean
- // URLs are disabled, we need to use a replacement token as path. Yuck.
- $settings['basePath'] = url('admin_menu');
- }
- // Otherwise, add the full menu to the page.
- else {
- $page['page_bottom']['admin_menu']['#markup'] = admin_menu_output($complete);
- }
-
- $replacements = module_invoke_all('admin_menu_replacements', $complete);
- if (!empty($replacements)) {
- $settings['replacements'] = $replacements;
- }
-
- if ($setting = variable_get('admin_menu_margin_top', 1)) {
- $settings['margin_top'] = $setting;
- // @todo Drupal.behaviors.adminMenuMarginTop is obsolete, but
- // hook_page_build() does not allow to set a CSS class on the body yet.
- // @see http://drupal.org/node/1473548, http://drupal.org/node/1194528
- //$page['#attributes']['class'][] = 'admin-menu';
- }
- if ($setting = variable_get('admin_menu_position_fixed', 1)) {
- $settings['position_fixed'] = $setting;
-
- // In fixed positioning, supply a callback function for tableheader.js to
- // allow it to determine the top viewport offset.
- // @see admin_menu.js, toolbar.js
- $attached['js'][] = array(
- 'data' => array('tableHeaderOffset' => 'Drupal.admin.height'),
- 'type' => 'setting',
- );
- }
- if ($setting = variable_get('admin_menu_tweak_tabs', 0)) {
- $settings['tweak_tabs'] = $setting;
- }
- if ($_GET['q'] == 'admin/modules' || strpos($_GET['q'], 'admin/modules/list') === 0) {
- $settings['tweak_modules'] = variable_get('admin_menu_tweak_modules', 0);
- }
- if ($_GET['q'] == 'admin/people/permissions' || $_GET['q'] == 'admin/people/permissions/list') {
- $settings['tweak_permissions'] = variable_get('admin_menu_tweak_permissions', 0);
- }
-
- $attached['js'][] = array(
- 'data' => array('admin_menu' => $settings),
- 'type' => 'setting',
- );
-}
-
-/**
- * Suppress display of administration menu.
- *
- * This function should be called from within another module's page callback
- * (preferably using module_invoke()) when the menu should not be displayed.
- * This is useful for modules that implement popup pages or other special
- * pages where the menu would be distracting or break the layout.
- *
- * @param $set
- * Defaults to TRUE. If called before hook_footer(), the menu will not be
- * displayed. If FALSE is passed, the suppression state is returned.
- */
-function admin_menu_suppress($set = TRUE) {
- static $suppress = FALSE;
- // drupal_add_js() must only be invoked once.
- if (!empty($set) && $suppress === FALSE) {
- $suppress = TRUE;
- drupal_add_js(array('admin_menu' => array('suppress' => 1)), 'setting');
- }
- return $suppress;
-}
-
-/**
- * Implements hook_js().
- */
-function admin_menu_js() {
- return array(
- 'cache' => array(
- 'callback' => 'admin_menu_js_cache',
- 'includes' => array('common', 'theme', 'unicode'),
- 'dependencies' => array('devel', 'filter', 'user'),
- ),
- );
-}
-
-/**
- * Retrieve a client-side cache hash from cache.
- *
- * The hash cache is consulted more than once per request; we therefore cache
- * the results statically to avoid multiple database requests.
- *
- * This should only be used for client-side cache hashes. Use cache_menu for
- * administration menu content.
- *
- * @param $cid
- * The cache ID of the data to retrieve.
- */
-function admin_menu_cache_get($cid) {
- $cache = &drupal_static(__FUNCTION__, array());
-
- if (!variable_get('admin_menu_cache_client', TRUE)) {
- return FALSE;
- }
- if (!array_key_exists($cid, $cache)) {
- $cache[$cid] = cache_get($cid, 'cache_admin_menu');
- if ($cache[$cid] && isset($cache[$cid]->data)) {
- $cache[$cid] = $cache[$cid]->data;
- }
- }
-
- return $cache[$cid];
-}
-
-/**
- * Store a client-side cache hash in persistent cache.
- *
- * This should only be used for client-side cache hashes. Use cache_menu for
- * administration menu content.
- *
- * @param $cid
- * The cache ID of the data to retrieve.
- */
-function admin_menu_cache_set($cid, $data) {
- if (variable_get('admin_menu_cache_client', TRUE)) {
- cache_set($cid, $data, 'cache_admin_menu');
- }
-}
-
-/**
- * Menu callback; Output administration menu for HTTP caching via AJAX request.
- *
- * @see admin_menu_deliver()
- */
-function admin_menu_js_cache() {
- global $conf;
-
- // Suppress Devel module.
- $GLOBALS['devel_shutdown'] = FALSE;
-
- // Enforce page caching.
- $conf['cache'] = 1;
- drupal_page_is_cacheable(TRUE);
-
- // If we have a cache, serve it.
- // @see _drupal_bootstrap_page_cache()
- $cache = drupal_page_get_cache();
- if (is_object($cache)) {
- header('X-Drupal-Cache: HIT');
- // Restore the metadata cached with the page.
- $_GET['q'] = $cache->data['path'];
- date_default_timezone_set(drupal_get_user_timezone());
-
- drupal_serve_page_from_cache($cache);
-
- // We are done.
- exit;
- }
-
- // Otherwise, create a new page response (that will be cached).
- header('X-Drupal-Cache: MISS');
-
- // The Expires HTTP header is the heart of the client-side HTTP caching. The
- // additional server-side page cache only takes effect when the client
- // accesses the callback URL again (e.g., after clearing the browser cache or
- // when force-reloading a Drupal page).
- $max_age = 3600 * 24 * 365;
- drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
- drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
-
- // Retrieve and return the rendered menu.
- return admin_menu_output();
-}
-
-/**
- * Delivery callback for client-side HTTP caching.
- *
- * @see admin_menu_js_cache()
- */
-function admin_menu_deliver($page_callback_result) {
- drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
-
- // Send appropriate language header for browsers.
- global $language;
- drupal_add_http_header('Content-Language', $language->language);
-
- // The page callback is always admin_menu_js_cache(), which always returns a
- // string, and is only accessed when the user actually has access to it.
- // Therefore, we do not care for the other possible page callback results.
- print $page_callback_result;
-
- // Perform end-of-request tasks. The page cache is created here.
- drupal_page_footer();
-}
-
-/**
- * Implements hook_admin_menu_replacements().
- */
-function admin_menu_admin_menu_replacements($complete) {
- $items = array();
- // If the complete menu is output, then it is uncached and will contain the
- // current counts already.
- if (!$complete) {
- // Check whether the users count component is enabled.
- $components = variable_get('admin_menu_components', array());
- if (!empty($components['admin_menu.users']) && ($user_count = admin_menu_get_user_count())) {
- // Replace the counters in the cached menu output with current counts.
- $items['.admin-menu-users a'] = $user_count;
- }
- }
- return $items;
-}
-
-/**
- * Return count of online anonymous/authenticated users.
- *
- * @see user_block(), user.module
- */
-function admin_menu_get_user_count() {
- $interval = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
- $count_anon = admin_menu_session_count($interval, TRUE);
- $count_auth = admin_menu_session_count($interval, FALSE);
-
- return t('@count-anon / @count-auth', array('@count-anon' => $count_anon, '@count-auth' => $count_auth));
-}
-
-/**
- * Counts how many users are active on the site.
- *
- * Counts how many users have sessions which have been active since the
- * specified time. Can count either anonymous sessions or authenticated
- * sessions.
- *
- * @param $timestamp
- * A Unix timestamp. Users who have been active since this time will be
- * counted. The default is 0, which counts all existing sessions.
- * @param $anonymous
- * TRUE counts only anonymous users. FALSE counts only authenticated users.
- *
- * @return
- * The number of users with sessions.
- *
- * @todo There are mostly no anonymous sessions anymore. Split this into a
- * separate module providing proper user statistics.
- */
-function admin_menu_session_count($timestamp = 0, $anonymous = TRUE) {
- $query = db_select('sessions');
- $query->addExpression('COUNT(sid)', 'count');
- $query->condition('timestamp', $timestamp, '>=');
- $query->condition('uid', 0, $anonymous ? '=' : '>');
- return $query->execute()->fetchField();
-}
-
-/**
- * Build the administration menu output.
- *
- * @param bool $complete
- * (optional) Whether to build to the complete menu including all components
- * and ignore the cache. Defaults to FALSE. Internally used for the settings
- * page.
- */
-function admin_menu_output($complete = FALSE) {
- global $user, $language;
-
- $cache_server_enabled = !$complete && variable_get('admin_menu_cache_server', TRUE);
- $cid = 'admin_menu:' . $user->uid . ':' . session_id() . ':' . $language->language;
-
- // Try to load and output administration menu from server-side cache.
- // @todo Duplicates the page cache? Page cache ID contains the hash that is
- // generated at the bottom of this function, which is based on $content,
- // but logically identical to the $cid. Investigate whether not only the
- // cache_menu but also the cache_admin_menu could be dropped; the
- // client-side HTTP cache hash check could be based on a cid lookup in
- // cache_page instead? (i.e., one cache to rule them all) However,
- // cache_page is cleared very often.
- if ($cache_server_enabled) {
- $cache = cache_get($cid, 'cache_menu');
- if ($cache && isset($cache->data)) {
- $content = $cache->data;
- }
- }
-
- // Rebuild the output.
- if (!isset($content)) {
- // Retrieve enabled components to display and make them available for others.
- $components = variable_get('admin_menu_components', array());
- $components += array(
- 'admin_menu.menu' => TRUE,
- 'admin_menu.icon' => TRUE,
- 'admin_menu.account' => TRUE,
- );
- $content['#components'] = $components;
- $content['#complete'] = $complete;
-
- // Add site name as CSS class for development/staging theming purposes. We
- // leverage the cookie domain instead of HTTP_HOST to account for many (but
- // not all) multi-domain setups (e.g. language-based sub-domains).
- $classes = 'admin-menu-site' . drupal_strtolower(preg_replace('/[^a-zA-Z0-9-]/', '-', $GLOBALS['cookie_domain']));
- // Displace overlay.
- // @see Drupal.overlay.create
- // @see toolbar_preprocess_toolbar()
- if (module_exists('overlay')) {
- $classes .= ' overlay-displace-top';
- }
- // @todo Always output container to harden JS-less support.
- $content['#prefix'] = '';
-
- // Load menu builder functions.
- module_load_include('inc', 'admin_menu');
-
- // @todo Move the below callbacks into hook_admin_menu_build()
- // implementations (and $module.admin_menu.inc).
-
- // Add administration menu.
- if (!empty($components['admin_menu.menu']) || $complete) {
- $content['menu'] = admin_menu_links_menu(admin_menu_tree('management'));
- $content['menu']['#theme'] = 'admin_menu_links';
- $content['menu']['#wrapper_attributes']['id'] = 'admin-menu-menu';
- // Ensure the menu tree is rendered between the icon and user links.
- $content['menu']['#weight'] = 0;
- }
-
- // Add menu additions.
- if (!empty($components['admin_menu.icon']) || $complete) {
- $content['icon'] = admin_menu_links_icon();
- }
- if (!empty($components['admin_menu.account']) || $complete) {
- $content['account'] = admin_menu_links_account();
- }
- if (!empty($components['admin_menu.users']) || $complete) {
- $content['users'] = admin_menu_links_users();
- }
- if (!empty($components['admin_menu.search']) || $complete) {
- $content['search'] = admin_menu_links_search();
- }
-
- // Allow modules to enhance the menu.
- // Uses '_output' suffix for consistency with the alter hook (see below).
- foreach (module_implements('admin_menu_output_build') as $module) {
- $function = $module . '_admin_menu_output_build';
- $function($content);
- }
-
- // Allow modules to alter the output.
- // The '_output' suffix is required to prevent hook implementation function
- // name clashes with the contributed Admin module.
- drupal_alter('admin_menu_output', $content);
-
- $content = drupal_render($content);
-
- // Cache the menu for this user.
- if ($cache_server_enabled) {
- cache_set($cid, $content, 'cache_menu');
- }
- }
-
- // Store the new hash for this user.
- if (!empty($_COOKIE['has_js']) && !$complete) {
- admin_menu_cache_set($cid, md5($content));
- }
-
- return $content;
-}
-
-/**
- * Implements hook_admin_menu_output_build().
- */
-function admin_menu_admin_menu_output_build(&$content) {
- if (!isset($content['menu'])) {
- return;
- }
-
- // Unassign weights for categories below Configuration.
- // An alphabetical order is more natural for a dropdown menu.
- if (isset($content['menu']['admin/config'])) {
- foreach (element_children($content['menu']['admin/config']) as $key) {
- $content['menu']['admin/config'][$key]['#weight_original'] = $content['menu']['admin/config'][$key]['#weight'];
- unset($content['menu']['admin/config'][$key]['#weight']);
- }
- }
-
- // Retrieve the "Add content" link tree.
- $link = db_query("SELECT * FROM {menu_links} WHERE router_path = 'node/add' AND module = 'system'")->fetchAssoc();
- $conditions = array();
- for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
- if (!empty($link["p$i"])) {
- $conditions["p$i"] = $link["p$i"];
- }
- }
- $tree = menu_build_tree($link['menu_name'], array(
- 'conditions' => $conditions,
- 'min_depth' => $link['depth'],
- ));
- $links = admin_menu_links_menu($tree);
- if (!empty($links)) {
- // If the user has access to the top-level "Content" category, insert the
- // "Add content" link tree there.
- if (isset($content['menu']['admin/content'])) {
- $content['menu']['admin/content'] += $links;
- }
- // Otherwise make insert "Add content" as top-level category.
- else {
- $key = key($links);
- $links[$key]['#weight'] = -100;
- $content['menu'] += $links;
- }
- }
-}
-
-/**
- * Implements hook_admin_menu_output_alter().
- */
-function admin_menu_admin_menu_output_alter(&$content) {
- foreach ($content['menu'] as $key => $link) {
- // Move local tasks on 'admin' into icon menu.
- if ($key == 'admin/tasks' || $key == 'admin/index') {
- $content['icon']['icon'][$key] = $link;
- unset($content['menu'][$key]);
- }
- }
-}
-
-/**
- * Render a themed list of links.
- *
- * @param $variables
- * - elements: A renderable array of links using the following keys:
- * - #attributes: Optional array of attributes for the list item, processed
- * via drupal_attributes().
- * - #title: Title of the link, passed to l().
- * - #href: Optional path of the link, passed to l(). When omitted, the
- * element's '#title' is rendered without link.
- * - #description: Optional alternative text for the link, passed to l().
- * - #options: Optional alternative text for the link, passed to l().
- * The array key of each child element itself is passed as path for l().
- */
-function theme_admin_menu_links($variables) {
- $destination = &drupal_static('admin_menu_destination');
- $elements = $variables['elements'];
-
- if (!isset($destination)) {
- $destination = drupal_get_destination();
- $destination = $destination['destination'];
- }
-
- // The majority of items in the menu are sorted already, but since modules
- // may add or change arbitrary items anywhere, there is no way around sorting
- // everything again. element_sort() is not sufficient here, as it
- // intentionally retains the order of elements having the same #weight,
- // whereas menu links are supposed to be ordered by #weight and #title.
- uasort($elements, 'admin_menu_element_sort');
- $elements['#sorted'] = TRUE;
-
- $output = '';
- foreach (element_children($elements) as $path) {
- // Early-return nothing if user does not have access.
- if (isset($elements[$path]['#access']) && !$elements[$path]['#access']) {
- continue;
- }
- $elements[$path] += array(
- '#attributes' => array(),
- '#options' => array(),
- );
- // Render children to determine whether this link is expandable.
- if (isset($elements[$path]['#type']) || isset($elements[$path]['#theme']) || isset($elements[$path]['#pre_render'])) {
- $elements[$path]['#children'] = drupal_render($elements[$path]);
- }
- else {
- $elements[$path]['#children'] = theme('admin_menu_links', array('elements' => $elements[$path]));
- if (!empty($elements[$path]['#children'])) {
- $elements[$path]['#attributes']['class'][] = 'expandable';
- }
- if (isset($elements[$path]['#attributes']['class'])) {
- $elements[$path]['#attributes']['class'] = $elements[$path]['#attributes']['class'];
- }
- }
-
- $link = '';
- // Handle menu links.
- if (isset($elements[$path]['#href'])) {
- // Strip destination query string from href attribute and apply a CSS class
- // for our JavaScript behavior instead.
- if (isset($elements[$path]['#options']['query']['destination']) && $elements[$path]['#options']['query']['destination'] == $destination) {
- unset($elements[$path]['#options']['query']['destination']);
- $elements[$path]['#options']['attributes']['class'][] = 'admin-menu-destination';
- }
-
- $link = l($elements[$path]['#title'], $elements[$path]['#href'], $elements[$path]['#options']);
- }
- // Handle plain text items, but do not interfere with menu additions.
- elseif (!isset($elements[$path]['#type']) && isset($elements[$path]['#title'])) {
- if (!empty($elements[$path]['#options']['html'])) {
- $title = $elements[$path]['#title'];
- }
- else {
- $title = check_plain($elements[$path]['#title']);
- }
- $attributes = '';
- if (isset($elements[$path]['#options']['attributes'])) {
- $attributes = drupal_attributes($elements[$path]['#options']['attributes']);
- }
- $link = '' . $title . ' ';
- }
-
- $output .= '';
- $output .= $link . $elements[$path]['#children'];
- $output .= ' ';
- }
- // @todo #attributes probably required for UL, but already used for LI.
- // @todo Use $element['#children'] here instead.
- if ($output) {
- $elements['#wrapper_attributes']['class'][] = 'dropdown';
- $attributes = drupal_attributes($elements['#wrapper_attributes']);
- $output = "\n" . '';
- }
- return $output;
-}
-
-/**
- * Function used by uasort to sort structured arrays by #weight AND #title.
- */
-function admin_menu_element_sort($a, $b) {
- // @see element_sort()
- $a_weight = isset($a['#weight']) ? $a['#weight'] : 0;
- $b_weight = isset($b['#weight']) ? $b['#weight'] : 0;
- if ($a_weight == $b_weight) {
- // @see element_sort_by_title()
- $a_title = isset($a['#title']) ? $a['#title'] : '';
- $b_title = isset($b['#title']) ? $b['#title'] : '';
- return strnatcasecmp($a_title, $b_title);
- }
- return ($a_weight < $b_weight) ? -1 : 1;
-}
-
-/**
- * Implements hook_translated_menu_link_alter().
- *
- * Here is where we make changes to links that need dynamic information such
- * as the current page path or the number of users.
- */
-function admin_menu_translated_menu_link_alter(&$item, $map) {
- global $user, $base_url;
- static $access_all;
-
- if ($item['menu_name'] != 'admin_menu') {
- return;
- }
-
- // Check whether additional development output is enabled.
- if (!isset($access_all)) {
- $access_all = variable_get('admin_menu_show_all', 0) && module_exists('devel');
- }
- // Prepare links that would not be displayed normally.
- if ($access_all && !$item['access']) {
- $item['access'] = TRUE;
- // Prepare for http://drupal.org/node/266596
- if (!isset($item['localized_options'])) {
- _menu_item_localize($item, $map, TRUE);
- }
- }
-
- // Don't waste cycles altering items that are not visible
- if (!$item['access']) {
- return;
- }
-
- // Add developer information to all links, if enabled.
- if ($extra = variable_get('admin_menu_display', 0)) {
- $item['title'] .= ' ' . $extra[0] . ': ' . $item[$extra];
- }
-}
-
-/**
- * Implements hook_flush_caches().
- *
- * Flushes client-side caches.
- *
- * @param int $uid
- * (optional) A user ID to limit the cache flush to.
- */
-function admin_menu_flush_caches($uid = NULL) {
- // A call to menu_rebuild() will trigger potentially thousands of calls into
- // menu_link_save(), for which admin_menu has to implement the corresponding
- // CRUD hooks, in order to take up any menu link changes, since any menu link
- // change could affect the admin menu (which essentially is an aggregate) and
- // since there is no other way to get notified about stale caches. The cache
- // only needs to be flushed once though, so we prevent a ton of needless
- // subsequent calls with this static.
- // @see http://drupal.org/node/918538
- $was_flushed = &drupal_static(__FUNCTION__, array());
- // $uid can be NULL. PHP automatically converts that into '' (empty string),
- // which is different to uid 0 (zero).
- if (isset($was_flushed[$uid])) {
- return;
- }
- $was_flushed[$uid] = TRUE;
-
- $cid = 'admin_menu:';
- if (isset($uid)) {
- $cid .= $uid . ':';
- }
- // Flush cached output of admin_menu.
- cache_clear_all($cid, 'cache_menu', TRUE);
- // Flush client-side cache hashes.
- drupal_static_reset('admin_menu_cache_get');
- // db_table_exists() required for SimpleTest.
- if (db_table_exists('cache_admin_menu')) {
- cache_clear_all(isset($uid) ? $cid : '*', 'cache_admin_menu', TRUE);
- }
-}
-
-/**
- * Implements hook_form_alter().
- */
-function admin_menu_form_alter(&$form, &$form_state, $form_id) {
- $global_flush_ids = array(
- 'admin_menu_theme_settings' => 1,
- // Update links for clean/non-clean URLs.
- 'system_clean_url_settings' => 1,
- // Incorporate changed user permissions.
- 'user_admin_permissions' => 1,
- // Removing a role potentially means less permissions.
- 'user_admin_role_delete_confirm' => 1,
- // User name and roles may be changed on the user account form.
- 'user_profile_form' => 1,
- );
- if (isset($global_flush_ids[$form_id])) {
- $form['#submit'][] = 'admin_menu_form_alter_flush_cache_submit';
-
- // Optionally limit the cache flush to a certain user ID.
- $form_state['admin_menu_uid'] = NULL;
- if ($form_id == 'user_profile_form') {
- $form_state['admin_menu_uid'] = $form_state['user']->uid;
- }
- }
-
- // UX: Add a confirmation to the permissions form to ask the user whether to
- // auto-enable the 'access administration menu' permission along with
- // 'access administration pages'.
- if ($form_id == 'user_admin_permissions') {
- $form['#attached']['js'][] = drupal_get_path('module', 'admin_menu') . '/admin_menu.admin.js';
- }
-}
-
-/**
- * Form submission handler to flush Administration menu caches.
- */
-function admin_menu_form_alter_flush_cache_submit($form, &$form_state) {
- admin_menu_flush_caches($form_state['admin_menu_uid']);
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Extends Devel module with Administration menu developer settings.
- */
-function admin_menu_form_devel_admin_settings_alter(&$form, &$form_state) {
- form_load_include($form_state, 'inc', 'admin_menu');
- _admin_menu_form_devel_admin_settings_alter($form, $form_state);
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu.uid1.css b/sites/all/modules/contrib/admin_menu/admin_menu.uid1.css
deleted file mode 100644
index e375cfe6..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu.uid1.css
+++ /dev/null
@@ -1,9 +0,0 @@
-
-/**
- * @file
- * Administration menu color override for uid1.
- */
-
-#admin-menu li.admin-menu-account > a {
- background: #911 url(images/bkg-red.png) bottom left repeat-x;
-}
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css
deleted file mode 100644
index a3e9f3e3..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css
+++ /dev/null
@@ -1,145 +0,0 @@
-
-/**
- * @file
- * Toolbar style for Administration menu.
- *
- * Important: We cannot re-use toolbar.png from Toolbar module, since we cannot
- * reliably determine the path to it.
- *
- * @todo Separate shortcut functionality into own module/widget.
- */
-
-/* Adjust margin/height */
-html body.admin-menu {
- margin-top: 29px !important;
-}
-html body.admin-menu-with-shortcuts {
- margin-top: 65px !important;
-}
-/* Displace the core Toolbar, if concurrently output. */
-body div#toolbar.toolbar {
- top: 30px;
-}
-
-/**
- * Base styles.
- *
- * We use a keyword for the toolbar font size to make it display consistently
- * across different themes, while still allowing browsers to resize the text.
- */
-#admin-menu {
- font: normal small "Lucida Grande", Verdana, sans-serif;
- -moz-box-shadow: 0 -10px 20px 13px #000;
- -webkit-box-shadow: 0 -10px 20px 13px #000;
- box-shadow: 0 -10px 20px 13px #000;
- right: 0;
- width: auto;
-}
-#admin-menu-wrapper {
- font-size: .846em;
- padding: 5px 10px 0;
-}
-
-#admin-menu .dropdown a {
- color: #fafafa;
-}
-
-/* Remove border from all lists and actions */
-#admin-menu .dropdown .admin-menu-action a {
- border-left: 0;
-}
-#admin-menu .dropdown .admin-menu-icon > a {
- padding: 2px 10px 3px;
-}
-
-/**
- * Administration menu.
- */
-#admin-menu .dropdown .admin-menu-icon > a span {
- vertical-align: text-bottom;
- width: 11px;
- height: 14px;
- display: block;
- background: url(toolbar.png) no-repeat 0 -45px;
- text-indent: -9999px;
-}
-#admin-menu > div > .dropdown > li > a {
- border-right: 0;
- margin-bottom: 4px;
- padding: 2px 10px 3px;
-}
-#admin-menu .dropdown .admin-menu-toolbar-category > a,
-#admin-menu .dropdown .admin-menu-action > a {
- border-radius: 10px;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
-}
-#admin-menu .dropdown .admin-menu-toolbar-category > a.active-trail {
- text-shadow: #333 0 1px 0;
- background: url(toolbar.png) 0 0 repeat-x;
-}
-#admin-menu .dropdown .admin-menu-toolbar-category > a:hover {
- background-color: #444;
-}
-#admin-menu .dropdown .admin-menu-tab a {
- border-right: 0;
-}
-#admin-menu .dropdown li li.expandable ul {
- margin: -22px 0 0 160px;
-}
-
-/**
- * Shortcuts toggle.
- */
-#admin-menu .shortcut-toggle {
- cursor: pointer;
- background: url(toolbar.png) 0 -20px no-repeat;
- display: block;
- float: right;
- margin: 0 0 0 1.3em;
- text-indent: -9999px;
- overflow: hidden;
- width: 25px;
- height: 25px;
-}
-#admin-menu .shortcut-toggle:focus,
-#admin-menu .shortcut-toggle:hover {
- background-position: -50px -20px;
-}
-#admin-menu .shortcut-toggle.active {
- background-position: -25px -20px;
-}
-#admin-menu .shortcut-toggle.active:focus,
-#admin-menu .shortcut-toggle.active:hover {
- background-position: -75px -20px;
-}
-
-/**
- * Shortcuts widget.
- */
-#admin-menu .shortcut-toolbar {
- background-color: #666;
- clear: both;
- display: none;
- margin: 0 -10px;
- overflow: hidden;
- /* Align with icon; @see shortcut.css */
- padding-left: 5px;
-}
-#admin-menu .shortcut-toolbar.active {
- display: block;
-}
-/* Override theme list style; @see shortcut.css */
-#admin-menu .shortcut-toolbar ul {
- margin: 0;
-}
-/* @see toolbar.css */
-#admin-menu .shortcut-toolbar li {
- float: left;
- list-style-image: none;
- list-style-type: none;
-}
-#admin-menu .shortcut-toolbar a {
- display: block;
-}
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info
deleted file mode 100644
index 2514776c..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info
+++ /dev/null
@@ -1,12 +0,0 @@
-name = Administration menu Toolbar style
-description = A better Toolbar.
-package = Administration
-core = 7.x
-dependencies[] = admin_menu
-
-; Information added by drupal.org packaging script on 2013-01-31
-version = "7.x-3.0-rc4"
-core = "7.x"
-project = "admin_menu"
-datestamp = "1359651687"
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install
deleted file mode 100644
index bf067d78..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install
+++ /dev/null
@@ -1,37 +0,0 @@
-fields(array('weight' => 101))
- ->condition('type', 'module')
- ->condition('name', 'admin_menu_toolbar')
- ->execute();
-}
-
-/**
- * Set module weight to a value higher than admin_menu.
- *
- * At this point, admin_menu should have a weight of 100. To account for
- * customized weights, we increase the weight relatively.
- *
- * @see admin_menu_toolbar_install()
- */
-function admin_menu_toolbar_update_6300() {
- $weight = db_query("SELECT weight FROM {system} WHERE type = 'module' AND name = 'admin_menu'")->fetchField();
- $weight++;
- db_update('system')
- ->fields(array('weight' => $weight))
- ->condition('type', 'module')
- ->condition('name', 'admin_menu_toolbar')
- ->execute();
-}
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js
deleted file mode 100644
index 809d9ead..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js
+++ /dev/null
@@ -1,56 +0,0 @@
-(function($) {
-
-Drupal.admin = Drupal.admin || {};
-Drupal.admin.behaviors = Drupal.admin.behaviors || {};
-
-/**
- * @ingroup admin_behaviors
- * @{
- */
-
-/**
- * Apply active trail highlighting based on current path.
- *
- * @todo Not limited to toolbar; move into core?
- */
-Drupal.admin.behaviors.toolbarActiveTrail = function (context, settings, $adminMenu) {
- if (settings.admin_menu.toolbar && settings.admin_menu.toolbar.activeTrail) {
- $adminMenu.find('> div > ul > li > a[href="' + settings.admin_menu.toolbar.activeTrail + '"]').addClass('active-trail');
- }
-};
-
-/**
- * Toggles the shortcuts bar.
- */
-Drupal.admin.behaviors.shortcutToggle = function (context, settings, $adminMenu) {
- var $shortcuts = $adminMenu.find('.shortcut-toolbar');
- if (!$shortcuts.length) {
- return;
- }
- var storage = window.localStorage || false;
- var storageKey = 'Drupal.admin_menu.shortcut';
- var $body = $(context).find('body');
- var $toggle = $adminMenu.find('.shortcut-toggle');
- $toggle.click(function () {
- var enable = !$shortcuts.hasClass('active');
- $shortcuts.toggleClass('active', enable);
- $toggle.toggleClass('active', enable);
- if (settings.admin_menu.margin_top) {
- $body.toggleClass('admin-menu-with-shortcuts', enable);
- }
- // Persist toggle state across requests.
- storage && enable ? storage.setItem(storageKey, 1) : storage.removeItem(storageKey);
- this.blur();
- return false;
- });
-
- if (!storage || storage.getItem(storageKey)) {
- $toggle.trigger('click');
- }
-};
-
-/**
- * @} End of "ingroup admin_behaviors".
- */
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module
deleted file mode 100644
index 74a9ee1f..00000000
--- a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module
+++ /dev/null
@@ -1,118 +0,0 @@
- TRUE);
-
- $attached['css'][$path . '/admin_menu_toolbar.css'] = $options;
- $attached['js'][$path . '/admin_menu_toolbar.js'] = $options;
-
- // @todo Stop-gap fix until cached rendering is resolved.
- // @see http://drupal.org/node/1567622
- if (module_exists('shortcut')) {
- $attached['css'][drupal_get_path('module', 'shortcut') . '/shortcut.css'] = $options;
- }
-
- $settings = array();
- // Add current path to support menu item highlighting.
- // @todo Compile real active trail here?
- $args = explode('/', $_GET['q']);
- if ($args[0] == 'admin' && !empty($args[1])) {
- $settings['activeTrail'] = url($args[0] . '/' . $args[1]);
- }
- elseif (drupal_is_front_page()) {
- $settings['activeTrail'] = url('');
- }
-
- $attached['js'][] = array(
- 'data' => array('admin_menu' => array('toolbar' => $settings)),
- 'type' => 'setting',
- );
-}
-
-/**
- * Implements hook_admin_menu_output_build().
- */
-function admin_menu_toolbar_admin_menu_output_build(&$content) {
- if (empty($content['#components']['shortcut.links']) && !$content['#complete']) {
- return;
- }
- // Add shortcuts toggle.
- $content['shortcut-toggle'] = array(
- '#access' => module_exists('shortcut'),
- '#weight' => -200,
- '#type' => 'link',
- '#title' => t('Show shortcuts'),
- '#href' => '',
- '#options' => array(
- 'attributes' => array('class' => 'shortcut-toggle'),
- ),
- );
-
- // Add shortcuts bar.
- $content['shortcut'] = array(
- '#access' => module_exists('shortcut'),
- '#weight' => 200,
- '#prefix' => '',
- '#suffix' => '
',
- );
- $content['shortcut']['shortcuts'] = array(
- // Shortcut module's CSS relies on Toolbar module's markup.
- // @see http://drupal.org/node/1217038
- '#prefix' => '',
- '#suffix' => '
',
- // @todo Links may contain .active-trail classes.
- '#pre_render' => array('shortcut_toolbar_pre_render'),
- );
-}
-
-/**
- * Implements hook_admin_menu_output_alter().
- */
-function admin_menu_toolbar_admin_menu_output_alter(&$content) {
- // Add a class to top-level items for styling.
- if (isset($content['menu'])) {
- foreach (element_children($content['menu']) as $link) {
- $content['menu'][$link]['#attributes']['class'][] = 'admin-menu-toolbar-category';
- }
- }
-
- // Alter icon.
- if (isset($content['icon'])) {
- unset($content['icon']['icon']['#theme']);
- $content['icon']['icon']['#title'] = '' . t('Home') . ' ';
- $content['icon']['icon']['#attributes']['class'][] = 'admin-menu-toolbar-category';
- }
-
- // Alter user account link.
- if (isset($content['account'])) {
- $content['account']['account']['#title'] = t('Hello @username ', array('@username' => $content['account']['account']['#title']));
- $content['account']['account']['#options']['html'] = TRUE;
- }
-}
-
diff --git a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/toolbar.png b/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/toolbar.png
deleted file mode 100644
index f2c7f355..00000000
Binary files a/sites/all/modules/contrib/admin_menu/admin_menu_toolbar/toolbar.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/arrow-rtl.png b/sites/all/modules/contrib/admin_menu/images/arrow-rtl.png
deleted file mode 100644
index dccaad7f..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/arrow-rtl.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/arrow.png b/sites/all/modules/contrib/admin_menu/images/arrow.png
deleted file mode 100644
index 3c3166ff..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/arrow.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/bkg-red.png b/sites/all/modules/contrib/admin_menu/images/bkg-red.png
deleted file mode 100644
index 80647b0e..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/bkg-red.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/bkg.png b/sites/all/modules/contrib/admin_menu/images/bkg.png
deleted file mode 100644
index 9de137bf..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/bkg.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/bkg_tab.png b/sites/all/modules/contrib/admin_menu/images/bkg_tab.png
deleted file mode 100644
index 6ee3de0b..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/bkg_tab.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/images/icon_users.png b/sites/all/modules/contrib/admin_menu/images/icon_users.png
deleted file mode 100644
index 0923fda0..00000000
Binary files a/sites/all/modules/contrib/admin_menu/images/icon_users.png and /dev/null differ
diff --git a/sites/all/modules/contrib/admin_menu/tests/admin_menu.test b/sites/all/modules/contrib/admin_menu/tests/admin_menu.test
deleted file mode 100644
index 4b48c9ab..00000000
--- a/sites/all/modules/contrib/admin_menu/tests/admin_menu.test
+++ /dev/null
@@ -1,520 +0,0 @@
- 'access administration pages',
- 'admin_menu' => 'access administration menu',
- );
-
- function setUp() {
- // Enable admin menu module and any other modules.
- $modules = func_get_args();
- $modules = isset($modules[0]) ? $modules[0] : $modules;
- $modules[] = 'admin_menu';
- parent::setUp($modules);
-
- // Disable client-side caching.
- variable_set('admin_menu_cache_client', FALSE);
- // Disable Clean URLs to ensure drupal.org testbot compatibility.
- variable_set('clean_url', 0);
- }
-
- /**
- * Check that an element exists in HTML markup.
- *
- * @param $xpath
- * An XPath expression.
- * @param array $arguments
- * (optional) An associative array of XPath replacement tokens to pass to
- * DrupalWebTestCase::buildXPathQuery().
- * @param $message
- * The message to display along with the assertion.
- * @param $group
- * The type of assertion - examples are "Browser", "PHP".
- *
- * @return
- * TRUE if the assertion succeeded, FALSE otherwise.
- */
- protected function assertElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
- $elements = $this->xpath($xpath, $arguments);
- return $this->assertTrue(!empty($elements[0]), $message, $group);
- }
-
- /**
- * Check that an element does not exist in HTML markup.
- *
- * @param $xpath
- * An XPath expression.
- * @param array $arguments
- * (optional) An associative array of XPath replacement tokens to pass to
- * DrupalWebTestCase::buildXPathQuery().
- * @param $message
- * The message to display along with the assertion.
- * @param $group
- * The type of assertion - examples are "Browser", "PHP".
- *
- * @return
- * TRUE if the assertion succeeded, FALSE otherwise.
- */
- protected function assertNoElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
- $elements = $this->xpath($xpath, $arguments);
- return $this->assertTrue(empty($elements), $message, $group);
- }
-
- /**
- * Asserts that links appear in the menu in a specified trail.
- *
- * @param array $trail
- * A list of menu link titles to assert in the menu.
- */
- protected function assertLinkTrailByTitle(array $trail) {
- $xpath = array();
- $args = array();
- $message = '';
- foreach ($trail as $i => $title) {
- $xpath[] = '/li/a[text()=:title' . $i . ']';
- $args[':title' . $i] = $title;
- $message .= ($i ? ' » ' : '') . check_plain($title);
- }
- $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
- $this->assertElementByXPath($xpath, $args, $message . ' link found.');
- }
-
- /**
- * Asserts that no link appears in the menu for a specified trail.
- *
- * @param array $trail
- * A list of menu link titles to assert in the menu.
- */
- protected function assertNoLinkTrailByTitle(array $trail) {
- $xpath = array();
- $args = array();
- $message = '';
- foreach ($trail as $i => $title) {
- $xpath[] = '/li/a[text()=:title' . $i . ']';
- $args[':title' . $i] = $title;
- $message .= ($i ? ' » ' : '') . check_plain($title);
- }
- $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
- $this->assertNoElementByXPath($xpath, $args, $message . ' link not found.');
- }
-}
-
-/**
- * Tests menu links depending on user permissions.
- */
-class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Menu link access permissions',
- 'description' => 'Tests appearance of menu links depending on user permissions.',
- 'group' => 'Administration menu',
- );
- }
-
- function setUp() {
- parent::setUp(array('node'));
- }
-
- /**
- * Test that the links are added to the page (no JS testing).
- */
- function testPermissions() {
- module_enable(array('contact'));
- $this->resetAll();
-
- // Anonymous users should not see the menu.
- $this->drupalGet('');
- $this->assertNoElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu not found.'));
-
- // Create a user who
- // - can access content overview
- // - cannot access drupal.org links
- // - cannot administer Contact module
- $permissions = $this->basePermissions + array(
- 'access content overview',
- );
- $admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($admin_user);
-
- // Check that the user can see the admin links, but not the drupal links.
- $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link found.');
- $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link not found.');
- $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link not found.');
-
- // Create a user "reversed" to the above; i.e., who
- // - cannot access content overview
- // - can access drupal.org links
- // - can administer Contact module
- $permissions = $this->basePermissions + array(
- 'display drupal links',
- 'administer contact forms',
- );
- $admin_user2 = $this->drupalCreateUser($permissions);
- $this->drupalLogin($admin_user2);
- $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
- $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link not found.');
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link found.');
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link found.');
- }
-
- /**
- * Tests handling of links pointing to category/overview pages.
- */
- function testCategories() {
- // Create a user with minimum permissions.
- $admin_user = $this->drupalCreateUser($this->basePermissions);
- $this->drupalLogin($admin_user);
-
- // Verify that no category links appear.
- $this->assertNoLinkTrailByTitle(array(t('Structure')));
- $this->assertNoLinkTrailByTitle(array(t('Configuration')));
-
- // Create a user with access to one configuration category.
- $permissions = $this->basePermissions + array(
- 'administer users',
- );
- $admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($admin_user);
-
- // Verify that only expected category links appear.
- $this->assertNoLinkTrailByTitle(array(t('Structure')));
- $this->assertLinkTrailByTitle(array(t('People')));
- $this->assertLinkTrailByTitle(array(t('Configuration')));
- $this->assertLinkTrailByTitle(array(t('Configuration'), t('People')));
- // Random picks are sufficient.
- $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('Media')));
- $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('System')));
- }
-
- /**
- * Tests that user role and permission changes are properly taken up.
- */
- function testPermissionChanges() {
- // Create a user who is able to change permissions.
- $permissions = $this->basePermissions + array(
- 'administer permissions',
- );
- $admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($admin_user);
-
- // Extract the user role ID that was created for above permissions.
- $rid = key(array_diff_key($admin_user->roles, array(DRUPAL_AUTHENTICATED_RID => 0)));
-
- // Verify that Configuration does not appear.
- $this->assertNoLinkTrailByTitle(array(t('Configuration')));
- // Grant the 'administer site configuration' permission to ourselves.
- $edit = array(
- $rid . '[administer site configuration]' => TRUE,
- );
- $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
- // Verify that Configuration appears.
- $this->assertLinkTrailByTitle(array(t('Configuration')));
-
- // Verify that Structure » Content types does not appear.
- $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
- // Create a new role.
- $edit = array(
- 'name' => 'test',
- );
- $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
- // It should be safe to assume that the new role gets the next ID.
- $test_rid = $rid + 1;
- // Grant the 'administer content types' permission for the role.
- $edit = array(
- $test_rid . '[administer content types]' => TRUE,
- );
- $this->drupalPost('admin/people/permissions/' . $test_rid, $edit, t('Save permissions'));
- // Verify that Structure » Content types does not appear.
- $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
-
- // Assign the role to ourselves.
- $edit = array(
- 'roles[' . $test_rid . ']' => TRUE,
- );
- $this->drupalPost('user/' . $admin_user->uid . '/edit', $edit, t('Save'));
- // Verify that Structure » Content types appears.
- $this->assertLinkTrailByTitle(array(t('Structure'), t('Content types')));
-
- // Delete the role.
- $this->drupalPost('admin/people/permissions/roles/edit/' . $test_rid, array(), t('Delete role'));
- $this->drupalPost(NULL, array(), t('Delete'));
- // Verify that Structure » Content types does not appear.
- $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
- }
-}
-
-/**
- * Tests appearance, localization, and escaping of dynamic links.
- */
-class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Dynamic links',
- 'description' => 'Tests appearance, localization, and escaping of dynamic links.',
- 'group' => 'Administration menu',
- );
- }
-
- function setUp() {
- parent::setUp(array('node'));
- }
-
- /**
- * Tests node type links.
- */
- function testNode() {
- $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
- // Create a content-type with special characters.
- $type = $this->drupalCreateContentType(array('type' => 'special', 'name' => 'Cool & Special'));
-
- $permissions = $this->basePermissions + array(
- 'administer content types',
- 'create article content',
- 'create special content',
- );
- $this->admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($this->admin_user);
-
- // Verify that dynamic links are displayed.
- $this->drupalGet('');
- $this->assertElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu found.'));
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/types'), "Structure » Content types link found.");
-
- // Verify link title output escaping.
- $this->assertNoRaw('Cool & Special');
- $this->assertRaw(check_plain('Cool & Special'));
-
- // Verify Manage content type links.
- $links = array(
- 'admin/structure/types/manage/article' => 'Article',
- 'admin/structure/types/manage/special' => 'Cool & Special',
- );
- foreach ($links as $path => $title) {
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
- ':path' => $path,
- ':title' => $title,
- ), "Structure » Content types » $title link found.");
- }
-
- // Verify Add content links.
- $links = array(
- 'node/add/article' => 'Article',
- 'node/add/special' => 'Cool & Special',
- );
- foreach ($links as $path => $title) {
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
- ':path' => $path,
- ':title' => $title,
- ), "Add content » $title link found.");
- }
- }
-
- /**
- * Tests Add content links.
- */
- function testNodeAdd() {
- $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
-
- // Verify that "Add content" does not appear for unprivileged users.
- $permissions = $this->basePermissions + array(
- 'access content',
- );
- $this->web_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($this->web_user);
- $this->assertNoText(t('Add content'));
-
- // Verify "Add content" appears below "Content" for administrative users.
- $permissions = $this->basePermissions + array(
- 'access content overview',
- 'access content',
- 'create article content',
- );
- $this->admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($this->admin_user);
- $this->assertLinkTrailByTitle(array(
- t('Content'),
- t('Add content'),
- ));
-
- // Verify "Add content" appears on the top-level for regular users.
- $permissions = $this->basePermissions + array(
- 'access content',
- 'create article content',
- );
- $this->web_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($this->web_user);
- $this->assertLinkTrailByTitle(array(
- t('Add content'),
- ));
- }
-}
-
-/**
- * Tests appearance of different types of links.
- */
-class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Link types',
- 'description' => 'Tests appearance of different types of links.',
- 'group' => 'Administration menu',
- );
- }
-
- function setUp() {
- parent::setUp(array('help'));
-
- $permissions = module_invoke_all('permission');
- $permissions = array_keys($permissions);
- $this->admin_user = $this->drupalCreateUser($permissions);
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Tests appearance of different router item link types.
- */
- function testLinkTypes() {
- // Verify that MENU_NORMAL_ITEMs appear.
- $this->assertLinkTrailByTitle(array(
- t('Configuration'),
- t('System'),
- t('Site information'),
- ));
-
- // Verify that MENU_LOCAL_TASKs appear.
- $this->assertLinkTrailByTitle(array(t('People'), t('Permissions')));
- $this->assertLinkTrailByTitle(array(t('Appearance'), t('Settings')));
- $this->assertLinkTrailByTitle(array(t('Modules'), t('Uninstall')));
-
- // Verify that MENU_LOCAL_ACTIONs appear.
- $this->assertLinkTrailByTitle(array(
- t('People'),
- t('Add user'),
- ));
-
- // Verify that MENU_DEFAULT_LOCAL_TASKs do NOT appear.
- $this->assertNoLinkTrailByTitle(array(t('Modules'), t('List')));
- $this->assertNoLinkTrailByTitle(array(t('People'), t('List')));
- $this->assertNoLinkTrailByTitle(array(t('People'), t('Permissions'), t('Permissions')));
- $this->assertNoLinkTrailByTitle(array(t('Appearance'), t('List')));
-
- // Verify that MENU_VISIBLE_IN_BREADCRUMB items (exact type) do NOT appear.
- $this->assertNoLinkTrailByTitle(array(t('Modules'), t('Uninstall'), t('Uninstall')));
- $this->assertNoLinkTrailByTitle(array(t('Help'), 'admin_menu'));
-
- // Verify that special "Index" link appears below icon.
- $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
- ':path' => 'admin/index',
- ':title' => t('Index'),
- ), "Icon » Index link found.");
- }
-}
-
-/**
- * Tests customized menu links.
- */
-class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Customized links',
- 'description' => 'Tests customized menu links.',
- 'group' => 'Administration menu',
- );
- }
-
- function setUp() {
- parent::setUp(array('menu'));
-
- $this->admin_user = $this->drupalCreateUser($this->basePermissions + array(
- 'administer menu',
- ));
- $this->drupalLogin($this->admin_user);
- }
-
- /**
- * Test disabled custom links.
- */
- function testCustomDisabled() {
- $type = $this->drupalCreateContentType();
- $node = $this->drupalCreateNode(array('type' => $type->type));
- $text = $this->randomName();
- $xpath = $this->buildXPathQuery('//div[@id=:id]//a[contains(text(), :text)]', array(
- ':id' => 'admin-menu',
- ':text' => $text,
- ));
-
- // Verify that the link does not appear in the menu.
- $this->drupalGet('node');
- $elements = $this->xpath($xpath);
- $this->assertFalse($elements, 'Custom link not found.');
-
- // Add a custom link to the node to the menu.
- $edit = array(
- 'link_path' => 'node/' . $node->nid,
- 'link_title' => $text,
- 'parent' => 'management:' . $this->queryMlidByPath('admin'),
- );
- $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
-
- // Verify that the link appears in the menu.
- $this->drupalGet('node');
- $elements = $this->xpath($xpath);
- $this->assertTrue($elements, 'Custom link found.');
-
- // Disable the link.
- $edit = array(
- 'enabled' => FALSE,
- );
- $this->drupalPost('admin/structure/menu/item/' . $this->queryMlidByPath('node/' . $node->nid) . '/edit', $edit, t('Save'));
-
- // Verify that the disabled link does not appear in the menu.
- $this->drupalGet('node');
- $elements = $this->xpath($xpath);
- $this->assertFalse($elements, 'Disabled custom link not found.');
- }
-
- /**
- * Tests external links.
- */
- function testCustomExternal() {
- // Add a custom link to the node to the menu.
- $edit = array(
- 'link_path' => 'http://example.com',
- 'link_title' => 'Example',
- 'parent' => 'management:' . $this->queryMlidByPath('admin'),
- );
- $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
-
- // Verify that the link appears in the menu.
- $this->drupalGet('');
- $elements = $this->xpath('//div[@id=:id]//a[@href=:href and contains(text(), :text)]', array(
- ':id' => 'admin-menu',
- ':href' => $edit['link_path'],
- ':text' => $edit['link_title'],
- ));
- $this->assertTrue($elements, 'External link found.');
- }
-
- /**
- * Returns the menu link ID for a given link path in the management menu.
- */
- protected function queryMlidByPath($path) {
- return db_query('SELECT mlid FROM {menu_links} WHERE menu_name = :menu AND link_path = :path', array(
- ':menu' => 'management',
- ':path' => $path,
- ))->fetchField();
- }
-}
-
diff --git a/sites/all/modules/contrib/auto_nodetitle/LICENSE.txt b/sites/all/modules/contrib/auto_nodetitle/LICENSE.txt
deleted file mode 100644
index 2c095c8d..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/LICENSE.txt
+++ /dev/null
@@ -1,274 +0,0 @@
-GNU GENERAL PUBLIC LICENSE
-
- Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
- Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
- MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
diff --git a/sites/all/modules/contrib/auto_nodetitle/README.txt b/sites/all/modules/contrib/auto_nodetitle/README.txt
deleted file mode 100755
index 1c6a2093..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/README.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-
-Automatic Nodetitle Module
-------------------------
-by Wolfgang Ziegler, nuppla@zites.net
-
-
-Description
------------
-This is a small and efficent module that allows hiding of the content title field in the form.
-To prevent empty content title fields it sets the title to the content type name or to an
-configurable string. It is possible to use various content data for the autogenerated title,
-e.g. the token [current-user:name] is going to be replaced with the currently logged in
-users name. If the token module is installed, a list of possible replacement patterns
-will be shown.
-
-Advanced users can also provide some PHP code, that is used for automatically generating an
-appropriate title.
-
-Installation
-------------
- * (optional) Download and install the token module in order to get token
- replacement help.
- * Copy the module's directory to your modules directory and activate the module.
- * For each content type you want to have an automatic title, configure the
- module at 'admin/structure/types'.
-
-
-Note
------
- Due to the way the module works, it is not possible to make use of some replacement
- tokens that are not available before the content node is saved the first time, e.g.
- like the node id ([node:nid]).
-
-
-
- Advanced Use: PHP Code
-------------------------
- You can access $node from your php code. Look at this simple example, which just adds the node's
- author as title:
-
-name"; ?>
-
-
-
- Advanced Use: Combining tokens and PHP
- ---------------------------------------
-
- You can combine php evalution with the token module, because tokens are replaced first.
- However be aware to don't use this with any textual values provided by users as this would
- open a security hole. If you are in doubt, don't combine tokens with php evaluation.
-
- Here is an example:
-
-
-
- So if the text of the number field [field_testnumber] isn't empty it will be used as title.
- Otherwise the node type will be used.
-
-
- Updating nodetitles from existing nodes
- ---------------------------------------
- If you set the nodetitle to be auto generated for some content type, existing nodes
- are not affected. You can update existing nodes by going to 'admin/content',
- then filter for your content type, mark some nodes and choose the "Update option"
- "Update automatic nodetitles".
-
-
\ No newline at end of file
diff --git a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.info b/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.info
deleted file mode 100644
index aff81dea..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.info
+++ /dev/null
@@ -1,13 +0,0 @@
-; $Id.
-name = Automatic Nodetitles
-description = Allows hiding of the content title field and automatic title creation.
-core = 7.x
-files[] = auto_nodetitle.install
-files[] = auto_nodetitle.module
-files[] = auto_nodetitle.js
-; Information added by drupal.org packaging script on 2011-06-07
-version = "7.x-1.0"
-core = "7.x"
-project = "auto_nodetitle"
-datestamp = "1307449915"
-
diff --git a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.install b/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.install
deleted file mode 100755
index 8d24a313..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.install
+++ /dev/null
@@ -1,33 +0,0 @@
- $type_name) {
- variable_del('ant_' . $type);
- variable_del('ant_pattern_' . $type);
- variable_del('ant_php_' . $type);
- }
-}
-
-/**
- * make sure hooks are invoked after cck main hooks
- */
-function auto_nodetitle_update_1() {
- $ret = array();
- $ret[] = update_sql("UPDATE {system} SET weight = 5 WHERE name = 'auto_nodetitle'");
- return $ret;
-}
\ No newline at end of file
diff --git a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.js b/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.js
deleted file mode 100644
index a24bb584..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.js
+++ /dev/null
@@ -1,23 +0,0 @@
-(function ($) {
-
-Drupal.behaviors.auto_nodetitleFieldsetSummaries = {
- attach: function (context) {
- $('fieldset#edit-auto-nodetitle', context).drupalSetSummary(function (context) {
-
- // Retrieve the value of the selected radio button
- var ant = $("input[@name=#edit-auto-nodetitle-ant]:checked").val();
-
- if (ant==0) {
- return Drupal.t('Disabled')
- }
- else if (ant==1) {
- return Drupal.t('Automatic (hide title field)')
- }
- else if (ant==2) {
- return Drupal.t('Automatic (if title empty)')
- }
- });
- }
-};
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.module b/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.module
deleted file mode 100644
index dc0d4042..00000000
--- a/sites/all/modules/contrib/auto_nodetitle/auto_nodetitle.module
+++ /dev/null
@@ -1,238 +0,0 @@
- array(
- 'title' => t('Use PHP for title patterns'),
- 'description' => t('Use PHP for title patterns.'),
- 'restrict access' => TRUE,
- ),
- );
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for the node form.
- */
-function auto_nodetitle_form_node_form_alter(&$form, &$form_state, $form_id) {
- if (auto_nodetitle_get_setting($form['#node']->type) == AUTO_NODETITLE_ENABLED) {
- // We will autogenerate the title later, just hide the title field in the
- // meanwhile.
- $form['title']['#value'] = 'ant';
- $form['title']['#type'] = 'value';
- $form['title']['#required'] = FALSE;
- }
- elseif (auto_nodetitle_get_setting($form['#node']->type) == AUTO_NODETITLE_OPTIONAL) {
- $form['title']['#required'] = FALSE;
- }
-}
-
-/**
- * Implements hook_node_submit().
- *
- * Generate the node title as soon as the form has been submitted. That way
- * the node preview is shown right too.
- */
-function auto_nodetitle_node_submit($node, $form, &$form_state) {
- $setting = auto_nodetitle_get_setting($node->type);
- if ($setting == AUTO_NODETITLE_ENABLED || ($setting == AUTO_NODETITLE_OPTIONAL && empty($form_state['values']['title']))) {
- auto_nodetitle_set_title($node);
- }
-}
-
-/**
- * Implements hook_node_presave().
- */
-function auto_nodetitle_node_presave($node) {
- // If not yet done, generate the title now.
- if (auto_nodetitle_is_needed($node)) {
- auto_nodetitle_set_title($node);
- }
-}
-
-/**
- * Returns whether the auto nodetitle has to be set.
- */
-function auto_nodetitle_is_needed($node) {
- return empty($node->auto_nodetitle_applied) && ($setting = auto_nodetitle_get_setting($node->type)) && !($setting == AUTO_NODETITLE_OPTIONAL && !empty($node->title));
-}
-
-/**
- * Sets the automatically generated nodetitle for the node
- */
-function auto_nodetitle_set_title(&$node) {
- $types = node_type_get_types();
- $pattern = variable_get('ant_pattern_' . $node->type, '');
- if (trim($pattern)) {
- $node->changed = REQUEST_TIME;
- $node->title = _auto_nodetitle_patternprocessor($pattern, $node);
- }
- elseif ($node->nid) {
- $node->title = t('@type @node-id', array('@type' => $types[$node->type]->name, '@node-id' => $node->nid));
- }
- else {
- $node->title = t('@type', array('@type' => $types[$node->type]->name));
- }
- // Ensure the generated title isn't too long.
- $node->title = substr($node->title, 0, 255);
- // With that flag we ensure we don't apply the title two times to the same
- // node. See auto_nodetitle_is_needed().
- $node->auto_nodetitle_applied = TRUE;
-}
-
-/**
- * Implements hook_node_operations().
- */
-function auto_nodetitle_node_operations() {
- $operations = array(
- 'nodetitle_update' => array(
- 'label' => t('Update automatic nodetitles'),
- 'callback' => 'auto_nodetitle_operations_update',
- ),
- );
- return $operations;
-}
-
-/**
- * Callback function for updating node titles.
- */
-function auto_nodetitle_operations_update($nodes) {
- foreach ($nodes as $nid) {
- $node = node_load($nid);
- if ($node && auto_nodetitle_is_needed($node)) {
- $previous_title = $node->title;
- auto_nodetitle_set_title($node);
- // Only save if the title has actually changed.
- if ($node->title != $previous_title) {
- node_save($node);
- }
- }
- }
-}
-
-/**
- * Helper function to generate the title according to the settings.
- *
- * @return a title string
- */
-function _auto_nodetitle_patternprocessor($pattern, $node) {
- // Replace tokens.
- $output = token_replace($pattern, array('node' => $node), array('sanitize' => FALSE));
- // Evalute PHP.
- if (variable_get('ant_php_' . $node->type, 0)) {
- $output = auto_nodetitle_eval($output, $node);
- }
- // Strip tags.
- $output = preg_replace('/[\t\n\r\0\x0B]/', '', strip_tags($output));
- return $output;
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for the node type form.
- */
-function auto_nodetitle_form_node_type_form_alter(&$form, &$form_state) {
- $default_value = auto_nodetitle_get_setting($form['#node_type']->type);
- $form['auto_nodetitle'] = array(
- '#type' => 'fieldset',
- '#title' => t('Automatic title generation'),
- '#weight' => 0,
- '#collapsible' => TRUE,
- '#collapsed' => !$default_value,
- '#group' => 'additional_settings',
- '#attached' => array(
- 'js' => array(
- 'auto-nodetitle' => drupal_get_path('module', 'auto_nodetitle') . '/auto_nodetitle.js',
- ),
- ),
- );
- $form['auto_nodetitle']['ant'] = array(
- '#type' => 'radios',
- '#default_value' => $default_value,
- '#options' => array(
- t('Disabled'),
- t('Automatically generate the title and hide the title field'),
- t('Automatically generate the title if the title field is left empty'),
- )
- );
- $form['auto_nodetitle']['ant_pattern'] = array(
- '#type' => 'textarea',
- '#title' => t('Pattern for the title'),
- '#description' => t('Leave blank for using the per default generated title. Otherwise this string will be used as title. Use the syntax [token] if you want to insert a replacement pattern.'),
- '#default_value' => variable_get('ant_pattern_' . $form['#node_type']->type, ''),
- );
- // Don't allow editing of the pattern if PHP is used, but the users lacks
- // permission for PHP.
- if (variable_get('ant_php_' . $form['#node_type']->type, '') && !user_access('use PHP for title patterns')) {
- $form['auto_nodetitle']['ant_pattern']['#disabled'] = TRUE;
- $form['auto_nodetitle']['ant_pattern']['#description'] = t('You are not allow the configure the pattern for the title, as you lack the %permission permission.', array('%permission' => t('Use PHP for title patterns')));
- }
-
- // Display the list of available placeholders if token module is installed.
- if (module_exists('token')) {
- $form['auto_nodetitle']['token_help'] = array(
- '#theme' => 'token_tree',
- '#token_types' => array('node'),
- );
- }
-
-
- $form['auto_nodetitle']['ant_php'] = array(
- '#access' => user_access('use PHP for title patterns'),
- '#type' => 'checkbox',
- '#title' => t('Evaluate PHP in pattern.'),
- '#description' => t('Put PHP code above that returns your string, but make sure you surround code in <?php and ?>. Note that $node is available and can be used by your code.'),
- '#default_value' => variable_get('ant_php_' . $form['#node_type']->type, ''),
- );
-}
-
-/**
- * Gets the auto node title setting associated with the given content type.
- */
-function auto_nodetitle_get_setting($type) {
- return variable_get('ant_' . $type, AUTO_NODETITLE_DISABLED);
-}
-
-/**
- * Evaluates php code and passes $node to it.
- */
-function auto_nodetitle_eval($code, $node) {
- ob_start();
- print eval('?>' . $code);
- $output = ob_get_contents();
- ob_end_clean();
- return $output;
-}
-
-/**
- * Implements hook_node_type().
- */
-function auto_nodetitle_node_type($op, $info) {
- switch ($op) {
- case 'delete':
- variable_del('ant_' . $info->type);
- variable_del('ant_pattern_' . $info->type);
- variable_del('ant_php_' . $info->type);
- break;
- case 'update':
- if (!empty($info->old_type) && $info->old_type != $info->type) {
- variable_set('ant_' . $info->type, auto_nodetitle_get_setting($info->old_type));
- variable_set('ant_pattern_' . $info->type, variable_get('ant_pattern_' . $info->old_type, ''));
- variable_set('ant_php_' . $info->type, variable_get('ant_php_' . $info->old_type, ''));
- variable_del('ant_' . $info->old_type);
- variable_del('ant_pattern_' . $info->old_type);
- variable_del('ant_php_' . $info->old_type);
- }
- break;
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/LICENSE.txt b/sites/all/modules/contrib/backup_migrate/LICENSE.txt
deleted file mode 100644
index d159169d..00000000
--- a/sites/all/modules/contrib/backup_migrate/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/backup_migrate/README.txt b/sites/all/modules/contrib/backup_migrate/README.txt
deleted file mode 100644
index 7ecc15d7..00000000
--- a/sites/all/modules/contrib/backup_migrate/README.txt
+++ /dev/null
@@ -1,94 +0,0 @@
-
--------------------------------------------------------------------------------
-Backup and Migrate 2 for Drupal 7.x
- by Ronan Dowling, Gorton Studios - ronan (at) gortonstudios (dot) com
--------------------------------------------------------------------------------
-
-DESCRIPTION:
-This module makes the task of backing up your Drupal database and migrating data
-from one Drupal install to another easier. It provides a function to backup the
-entire database to file or download, and to restore from a previous backup. You
-can also schedule the backup operation. Compression of backup files is also
-supported.
-
-There are options to exclude the data from certain tables (such as cache or
-search index tables) to increase efficiency by ignoring data that does not need
-to be backed up or migrated.
-
-The backup files are a list of SQL statements which can be executed with a tool
-such as phpMyAdmin or the command-line mysql client.
-
--------------------------------------------------------------------------------
-
-INSTALLATION:
-* Put the module in your Drupal modules directory and enable it in
- admin/modules.
-* Go to admin/people/permissions and grant permission to any roles that need to be
- able to backup or restore the database.
-* Configure and use the module at admin/config/system/backup_migrate
-
-OPTIONAL:
-* Enable token.module to allow token replacement in backup file names.
-* To Backup to Amazon S3:
- - Download the S3 library from http://undesigned.org.za/2007/10/22/amazon-s3-php-class
- and place the file 'S3.php' in the includes directory in this module.
- The stable version (0.4.0 – 20th Jul 2009) works best with Backup and Migrate.
-
-LIGHTTPD USERS:
-Add the following code to your lighttp.conf to secure your backup directories:
- $HTTP["url"] =~ "^/sites/default/files/backup_migrate/" {
- url.access-deny = ( "" )
- }
-You may need to adjust the path to reflect the actual path to the files.
-
-IIS 7 USERS:
-Add the following code to your web.config code to secure your backup directories:
-
-
-
-
-You may need to adjust the path to reflect the actual path to the files.
-
--------------------------------------------------------------------------------
-
-VERY IMPORTANT SECURITY NOTE:
-Backup files may contain sensitive data and by default, are saved to your web
-server in a directory normally accessible by the public. This could lead to a
-very serious security vulnerability. Backup and Migrate attempts to protect
-backup files using a .htaccess file, but this is not guaranteed to work on all
-environments (and is guaranteed to fail on web servers that are not apache). You
-should test to see if your backup files are publicly accessible, and if in doubt
-do not save backups to the server, or use the destinations feature to save to a
-folder outside of your webroot.
-
-OTHER WARNINGS:
-A failed restore can destroy your database and therefore your entire Drupal
-installation. ALWAYS TEST BACKUP FILES ON A TEST ENVIRONMENT FIRST. If in doubt
-do not use this module.
-
-This module has only been tested with MySQL and does not work with any other dbms.
-If you have experiences with Postgres or any other dbms and are willing to help
-test and modify the module to work with it, please contact the developer at
-ronan (at) gortonstudios (dot) com.
-
-Make sure your php timeout is set high enough to complete a backup or restore
-operation. Larger databases require more time. Also, while the module attempts
-to keep memory needs to a minimum, a backup or restore will require
-significantly more memory then most Drupal operations.
-
-If your backup file contains the 'sessions' table all other users will be logged
-out after you run a restore. To avoid this, exclude the sessions table when
-creating your backups. Be aware though that you will need to recreate the
-sessions table if you use this backup on an empty database.
-
-Do not change the file extension of backup files or the restore function will be
-unable to determine the compression type the file and will not function
-correctly.
-
-IF A RESTORE FAILS:
-Don't panic, the restore file should work with phpMyAdmin's import function, or
-with the mysql command line tool. If it does not, then it is likely corrupt; you
-may panic now. MAKE SURE THAT THIS MODULE IS NOT YOUR ONLY FORM OF BACKUP.
-
--------------------------------------------------------------------------------
-
diff --git a/sites/all/modules/contrib/backup_migrate/backup_migrate.css b/sites/all/modules/contrib/backup_migrate/backup_migrate.css
deleted file mode 100644
index 936a3746..00000000
--- a/sites/all/modules/contrib/backup_migrate/backup_migrate.css
+++ /dev/null
@@ -1,42 +0,0 @@
-.schedule-list-disabled {
- filter:alpha(opacity=50);
- -moz-opacity: .50;
- opacity: .50;
-}
-
-.backup-migrate-cache-time {
- font-size: 0.85em;
-}
-
-.backup-migrate-tables-checkboxes .form-item {
- margin: 0;
-}
-.backup-migrate-tables-checkboxes .form-item label {
- width: 15em;
- float: left;
- overflow: hidden;
- white-space: nowrap;
- height: 1.75em;
- margin: .25em .25em 0 0;
-}
-.backup-migrate-tables-checkboxes .form-item label.checked {
- background-color: #eee;
-}
-.backup-migrate-tables-checkboxes .form-item label input {
- margin-right: .25em;
-}
-
-div.backup-migrate-tables-checkboxes {
- max-height: 40em;
- overflow: auto;
-}
-div.backup-migrate-description {
- font-size: smaller;
-}
-
-
-div.row-error {
- color: #FF0000;
- font-weight: bold;
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/backup_migrate.info b/sites/all/modules/contrib/backup_migrate/backup_migrate.info
deleted file mode 100644
index 30d42d20..00000000
--- a/sites/all/modules/contrib/backup_migrate/backup_migrate.info
+++ /dev/null
@@ -1,17 +0,0 @@
-name = Backup and Migrate
-description = "Backup or migrate the Drupal Database quickly and without unnecessary data."
-core = 7.x
-
-files[] = backup_migrate.module
-files[] = backup_migrate.install
-files[] = includes/destinations.inc
-files[] = includes/profiles.inc
-files[] = includes/schedules.inc
-
-configure = admin/config/system/backup_migrate
-; Information added by drupal.org packaging script on 2013-05-16
-version = "7.x-2.7"
-core = "7.x"
-project = "backup_migrate"
-datestamp = "1368729920"
-
diff --git a/sites/all/modules/contrib/backup_migrate/backup_migrate.install b/sites/all/modules/contrib/backup_migrate/backup_migrate.install
deleted file mode 100644
index ad04a214..00000000
--- a/sites/all/modules/contrib/backup_migrate/backup_migrate.install
+++ /dev/null
@@ -1,423 +0,0 @@
- array(
- 'profile_id' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The primary identifier for a profile.',
- ),
- 'name' => array(
- 'description' => 'The name of the profile.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE
- ),
- 'filename' => array(
- 'description' => 'The name of the profile.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE
- ),
- 'append_timestamp' => array(
- 'description' => 'Append a timestamp to the filename.',
- 'type' => 'int',
- 'size' => 'tiny',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0
- ),
- 'timestamp_format' => array(
- 'description' => 'The format of the timestamp.',
- 'type' => 'varchar',
- 'length' => 14,
- 'not null' => TRUE
- ),
- 'filters' => array(
- 'description' => 'The filter settings for the profile.',
- 'type' => 'text',
- 'not null' => TRUE,
- 'serialize' => TRUE,
- 'serialized default' => 'a:0:{}',
- ),
- ),
- 'primary key' => array('profile_id'),
- );
- $schema['backup_migrate_destinations'] = array(
- 'fields' => array(
- 'destination_id' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The primary identifier for a profile.',
- ),
- 'name' => array(
- 'description' => 'The name of the profile.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE
- ),
- 'type' => array(
- 'description' => 'The type of the destination.',
- 'type' => 'varchar',
- 'length' => 32,
- 'not null' => TRUE
- ),
- 'location' => array(
- 'description' => 'The the location string of the destination.',
- 'type' => 'text',
- 'not null' => TRUE
- ),
- 'settings' => array(
- 'description' => 'Other settings for the destination.',
- 'type' => 'text',
- 'not null' => TRUE,
- 'serialize' => TRUE,
- 'serialized default' => 'a:0:{}',
- ),
- ),
- 'primary key' => array('destination_id'),
- );
- $schema['backup_migrate_schedules'] = array(
- 'fields' => array(
- 'schedule_id' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The primary identifier for a profile.',
- ),
- 'name' => array(
- 'description' => 'The name of the profile.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE
- ),
- 'source_id' => array(
- 'description' => 'The {backup_migrate_destination}.destination_id of the source to backup from.',
- 'type' => 'varchar',
- 'length' => 255,
- 'default' => 'db',
- 'not null' => TRUE
- ),
- 'destination_id' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The {backup_migrate_destination}.destination_id of the destination to back up to.',
- ),
- 'profile_id' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The primary identifier for a profile.',
- ),
- 'keep' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The number of backups to keep.',
- ),
- 'period' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- 'description' => 'The number of seconds between backups.',
- ),
- 'enabled' => array(
- 'description' => 'Whether the schedule is enabled.',
- 'type' => 'int',
- 'size' => 'tiny',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0
- ),
- 'cron' => array(
- 'description' => 'Whether the schedule should be run during cron.',
- 'type' => 'int',
- 'size' => 'tiny',
- 'unsigned' => TRUE,
- 'not null' => TRUE,
- 'default' => 0
- ),
- ),
- 'primary key' => array('schedule_id'),
- );
-
- return $schema;
-}
-
-/**
- * Implementation of hook_install().
- */
-function backup_migrate_install() {
- _backup_migrate_setup_database_defaults();
-}
-
-function _backup_migrate_setup_database_defaults() {
- if (variable_get("backup_migrate_file_name", NULL)) {
- require_once DRUPAL_ROOT . '/'. drupal_get_path('module', 'backup_migrate') .'/includes/crud.inc';
- require_once DRUPAL_ROOT . '/'. drupal_get_path('module', 'backup_migrate') .'/backup_migrate.module';
- require_once DRUPAL_ROOT . '/'. drupal_get_path('module', 'backup_migrate') .'/includes/profiles.inc';
- require_once DRUPAL_ROOT . '/'. drupal_get_path('module', 'backup_migrate') .'/includes/files.inc';
-
- $settings = array(
- 'profile_id' => 'default',
- 'filename' => variable_get("backup_migrate_file_name", _backup_migrate_default_filename()),
- 'append_timestamp' => variable_get("backup_migrate_append_timestamp", FALSE) ? 1 : 0,
- 'timestamp_format' => variable_get("backup_migrate_timestamp_format", 'Y-m-d\TH-i-s'),
- 'filters' => array(
- 'compression' => variable_get("backup_migrate_compression", "none"),
- 'exclude_tables' => variable_get("backup_migrate_exclude_tables", array()),
- 'nodata_tables' => variable_get("backup_migrate_nodata_tables", array()),
- ),
- 'name' => t('Default Settings'),
- );
- $profile = backup_migrate_crud_create_item('profile', $settings);
- $profile->save();
- variable_set("backup_migrate_profile_id", 'default');
-
- // Set up the default schedules.
- if (variable_get("backup_migrate_schedule_backup_period", 0)) {
- require_once DRUPAL_ROOT . '/'. drupal_get_path('module', 'backup_migrate') .'/includes/schedules.inc';
- $schedule = array(
- 'name' => t('Default Schedule'),
- 'profile_id' => $profile->get_id(),
- 'enabled' => 1,
- 'destination_id' => 'scheduled',
- 'period' => array('number' => variable_get("backup_migrate_schedule_backup_period", 0), 'type' => 'hours'),
- 'keep' => variable_get("backup_migrate_schedule_backup_keep", 0),
- );
- $schedule = backup_migrate_crud_create_item('schedule', $schedule);
- $schedule->save();
- }
- }
-}
-
-/**
- * Remove variables on uninstall.
- */
-function backup_migrate_uninstall() {
- db_query("DELETE FROM {variable} WHERE name LIKE 'backup_migrate_%'");
- cache_clear_all('variables', 'cache');
-}
-
-/**
- * Update from 1.x to 2.x.
- */
-function backup_migrate_update_2000() {
- _backup_migrate_setup_database_defaults();
- return array();
-}
-
-/**
- * Adding filter field for dev release of 2009-01-28
- */
-function backup_migrate_update_2001() {
- $ret = array();
- $schema = drupal_get_schema_unprocessed('backup_migrate', 'backup_migrate_profiles');
-
- // Add the filters field to the db.
- if (!db_field_exists('backup_migrate_profiles', 'filters')) {
- db_add_field('backup_migrate_profiles', 'filters', array('description' => t('The filter settings for the profile.'),'type' => 'text', 'not null' => TRUE));
- }
- // Add the source field
- if (!db_field_exists('backup_migrate_profiles', 'source_id')) {
- db_add_field('backup_migrate_profiles', 'source_id', array('description' => t('The {backup_migrate_destination}.destination_id of the source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE));
- }
- // Remove the compression field.
- if (db_field_exists('backup_migrate_profiles', 'compression')) {
- db_drop_field('backup_migrate_profiles', 'compression');
- }
- return $ret;
-}
-
-/**
- * Clearing the cache because there was a menu structure change in the dev of 2009-05-31
- */
-function backup_migrate_update_2002() {
- // Cache should clear automatically. Nothing to do here.
- return array();
-}
-
-/**
- * Allowing non-int profile ids in schedules 2009-05-31
- */
-function backup_migrate_update_2003() {
- $ret = array();
- $spec = array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- 'description' => 'The primary identifier for a profile.',
- );
-
- db_change_field('backup_migrate_schedules', 'profile_id', 'profile_id', $spec);
- return $ret;
-}
-
-/**
- * Allowing non-int profile ids 2009-07-01
- */
-function backup_migrate_update_2004() {
- $ret = array();
- $spec = array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '0',
- );
-
- $spec['description'] = 'The primary identifier for a destination.';
- db_change_field('backup_migrate_destinations', 'destination_id', 'destination_id', $spec);
-
- $spec['description'] = 'The primary identifier for a profile.';
- db_change_field('backup_migrate_profiles', 'profile_id', 'profile_id', $spec);
-
- $spec['description'] = 'The primary identifier for a schedule.';
- db_change_field('backup_migrate_schedules', 'schedule_id', 'schedule_id', $spec);
-
- // Drop the user/pass fields as they weren't being used.
- if (db_field_exists('backup_migrate_destinations', 'username')) {
- db_drop_field('backup_migrate_destinations', 'username');
- }
- if (db_field_exists('backup_migrate_destinations', 'password')) {
- db_drop_field('backup_migrate_destinations', 'password');
- }
-
- return $ret;
-}
-
-/**
- * Change the default database id to something friendlier 2009-08-08
- */
-function backup_migrate_update_2005() {
- require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/crud.inc';
- require_once './'. drupal_get_path('module', 'backup_migrate') .'/includes/profiles.inc';
-
- $ret = array();
- // Change the destination ids of the defined database sources mostly to make using them with drush friendlier.
-
- // Change the db_url:default id to simply 'db'
- $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = 'db' WHERE source_id = 'db_url:default'");
- $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = 'db' WHERE destination_id = 'db_url:default'");
-
- // Change the defined db keys from db_url:key to db:key.
- $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = REPLACE(source_id, 'db_url:', 'db:')");
- $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = REPLACE(destination_id, 'db_url:', 'db:')");
-
- // Add the source field to the schedule
- if (!db_field_exists('backup_migrate_schedules', 'source_id')) {
- db_add_field('backup_migrate_schedules', 'source_id', array('description' => t('The db source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE));
- }
-
- // Copy source data from profiles to schedules.
- $result = db_query('SELECT p.source_id, s.schedule_id FROM {backup_migrate_schedules} s LEFT JOIN {backup_migrate_profiles} p ON s.profile_id = p.profile_id', array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($result as $schedule) {
- if (!$schedule['source_id']) {
- $schedule['source_id'] = 'db';
- }
- $ret[] = db_query("UPDATE {backup_migrate_schedules} SET source_id = '". $schedule['source_id'] ."' WHERE schedule_id = '". $schedule['profile_id'] ."'");
- }
-
- if (db_field_exists('backup_migrate_profiles', 'source_id')) {
- db_drop_field('backup_migrate_profiles', 'source_id');
- }
-
- // Copy the no-data and exclude tables settings into the 'filter' field.
- $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($result as $item) {
- if (isset($item['nodata_tables']) && isset($item['exclude_tables'])) {
- $profile = backup_migrate_get_profile($item['profile_id']);
- $profile->filters['nodata_tables'] = unserialize($item['nodata_tables']);
- $profile->filters['exclude_tables'] = unserialize($item['exclude_tables']);
- $profile->save();
- }
- }
- if (db_field_exists('backup_migrate_profiles', 'nodata_tables')) {
- db_drop_field('backup_migrate_profiles', 'nodata_tables');
- }
- if (db_field_exists('backup_migrate_profiles', 'exclude_tables')) {
- db_drop_field('backup_migrate_profiles', 'exclude_tables');
- }
-
- return $ret;
-}
-
-/**
- * Move the backup and migrate directory to the private directory.
- */
-function backup_migrate_update_7200() {
- $from = 'public://backup_migrate';
- $to = 'private://backup_migrate';
- if (drupal_realpath($from) && !drupal_realpath($to)) {
- if (!rename($from, $to)) {
- drupal_set_message(t('Unable to move the backups directory to your private folder, please check file permissions and move the directory %from to %to', array('%from' => drupal_realpath($from), '%to' => drupal_realpath($to))), 'warning');
- }
- }
-}
-
-
-/**
- * Change the filename field to support 255 characters.
- */
-function backup_migrate_update_7202() {
- $ret = array();
- db_change_field('backup_migrate_profiles', 'filename', 'filename', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
- return $ret;
-}
-
-
-/**
- * Update the schedule last run times to use variables instead of saving with the schedule.
- */
-function backup_migrate_update_7203() {
- $result = db_query('SELECT * FROM {backup_migrate_schedules}', array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($result as $item) {
- if (isset($item['last_run'])) {
- variable_set('backup_migrate_schedule_last_run_' . $item['schedule_id'], $item['last_run']);
- }
- }
- if (db_field_exists('backup_migrate_schedules', 'last_run')) {
- db_drop_field('backup_migrate_schedules', 'last_run');
- }
-}
-
-
-
-/**
- * Disable the NodeSquirrel module if it's installed.
- */
-function backup_migrate_update_7204() {
- $ret = NULL;
- if (module_exists('nodesquirrel')) {
- module_disable(array('nodesquirrel'));
- $ret = t("The NodeSquirrel module was disabled. NodeSquirrel support is now built into Backup and Migrate.");
- }
- return $ret;
-}
diff --git a/sites/all/modules/contrib/backup_migrate/backup_migrate.js b/sites/all/modules/contrib/backup_migrate/backup_migrate.js
deleted file mode 100644
index 46508b80..00000000
--- a/sites/all/modules/contrib/backup_migrate/backup_migrate.js
+++ /dev/null
@@ -1,59 +0,0 @@
-
-(function ($) {
-Drupal.backup_migrate = {
- callbackURL : "",
- autoAttach : function() {
- if (Drupal.settings.backup_migrate !== undefined) {
- if ($("#edit-save-settings").length && !$("#edit-save-settings").attr("checked")) {
- // Disable input and hide its description.
- // Set display none instead of using hide(), because hide() doesn't work when parent is hidden.
- $('div.backup-migrate-save-options').css('display', 'none');
- }
-
- $("#edit-save-settings").bind("click", function() {
- if (!$("#edit-save-settings").attr("checked")) {
- $("div.backup-migrate-save-options").slideUp('slow');
- }
- else {
- // Save unchecked; enable input.
- $("div.backup-migrate-save-options").slideDown('slow');
- }
- });
-
- $('#backup-migrate-ui-manual-backup-form select[multiple], #backup-migrate-crud-edit-form select[multiple]').each(function() {
- $(this).after(
- $('
').append(
- $(' ').text(Drupal.settings.backup_migrate.checkboxLinkText).click(function() {
- Drupal.backup_migrate.selectToCheckboxes($(this).parents('.form-item').find('select'));
- })
- )
- );
- }
- );
- }
- },
-
- selectToCheckboxes : function($select) {
- var field_id = $select.attr('id');
- var $checkboxes = $('
').addClass('backup-migrate-tables-checkboxes');
- $('option', $select).each(function(i) {
- var self = this;
- $box = $(' ').bind('change click', function() {
- $select.find('option[value="'+self.value+'"]').attr('selected', this.checked);
- if (this.checked) {
- $(this).parent().addClass('checked');
- }
- else {
- $(this).parent().removeClass('checked');
- }
- }).attr('checked', this.selected ? 'checked' : '');
- $checkboxes.append($('
').append($(''+this.value+' ').prepend($box)));
- });
- $select.parent().find('.backup-migrate-checkbox-link').remove();
- $select.before($checkboxes);
- $select.hide();
- }
-}
-
-$(document).ready(Drupal.backup_migrate.autoAttach);
-})(jQuery);
diff --git a/sites/all/modules/contrib/backup_migrate/backup_migrate.module b/sites/all/modules/contrib/backup_migrate/backup_migrate.module
deleted file mode 100644
index 7118dc31..00000000
--- a/sites/all/modules/contrib/backup_migrate/backup_migrate.module
+++ /dev/null
@@ -1,1052 +0,0 @@
-
- t('Backup and Migrate makes the task of backing up your Drupal database and migrating data from one Drupal install to another easier. It provides a function to backup the entire database to file or download, and to restore from a previous backup. You can also schedule the backup operation. Compression of backup files is also supported. The database backup files created with this module can be imported into this or any other Drupal installation with the !restorelink, or you can use a database tool such as phpMyAdmin or the mysql command line command.',
- array(
- '!restorelink' => user_access('restore from backup') ? l(t('restore feature'), BACKUP_MIGRATE_MENU_PATH . '/restore') : t('restore feature'),
- '!phpmyadminurl' => 'http://www.phpmyadmin.net'
- )
- )
- ),
- BACKUP_MIGRATE_MENU_PATH => array(
- 'title' => t('Quick Backup Tab'),
- 'body' => t('Use this form to run simple manual backups of your database. Visit the !helppage for more help using this module',
- array('!helppage' => l(t('help page'), 'admin/help/backup_migrate'))),
- 'access arguments' => array('perform backup'),
- ),
- BACKUP_MIGRATE_MENU_PATH . '/export/advanced' => array(
- 'title' => t('Advanced Backup Tab'),
- 'body' => t('Use this form to run manual backups of your database with more advanced options. If you have any !profilelink saved you can load those settings. You can save any of the changes you make to these settings as a new settings profile.',
- array("!profilelink" => user_access('administer backup and migrate') ? l(t('settings profiles'), BACKUP_MIGRATE_MENU_PATH . '/profile') : t('settings profiles'), '!restorelink' => user_access('restore from backup') ? l(t('restore feature'), BACKUP_MIGRATE_MENU_PATH . '/restore') : t('restore feature'), '!phpmyadminurl' => 'http://www.phpmyadmin.net')),
- 'access arguments' => array('perform backup'),
- ),
- BACKUP_MIGRATE_MENU_PATH . '/restore' => array(
- 'title' => t('Restore Tab'),
- 'body' => t('Upload a backup and migrate backup file. The restore function will not work with database dumps from other sources such as phpMyAdmin.'),
- 'access arguments' => array('restore from backup'),
- ),
- BACKUP_MIGRATE_MENU_PATH . '/destination' => array(
- 'title' => t('Destinations'),
- 'body' => t('Destinations are the places you can save your backup files to or them load from.'),
- 'more' => t('Files can be saved to a directory on your web server, downloaded to your desktop or emailed to a specified email account. From the Destinations tab you can create, delete and edit destinations or list the files which have already been backed up to the available destinations.'),
- 'access arguments' => array('administer backup and migrate'),
- ),
- BACKUP_MIGRATE_MENU_PATH . '/profile' => array(
- 'title' => t('Profiles'),
- 'body' => t('Profiles are saved backup settings. Profiles store your table exclusion settings as well as your backup file name, compression and timestamp settings. You can use profiles in !schedulelink and for !manuallink.',
- array('!schedulelink' => user_access('administer backup and migrate') ? l(t('schedules'), BACKUP_MIGRATE_MENU_PATH . '/schedule') : t('settings profiles'), '!manuallink' => user_access('perform backups') ? l(t('manual backups'), BACKUP_MIGRATE_MENU_PATH) : t('manual backups'))),
- 'more' => t('You can create new profiles using the add profiles tab or by checking the "Save these settings" button on the advanced backup page.'),
- 'access arguments' => array('administer backup and migrate'),
- ),
- BACKUP_MIGRATE_MENU_PATH . '/schedule' => array(
- 'title' => t('Scheduling'),
- 'body' => t('Automatically backup up your database on a regular schedule using cron .',
- array('!cronurl' => 'http://drupal.org/cron')),
- 'more' => t('Each schedule will run a maximum of once per cron run, so they will not run more frequently than your cron is configured to run. If you specify a number of backups to keep for a schedule, old backups will be deleted as new ones created. If specifiy a number of files to keep other backup files in that schedule\'s destination will get deleted .'),
- 'access arguments' => array('administer backup and migrate'),
- ),
- );
-
- if (isset($help[$section])) {
- return $help[$section]['body'];
- }
-
- if ($section == 'admin/help#backup_migrate') {
- $out = "";
- foreach ($help as $key => $section) {
- if (isset($section['access arguments'])) {
- foreach($section['access arguments'] as $access) {
- if (!user_access($access)) {
- continue 2;
- }
- }
- }
- if (@$section['title']) {
- if (!is_numeric($key)) {
- $section['title'] = l($section['title'], $key);
- }
- $out .= "". $section['title'] ." ";
- }
- $out .= "". $section['body'] ."
";
- if (!empty($section['more'])) {
- $out .= "". $section['more'] ."
";
- }
- }
- return $out;
- }
-}
-
-/**
- * Implementation of hook_menu().
- */
-function backup_migrate_menu() {
- $items = array();
-
- $items[BACKUP_MIGRATE_MENU_PATH] = array(
- 'title' => 'Backup and Migrate',
- 'description' => 'Backup/restore your database or migrate data to or from another Drupal site.',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('', 'backup_migrate_ui_manual_backup_quick', TRUE),
- 'access arguments' => array('access backup and migrate'),
- 'type' => MENU_NORMAL_ITEM,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/export'] = array(
- 'title' => 'Backup',
- 'description' => 'Backup the database.',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('', 'backup_migrate_ui_manual_backup_quick', TRUE),
- 'access arguments' => array('access backup and migrate'),
- 'weight' => 0,
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/export/quick'] = array(
- 'title' => 'Quick Backup',
- 'description' => 'Backup the database.',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('', 'backup_migrate_ui_manual_backup_quick', TRUE),
- 'access arguments' => array('access backup and migrate'),
- 'weight' => 0,
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/export/advanced'] = array(
- 'title' => 'Advanced Backup',
- 'description' => 'Backup the database.',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('', 'backup_migrate_ui_manual_backup_advanced', TRUE),
- 'access arguments' => array('perform backup'),
- 'weight' => 1,
- 'type' => MENU_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/restore'] = array(
- 'title' => 'Restore',
- 'description' => 'Restore the database from a previous backup',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('', 'backup_migrate_ui_manual_restore', TRUE),
- 'access arguments' => array('restore from backup'),
- 'weight' => 1,
- 'type' => MENU_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/nodesquirrel'] = array(
- 'title' => 'NodeSquirrel',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('destinations.nodesquirrel', 'nodesquirrel_settings_page'),
- 'access arguments' => array('administer backup and migrate'),
- 'weight' => 10,
- 'type' => MENU_LOCAL_TASK,
- );
-
- backup_migrate_include('crud');
- $items += backup_migrate_crud_menu();
- return $items;
-}
-
-/**
- * Implementation of hook_cron().
- *
- * Takes care of scheduled backups and deletes abandoned temp files.
- */
-function backup_migrate_cron() {
- // Set the message mode to logging.
- _backup_migrate_message_callback('_backup_migrate_message_log');
-
- backup_migrate_include('schedules');
- backup_migrate_schedules_run();
-
- backup_migrate_include('files');
- _backup_migrate_temp_files_delete();
-}
-
-/**
- * Implementation of hook_permission().
- */
-function backup_migrate_permission() {
- return array(
- 'access backup and migrate' => array(
- 'title' => t('Access Backup and Migrate'),
- 'description' => t('Access the Backup and Migrate admin section.'),
- ),
- 'perform backup' => array(
- 'title' => t('Perform a backup'),
- 'description' => t('Back up any of the available databases.'),
- ),
- 'access backup files' => array(
- 'title' => t('Access backup files'),
- 'description' => t('Access and download the previously created backup files.'),
- ),
- 'delete backup files' => array(
- 'title' => t('Delete backup files'),
- 'description' => t('Delete the previously created backup files.'),
- ),
- 'restore from backup' => array(
- 'title' => t('Restore the site'),
- 'description' => t('Restore the site\'s database from a backup file.'),
- ),
- 'administer backup and migrate' => array(
- 'title' => t('Administer Backup and Migrate'),
- 'description' => t('Edit Backup and Migrate profiles, schedules and destinations.'),
- ),
- );
-}
-
-/**
- * Implementation of hook_simpletest().
- */
-function backup_migrate_simpletest() {
- $dir = drupal_get_path('module', 'backup_migrate') .'/tests';
- $tests = file_scan_directory($dir, '\.test$');
- return array_keys($tests);
-}
-
-/**
- * Implementation of hook_theme().
- */
-function backup_migrate_theme() {
- $themes = array(
- 'backup_migrate_ui_manual_quick_backup_form' => array(
- 'arguments' => array('form'),
- 'render element' => 'form',
- ),
- );
- return $themes;
-}
-
-/* Menu Callbacks */
-
-/**
- * A menu callback helper. Handles file includes and interactivity setting.
- */
-function backup_migrate_menu_callback($include, $function, $interactive = TRUE) {
- if ($include) {
- backup_migrate_include($include);
- }
- // Set the message handler based on interactivity setting.
- _backup_migrate_message_callback($interactive ? '_backup_migrate_message_browser' : '_backup_migrate_message_log');
- // Get the arguments with the first 3 removed.
- $args = array_slice(func_get_args(), 3);
- return call_user_func_array($function, $args);
-}
-
-/**
- * Include views .inc files as necessary.
- */
-function backup_migrate_include() {
- static $used = array();
- foreach (func_get_args() as $file) {
- if (!isset($used[$file])) {
- require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'backup_migrate') . "/includes/$file.inc";
- }
-
- $used[$file] = TRUE;
- }
-}
-
-
-/**
- * The menu callback for easy manual backups.
- */
-function backup_migrate_ui_manual_backup_quick() {
- $out = array();
- if (user_access('perform backup')) {
- return drupal_get_form('backup_migrate_ui_manual_quick_backup_form');
- }
- else {
- return t('You do not have permission to back up this site.');
- }
- return $out;
-}
-
-/**
- * The menu callback for advanced manual backups.
- */
-function backup_migrate_ui_manual_backup_advanced() {
- backup_migrate_include('profiles');
- $out = array();
- $profile_id = arg(BACKUP_MIGRATE_MENU_DEPTH + 2);
- $profile = _backup_migrate_profile_saved_default_profile($profile_id);
-
- $out[] = drupal_get_form('backup_migrate_ui_manual_backup_load_profile_form', $profile);
- $out[] = drupal_get_form('backup_migrate_ui_manual_backup_form', $profile);
- return $out;
-}
-
-/**
- * The backup/export load profile form.
- */
-function backup_migrate_ui_manual_backup_load_profile_form($form, &$form_state, $profile = NULL) {
- $form = array();
- $profile_options = _backup_migrate_get_profile_form_item_options();
- if (count($profile_options) > 0) {
- $profile_options = array(0 => t('-- Select a Settings Profile --')) + $profile_options;
- $form['profile'] = array(
- "#title" => t("Settings Profile"),
- "#collapsible" => TRUE,
- "#collapsed" => FALSE,
- "#prefix" => '',
- "#suffix" => '
',
- "#tree" => FALSE,
- "#description" => t("You can load a profile. Any changes you made below will be lost."),
- );
- $form['profile']['profile_id'] = array(
- "#type" => "select",
- "#title" => t("Load Settings"),
- '#default_value' => is_object($profile) ? $profile->get_id() : 0,
- "#options" => $profile_options,
- );
- $form['profile']['load_profile'] = array(
- '#type' => 'submit',
- '#value' => t('Load Profile'),
- );
- }
- return $form;
-}
-
-/**
- * Submit the profile load form.
- */
-function backup_migrate_ui_manual_backup_load_profile_form_submit($form, &$form_state) {
- if ($profile = backup_migrate_get_profile($form_state['values']['profile_id'])) {
- variable_set("backup_migrate_profile_id", $profile->get_id());
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . '/export/advanced';
- }
- else {
- variable_set("backup_migrate_profile_id", NULL);
- }
-}
-
-/**
- * The quick backup form.
- */
-function backup_migrate_ui_manual_quick_backup_form($form, &$form_state) {
- backup_migrate_include('profiles', 'destinations');
- drupal_add_js(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.js');
-
- $form = array();
-
- $form['quickbackup'] = array(
- '#type' => 'fieldset',
- "#title" => t("Quick Backup"),
- "#collapsible" => FALSE,
- "#collapsed" => FALSE,
- "#tree" => FALSE,
- );
-
- $form['quickbackup']['source_id'] = _backup_migrate_get_source_pulldown(variable_get('backup_migrate_source_id', NULL));
-
- $form['quickbackup']['destination_id'] = array(
- "#type" => "select",
- "#title" => t("Destination"),
- "#options" => _backup_migrate_get_destination_form_item_options('manual backup'),
- "#default_value" => variable_get("backup_migrate_destination_id", "download"),
- );
- $profile_options = _backup_migrate_get_profile_form_item_options();
- $form['quickbackup']['profile_id'] = array(
- "#type" => "select",
- "#title" => t("Settings Profile"),
- '#default_value' => variable_get('backup_migrate_profile_id', NULL),
- "#options" => $profile_options,
- );
-
- $form['quickbackup']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Backup now'),
- '#weight' => 1,
- );
-
- $form['advanced'] = array(
- '#type' => 'markup',
- '#markup' => t('For more backup options, try the advanced backup page .', array('!advancedurl' => url(BACKUP_MIGRATE_MENU_PATH . '/export/advanced'))),
- );
-
-
- return $form;
-}
-
-/**
- * Validate the quick backup form.
- */
-function backup_migrate_ui_manual_quick_backup_form_validate($form, &$form_state) {
- if ($form_state['values']['source_id'] == $form_state['values']['destination_id']) {
- form_set_error('destination_id', t('A source cannot be backed up to itself. Please pick a different destination for this backup.'));
- }
-}
-
-/**
- * Submit the quick backup form.
- */
-function backup_migrate_ui_manual_quick_backup_form_submit($form, &$form_state) {
- backup_migrate_include('profiles', 'destinations');
- if (user_access('perform backup')) {
- // For a quick backup use the default settings.
- $settings = _backup_migrate_profile_saved_default_profile($form_state['values']['profile_id']);
-
- // Set the destination to the one chosen in the pulldown.
- $settings->destination_id = $form_state['values']['destination_id'];
- $settings->source_id = $form_state['values']['source_id'];
-
- // Save the settings for next time.
- variable_set("backup_migrate_source_id", $form_state['values']['source_id']);
- variable_set("backup_migrate_destination_id", $form_state['values']['destination_id']);
- variable_set("backup_migrate_profile_id", $form_state['values']['profile_id']);
-
- // Do the backup.
- backup_migrate_ui_manual_backup_perform($settings);
- }
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH;
-}
-
-/**
- * Theme the quick backup form.
- */
-function theme_backup_migrate_ui_manual_quick_backup_form($form) {
- $form = $form['form'];
-
- // Remove the titles so that the pulldowns can be displayed inline.
- unset($form['quickbackup']['source_id']['#title']);
- unset($form['quickbackup']['destination_id']['#title']);
- unset($form['quickbackup']['profile_id']['#title']);
-
- $replacements = array(
- '!from' => drupal_render($form['quickbackup']['source_id']),
- '!to' => drupal_render($form['quickbackup']['destination_id']),
- '!profile' => drupal_render($form['quickbackup']['profile_id']),
- '!submit' => drupal_render($form['quickbackup']['submit']),
- );
- $form['quickbackup']['markup'] = array(
- '#type' => 'markup',
- "#prefix" => '',
- "#suffix" => '
',
- '#markup' => t('Backup from !from to !to using !profile !submit', $replacements),
- );
- unset($form['quickbackup']['source_id']);
- unset($form['quickbackup']['destination_id']);
- unset($form['quickbackup']['profile_id']);
- unset($form['quickbackup']['submit']);
-
- return drupal_render_children($form);
-}
-
-/**
- * The backup/export form.
- */
-function backup_migrate_ui_manual_backup_form($form, &$form_state, $profile) {
- drupal_add_js(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.js', array('type' => 'module', 'scope' => 'footer'));
-
- $form = array();
-
- $form += _backup_migrate_get_source_form('db');
- $form += _backup_migrate_ui_backup_settings_form($profile);
-
- $form['profile_id'] = array(
- "#type" => "value",
- '#default_value' => $profile->get_id(),
- );
- $form['storage'] = array(
- "#type" => "value",
- '#default_value' => $profile->storage,
- );
- $form['destination'] = array(
- "#type" => "fieldset",
- "#title" => t("Backup Destination"),
- "#collapsible" => TRUE,
- "#collapsed" => FALSE,
- "#tree" => FALSE,
- "#description" => t("Choose where the backup file will be saved. Backup files contain sensitive data, so be careful where you save them. Select 'Download' to download the file to your desktop."),
- '#weight' => 70,
- );
- $form['destination']['destination_id'] = array(
- "#type" => "select",
- "#title" => t("Destination"),
- "#options" => _backup_migrate_get_destination_form_item_options('manual backup'),
- "#default_value" => variable_get("backup_migrate_destination_id", "download"),
- );
- if (user_access('administer backup and migrate')) {
- $form['destination']['destination_id']['#description'] = l(t("Create new destination"), BACKUP_MIGRATE_MENU_PATH . "/destination/add");
- }
-
- if (user_access('administer backup and migrate')) {
- $form['save_settings'] = array(
- "#type" => "checkbox",
- "#title" => t('Save these settings.'),
- "#default_value" => FALSE,
- '#weight' => 80,
- );
- $form['save_options'] = array(
- '#prefix' => '',
- '#suffix' => '
',
- '#weight' => 90,
- );
- $name = array(
- '#default_value' => $profile->get('name'),
- '#type' => 'textfield',
- '#title' => t('Save the settings as'),
- );
-
- if ($profile->get_id()) {
- $form['save_options']['create_new'] = array(
- '#default_value' => $profile->get('name'),
- '#type' => 'radios',
- '#default_value' => 0,
- '#options' => array(
- 0 => t("Replace the '%profile' profile", array('%profile' => $profile->get('name'))),
- 1 => t('Create new profile'),
- ),
- );
-
- $name["#title"] = t('Profile name');
- $name["#description"] = t("This will be the name of your new profile if you select 'Create new profile' otherwise it will become the name of the '%profile' profile.", array('%profile' => $profile->get('name')));
- }
- else {
- $name["#title"] = t('Save the settings as');
- $name["#description"] = t('Pick a name for the settings. Your settings will be saved as a profile and will appear in the Profiles Tab .', array('!url' => url(BACKUP_MIGRATE_MENU_PATH . '/profile')));
- $name["#default_value"] = t('Untitled Profile');
- }
- $form['save_options']['name'] = $name;
- $form['save_options'][] = array(
- '#type' => 'submit',
- '#value' => t('Save Without Backing Up'),
- );
- }
- $form['#validate'][] = 'backup_migrate_ui_manual_quick_backup_form_validate';
- $form['#submit'][] = 'backup_migrate_ui_manual_backup_form_submit';
-
- $form[] = array(
- '#type' => 'submit',
- '#value' => t('Backup now'),
- '#weight' => 100,
- );
- return $form;
-}
-
-
-/**
- * Submit the form. Save the values as defaults if desired and output the backup file.
- */
-function backup_migrate_ui_manual_backup_form_submit($form, &$form_state) {
- // Save the settings profile if the save box is checked.
-// $form_state['values']['nodata_tables'] = array_filter((array)$form_state['values']['nodata_tables']);
-// $form_state['values']['exclude_tables'] = array_filter((array)$form_state['values']['exclude_tables']);
-
- $profile = backup_migrate_crud_create_item('profile', $form_state['values']);
-
- // Save the settings profile if the save box is checked.
- if ($form_state['values']['save_settings'] && user_access('administer backup and migrate')) {
- if (@$form_state['values']['create_new']) {
- // Reset the id and storage so a new item will be saved.
- $profile->set_id(NULL);
- $profile->storage = BACKUP_MIGRATE_STORAGE_NONE;
- }
- $profile->save();
- variable_set("backup_migrate_profile_id", $profile->get_id());
- variable_set("backup_migrate_destination_id", $form_state['values']['destination_id']);
- }
-
- // Perform the actual backup if that is what was selected.
- if ($form_state['values']['op'] == t('Backup now') && user_access('perform backup')) {
- backup_migrate_ui_manual_backup_perform($profile);
- }
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . "/export/advanced";
-}
-
-/**
- * Perform an actual manual backup and tell the user of the progress.
- */
-
-function backup_migrate_ui_manual_backup_perform($settings) {
- // Peform the actual backup.
- backup_migrate_perform_backup($settings);
-}
-
-/**
- * The restore/import upload page.
- */
-function backup_migrate_ui_manual_restore() {
- return drupal_get_form('backup_migrate_ui_manual_restore_form');
-}
-
-/**
- * The restore/import upload form.
- */
-function backup_migrate_ui_manual_restore_form() {
- backup_migrate_include('filters', 'destinations');
-
- $form = array();
-
- $sources = _backup_migrate_get_destination_form_item_options('source');
- if (count($sources) > 1) {
- $form['source_id'] = array(
- "#type" => "select",
- "#title" => t("Restore to"),
- "#options" => _backup_migrate_get_destination_form_item_options('source'),
- "#description" => t("Choose the database to restore to. Any database destinations you have created and any databases specified in your settings.php can be restored to."),
- "#default_value" => 'db',
- );
- }
- else {
- $form['source_id'] = array(
- "#type" => "value",
- "#value" => 'db',
- );
- }
-
- $form['backup_migrate_restore_upload'] = array(
- '#title' => t('Upload a Backup File'),
- '#type' => 'file',
- '#description' => t("Upload a backup file created by this version of this module. For other database backups please use another tool for import. Max file size: %size", array("%size" => format_size(file_upload_max_size()))),
- );
- drupal_set_message(t('Restoring will delete some or all of your data and cannot be undone. Always test your backups on a non-production server! '), 'warning', FALSE);
-
- $form = array_merge_recursive($form, backup_migrate_filters_settings_form(backup_migrate_filters_settings_default('restore'), 'restore'));
- // Add the advanced fieldset if there are any fields in it.
- if (@$form['advanced']) {
- $form['advanced']['#type'] = 'fieldset';
- $form['advanced']['#title'] = t('Advanced Options');
- $form['advanced']['#collapsed'] = true;
- $form['advanced']['#collapsible'] = true;
- }
-
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Restore now'),
- );
- if (user_access('access backup files')) {
- $form[] = array(
- '#type' => 'markup',
- '#markup' => t('Or you can restore one of the files in your saved backup destinations.
', array("!url" => url(BACKUP_MIGRATE_MENU_PATH . "/destination"))),
- );
- }
- $form['#attributes'] = array('enctype' => 'multipart/form-data');
- return $form;
-}
-
-/**
- * The restore submit. Do the restore.
- */
-function backup_migrate_ui_manual_restore_form_submit($form, &$form_state) {
- $validators = array('file_validate_extensions' => array('gz zip sql mysql bz bz2'));
- if ($file = file_save_upload('backup_migrate_restore_upload', $validators)) {
- backup_migrate_include('destinations');
- backup_migrate_perform_restore('upload', $file->uri, $form_state['values']);
- }
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . '/restore';
-}
-
-/**
- * Convert an item to an 'exportable'.
- */
-function backup_migrate_ui_export_form($form, &$form_state, $item) {
- if ($item && function_exists('ctools_var_export')) {
- $code = ctools_var_export($item);
- $form = ctools_export_form($form_state, $code);
- return $form;
- }
- return array();
-}
-
-/**
- * Perform a backup with the given settings.
- */
-function backup_migrate_perform_backup(&$settings) {
- backup_migrate_include('destinations', 'files', 'filters');
- timer_start('backup_migrate_backup');
-
- // If not in 'safe mode', increase the maximum execution time:
- if (!ini_get('safe_mode') && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE && ini_get('max_execution_time') < 1200) {
- set_time_limit(variable_get('backup_migrate_backup_max_time', 1200));
- }
-
- $timestamp = '';
- if ($settings->append_timestamp && $settings->timestamp_format) {
- $timestamp = format_date(time(), 'custom', $settings->timestamp_format);
- }
- $filename = _backup_migrate_construct_filename($settings->filename, $timestamp);
-
- $file = new backup_file(array('filename' => $filename));
- if (!$file) {
- backup_migrate_backup_fail("Could not run backup because a temporary file could not be created.", array(), $settings);
- return FALSE;
- }
-
- // Register shutdown callback to deal with timeouts.
- register_shutdown_function('backup_migrate_shutdown', $settings);
-
- $file = backup_migrate_filters_backup($file, $settings);
- if (!$file) {
- if (_backup_migrate_check_timeout()) {
- backup_migrate_backup_fail('Could not complete the backup because the script timed out. Try increasing your PHP max_execution_time setting .', array('!url' => 'http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time'), $settings);
- }
- else {
- backup_migrate_backup_fail("Could not complete the backup.", array(), $settings);
- }
- return FALSE;
- }
-
- $file = backup_migrate_destination_save_file($file, $settings);
- if (!$file) {
- backup_migrate_backup_fail("Could not run backup because the file could not be saved to the destination.", array(), $settings);
- return FALSE;
- }
-
- // Backup succeeded,
- $time = timer_stop('backup_migrate_backup');
- $message = '%source backed up successfully to %file in destination %dest in !time ms. !action';
- $params = array(
- '%file' => $filename,
- '%dest' => $settings->get_destination_name(),
- '%source' => $settings->get_source_name(),
- '!time' => $time['time'],
- '!action' => !empty($settings->performed_action) ? $settings->performed_action : '',
- );
- if (($destination = $settings->get_destination()) && ($links = $destination->get_file_links($file->file_id()))) {
- $params['!links'] = implode(", ", $links);
- }
-
- backup_migrate_backup_succeed($message, $params, $settings);
- return $file;
-}
-
-/**
- * Restore from a file in the given destination.
- */
-function backup_migrate_perform_restore($destination_id, $file, $settings = array()) {
- backup_migrate_include('files', 'filters');
- timer_start('backup_migrate_restore');
-
- // If not in 'safe mode', increase the maximum execution time:
- if (!ini_get('safe_mode') && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE && ini_get('max_execution_time') < variable_get('backup_migrate_backup_max_time', 1200)) {
- set_time_limit(variable_get('backup_migrate_restore_max_time', 1200));
- }
-
- // Make the settings into a default profile.
- if (!is_object($settings)) {
- $settings = backup_migrate_crud_create_item('profile', $settings);
- $settings->source_id = empty($settings->source_id) ? 'db' : $settings->source_id;
- }
-
- // Register shutdown callback.
- register_shutdown_function('backup_migrate_shutdown', $settings);
-
- if (!is_object($file)) {
- // Load the file from the destination.
- $file = backup_migrate_destination_get_file($destination_id, $file);
- if (!$file) {
- _backup_migrate_message("Could not restore because the file could not be loaded from the destination.", array(), 'error');
- backup_migrate_cleanup();
- return FALSE;
- }
- }
- $file_id = $file->file_id();
-
- // Filter the file and perform the restore.
- $file = backup_migrate_filters_restore($file, $settings);
- if (!$file) {
- if (_backup_migrate_check_timeout()) {
- backup_migrate_restore_fail('Could not perform the restore because the script timed out. Try increasing your PHP max_execution_time setting .', array('!url' => 'http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time'), 'error');
- }
- else {
- backup_migrate_restore_fail("Could not perform the restore.", array(), 'error');
- }
- backup_migrate_cleanup();
- return FALSE;
- }
-
- $time = timer_stop('backup_migrate_restore');
- if ($file) {
- $destination = backup_migrate_get_destination($destination_id);
- $message = '%source restored from %dest file %file in !time ms. !action';
- $params = array(
- '%file' => $file->filename(),
- '%source' => $settings->get_source_name(),
- '%dest' => $destination->get_name(),
- '!time' => $time['time'],
- '!action' => !empty($settings->performed_action) ? $settings->performed_action : '',
- );
- if ($destination && $destination->op('list files')) {
- $params['!links'] = t('Restore again ', array('!restoreurl' => url(BACKUP_MIGRATE_MENU_PATH . '/destination/restorefile/'. $destination_id ."/". $file_id)));
- }
- backup_migrate_restore_succeed($message, $params, $settings);
- }
- // Delete any temp files we've created.
- backup_migrate_cleanup();
-
- // No errors. Return the file.
- return $file;
-}
-
-/**
- * Clean up when a backup operation fails.
- */
-function backup_migrate_backup_fail($message, $params, $settings) {
- backup_migrate_include('files', 'filters');
-
- _backup_migrate_message($message, $params, 'error');
- backup_migrate_cleanup();
- backup_migrate_filters_invoke_all('backup_fail', $settings, $message, $params);
- return FALSE;
-}
-
-/**
- * Clean up when a backup operation suceeds.
- */
-function backup_migrate_backup_succeed($message, $params, $settings) {
- backup_migrate_include('filters', 'files');
- _backup_migrate_message($message, $params, 'success');
- backup_migrate_cleanup();
- backup_migrate_filters_invoke_all('backup_succeed', $settings, $message, $params);
- return FALSE;
-}
-
-/**
- * Clean up when a restore operation fails.
- */
-function backup_migrate_restore_fail($message, $params, $settings) {
- backup_migrate_include('files', 'filters');
- _backup_migrate_message($message, $params, 'error');
- backup_migrate_cleanup();
- backup_migrate_filters_invoke_all('restore_fail', $settings, $message, $params);
- return FALSE;
-}
-
-/**
- * Clean up when a restore operation suceeds.
- */
-function backup_migrate_restore_succeed($message, $params, $settings) {
- backup_migrate_include('filters', 'files');
- _backup_migrate_message($message, $params, 'success');
- backup_migrate_cleanup();
- backup_migrate_filters_invoke_all('restore_succeed', $settings, $message, $params);
- return FALSE;
-}
-
-
-/**
- * Cleanup after a success or failure.
- */
-function backup_migrate_cleanup() {
- // Check that the cleanup function exists. If it doesn't then we probably didn't create any files to be cleaned up.
- if (function_exists('_backup_migrate_temp_files_delete')) {
- _backup_migrate_temp_files_delete();
- }
-}
-
-
-/**
- * Shutdown callback. Called when the script terminates even if the script timed out.
- */
-function backup_migrate_shutdown($settings) {
- // If we ran out of time, set an error so the user knows what happened
- if (_backup_migrate_check_timeout()) {
- backup_migrate_cleanup();
- backup_migrate_backup_fail('The operation timed out. Try increasing your PHP max_execution_time setting .', array('!url' => 'http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time'), $settings);
- // The session will have already been written and closed, so we need to write any changes directly.
- _drupal_session_write(session_id(), session_encode());
- // Add a redirect or we'll just get whitescreened.
- drupal_goto(BACKUP_MIGRATE_MENU_PATH);
- }
-}
-
-
-
-/* Actions/Workflow integration */
-
-/**
- * Action to backup the drupal site. Requires actions.module.
-function action_backup_migrate_backup($op, $edit = array()) {
- switch ($op) {
- case 'do':
- _backup_migrate_backup_with_defaults();
- watchdog('action', 'Backed up database');
- break;
-
- case 'metadata':
- return array(
- 'description' => t('Backup the database with the default settings'),
- 'type' => t('Backup and Migrate'),
- 'batchable' => TRUE,
- 'configurable' => FALSE,
- );
-
- // Return an HTML config form for the action.
-
- case 'form':
- return '';
-
- // Validate the HTML form.
-
- case 'validate':
- return TRUE;
-
- // Process the HTML form to store configuration.
-
- case 'submit':
- return '';
- }
-}
- */
-
-/*
- * Implementation of hook_action_info().
-function backup_migrate_action_info() {
- return array(
- 'backup_migrate_action_backup' => array(
- 'label' => t('Backup the database'),
- 'description' => t('Backup the database with the default settings.'),
- ),
- );
-}
- */
-
-/*
- * Action callback.
- */
-function backup_migrate_action_backup() {
- _backup_migrate_backup_with_defaults();
-}
-
-/* Utilities */
-
-/**
- * Backup the database with the default settings.
- */
-function _backup_migrate_backup_with_defaults($destination_id = "manual") {
- backup_migrate_include('files', 'profiles');
-
- $settings = _backup_migrate_profile_saved_default_profile();
- $settings->destination_id = $destination_id;
- $settings->source_id = 'db';
- backup_migrate_perform_backup($settings);
-}
-
-/**
- * Helper function to set a drupal message and watchdog message depending on whether the module is being run interactively.
- */
-function _backup_migrate_message($message, $replace = array(), $type = 'status') {
- // Only set a message if there is a callback handler to handle the message.
- if (($callback = _backup_migrate_message_callback()) && function_exists($callback)) {
- $callback($message, $replace, $type);
- }
-
- // Store the message in case it's needed (for the status notification filter for example).
- _backup_migrate_messages($message, $replace, $type);
-}
-
-/**
- * Helper function to set a drupal message and watchdog message depending on whether the module is being run interactively.
- */
-function _backup_migrate_messages($message = NULL, $replace = array(), $type = 'status') {
- static $messages = array();
- if ($message) {
- $messages[] = array('message' => $message, 'replace' => $replace, 'type' => 'status');
- }
- return $messages;
-}
-
-/**
- * Send a message to the browser. The normal type of message handling for interactive use.
- */
-function _backup_migrate_message_browser($message, $replace, $type) {
- // Log the message as well for admins.
- _backup_migrate_message_log($message, $replace, $type);
-
- // If there are links, we can display them in the browser.
- if (!empty($replace['!links'])) {
- $message .= " (!links)";
- }
- // Use drupal_set_message to display to the user.
- drupal_set_message(t($message, $replace), str_replace('success', 'status', $type), FALSE);
-}
-
-/**
- * Log message if we are in a non-interactive mode such as a cron run.
- */
-function _backup_migrate_message_log($message, $replace, $type) {
- // We only want to log the errors or successful completions.
- if (in_array($type, array('error', 'success'))) {
- watchdog('backup_migrate', $message, $replace, $type == 'error' ? WATCHDOG_ERROR : WATCHDOG_NOTICE);
- }
-}
-
-/**
- * Set or retrieve a message handler.
- */
-function _backup_migrate_message_callback($callback = NULL) {
- static $current_callback = '_backup_migrate_message_log';
- if ($callback !== NULL) {
- $current_callback = $callback;
- }
- return $current_callback;
-}
-
-function _backup_migrate_check_timeout() {
- static $timeout;
-
- // Max execution of 0 means unlimited.
- if (ini_get('max_execution_time') == 0) {
- return false;
- }
- // Figure out when we should stop execution.
- if (!$timeout) {
- $timeout = (!empty($_SERVER['REQUEST_TIME']) ? $_SERVER['REQUEST_TIME'] : time()) + ini_get('max_execution_time') - variable_get('backup_migrate_timeout_buffer', 5);
- }
- return (time() > $timeout);
-}
-
-/**
- * Convert an associated array to an ini format string.
- */
-function _backup_migrate_array_to_ini($data, $prefix = '') {
- $content = "";
- foreach ($data as $key => $val) {
- if ($prefix) {
- $key = $prefix . '[' . $key .']';
- }
- if (is_array($val)) {
- $content .= _backup_migrate_array_to_ini($val, $key);
- }
- else {
- $content .= $key . " = \"". $val ."\"\n";
- }
- }
- return $content;
-}
-
-/**
- * Execute a command line command. Returns false if the function failed.
- */
-function backup_migrate_exec($command, $args = array()) {
- if (!function_exists('exec') || ini_get('safe_mode')) {
- return FALSE;
- }
-
- // Escape the arguments
- foreach ($args as $key => $arg) {
- $args[$key] = escapeshellarg($arg);
- }
- $command = strtr($command, $args);
- $output = $result = NULL;
-
- // Run the command.
- exec($command . ' 2>&1', $output, $result);
-
- return $result == 0;
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/backup_migrate.drush.inc b/sites/all/modules/contrib/backup_migrate/includes/backup_migrate.drush.inc
deleted file mode 100644
index 73097cbf..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/backup_migrate.drush.inc
+++ /dev/null
@@ -1,243 +0,0 @@
- 'backup_migrate_drush_backup',
- 'description' => dt('Backup the site\'s database with Backup and Migrate.'),
- 'aliases' => array('bb'),
- 'examples' => array(
- 'drush bam-backup' => 'Backup the default databse to the manual backup directory using the default settings.',
- 'drush bam-backup db scheduled mysettings' => 'Backup the database to the scheduled directory using a settings profile called "mysettings"',
- 'drush bam-backup files' => 'Backup the files directory to the manual directory using the default settings. The Backup and Migrate Files module is required for files backups.',
- ),
- 'arguments' => array(
- 'source' => "Optional. The id of the source (usually a database) to backup. Use 'drush bam-sources' to get a list of sources. Defaults to 'db'",
- 'destination' => "Optional. The id of destination to send the backup file to. Use 'drush bam-destinations' to get a list of destinations. Defaults to 'manual'",
- 'profile' => "Optional. The id of a settings profile to use. Use 'drush bam-profiles' to get a list of available profiles. Defaults to 'default'",
- ),
- );
- $items['bam-restore'] = array(
- 'callback' => 'backup_migrate_drush_restore',
- 'description' => dt('Restore the site\'s database with Backup and Migrate.'),
- 'arguments' => array(
- 'source' => "Required. The id of the source (usually a database) to restore the backup to. Use 'drush bam-sources' to get a list of sources. Defaults to 'db'",
- 'destination' => "Required. The id of destination to send the backup file to. Use 'drush bam-destinations' to get a list of destinations. Defaults to 'manual'",
- 'backup id' => "Required. The id of a backup file restore. Use 'drush bam-backups' to get a list of available backup files.",
- ),
- 'options' => array(
- 'yes' => 'Skip confirmation',
- ),
- );
- $items['bam-destinations'] = array(
- 'callback' => 'backup_migrate_drush_destinations',
- 'description' => dt('Get a list of available destinations.'),
- );
-
- $items['bam-sources'] = array(
- 'callback' => 'backup_migrate_drush_sources',
- 'description' => dt('Get a list of available sources.'),
- );
- $items['bam-profiles'] = array(
- 'callback' => 'backup_migrate_drush_profiles',
- 'description' => dt('Get a list of available settings profiles.'),
- );
- $items['bam-backups'] = array(
- 'callback' => 'backup_migrate_drush_destination_files',
- 'description' => dt('Get a list of previously created backup files.'),
- 'arguments' => array(
- 'destination' => "Required. The id of destination to list backups from. Use 'drush bam-destinations' to get a list of destinations.",
- ),
- );
- return $items;
-}
-
-/**
- * Implementation of hook_drush_help().
- */
-function backup_migrate_drush_help($section) {
- switch ($section) {
- case 'drush:bam-backup':
- return dt("Backup the site's database using default settings.");
- case 'drush:bam-restore':
- return dt('Restore the site\'s database with Backup and Migrate.');
- case 'drush:bam-destinations':
- return dt('Get a list of available destinations.');
- case 'drush:bam-profiles':
- return dt('Get a list of available settings profiles.');
- case 'drush:bam-backups':
- return dt('Get a list of previously created backup files.');
- }
-}
-
-/**
- * Backup the default database.
- */
-function backup_migrate_drush_backup($source_id = 'db', $destination_id = 'manual', $profile_id = 'default') {
- backup_migrate_include('profiles', 'destinations');
-
- // Set the message mode to logging.
- _backup_migrate_message_callback('_backup_migrate_message_drush');
-
- if (!backup_migrate_get_destination($source_id)) {
- _backup_migrate_message("Could not find the source '@source'. Try using 'drush bam-sources' to get a list of available sources or use 'db' to backup the Drupal database.", array('@source' => $source_id), 'error');
- return;
- }
- if (!backup_migrate_get_destination($destination_id)) {
- _backup_migrate_message("Could not find the destination '@destination'. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
- return;
- }
- $settings = backup_migrate_get_profile($profile_id);
- if(!$settings) {
- _backup_migrate_message("Could not find the profile '@profile'. Try using 'drush bam-profiles' to get a list of available profiles.", array('@profile' => $profile_id), 'error');
- return;
- }
-
- _backup_migrate_message('Starting backup...');
- $settings->destination_id = $destination_id;
- $settings->source_id = $source_id;
- backup_migrate_perform_backup($settings);
-}
-
-/**
- * Restore to the default database.
- */
-function backup_migrate_drush_restore($source_id = '', $destination_id = '', $file_id = '') {
- drush_print(dt('Restoring will delete some or all of your data and cannot be undone. ALWAYS TEST YOUR BACKUPS ON A NON-PRODUCTION SERVER!'));
- if (!drush_confirm(dt('Are you sure you want to restore the database?'))) {
- return drush_user_abort();
- }
-
- backup_migrate_include('profiles', 'destinations');
-
- // Set the message mode to drush output.
- _backup_migrate_message_callback('_backup_migrate_message_drush');
-
- if (!backup_migrate_get_destination($source_id)) {
- _backup_migrate_message("Could not find the source '@source'. Try using 'drush bam-sources' to get a list of available sources or use 'db' to backup the Drupal database.", array('@source' => $source_id), 'error');
- return;
- }
- if (!$destination = backup_migrate_get_destination($destination_id)) {
- _backup_migrate_message("Could not find the destination '@destination'. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
- return;
- }
- if (!$file_id || !$file = backup_migrate_destination_get_file($destination_id, $file_id)) {
- _backup_migrate_message("Could not find the file '@file'. Try using 'drush bam-backups @destination' to get a list of available backup files in this destination destinations.", array('@destination' => $destination_id, '@file' => $file_id), 'error');
- return;
- }
-
- _backup_migrate_message('Starting restore...');
- $settings = array('source_id' => $source_id);
- backup_migrate_perform_restore($destination_id, $file_id);
-}
-
-/**
- * Get a list of available destinations.
- */
-function backup_migrate_drush_destinations() {
- return _backup_migrate_drush_destinations('all');
-}
-
-/**
- * Get a list of available sources.
- */
-function backup_migrate_drush_sources() {
- return _backup_migrate_drush_destinations('source');
-}
-
-
-/**
- * Get a list of available destinations with the given op.
- */
-function _backup_migrate_drush_destinations($op = NULL) {
- backup_migrate_include('destinations');
- $rows = array(array(dt('ID'), dt('Name'), dt('Operations')));
- foreach (backup_migrate_get_destinations($op) as $destination) {
- $rows[] = array(
- $destination->get_id(),
- $destination->get_name(),
- implode (', ', $destination->ops()),
- );
- }
- drush_print_table($rows, TRUE, array(32, 32));
-}
-
-/**
- * Get a list of available profiles.
- */
-function backup_migrate_drush_profiles() {
- backup_migrate_include('profiles');
- $rows = array(array(dt('ID'), dt('Name')));
- foreach (backup_migrate_get_profiles() as $profile) {
- $rows[] = array(
- $profile->get_id(),
- $profile->get_name(),
- );
- }
- drush_print_table($rows, TRUE, array(32, 32));
-}
-
-/**
- * Get a list of files in a given destination
- */
-function backup_migrate_drush_destination_files($destination_id = NULL) {
- backup_migrate_include('destinations');
-
- // Set the message mode to drush output.
- _backup_migrate_message_callback('_backup_migrate_message_drush');
-
- if (!$destination_id) {
- _backup_migrate_message("You must specify an existing destination. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
- return;
- }
- if (!$destination = backup_migrate_get_destination($destination_id)) {
- _backup_migrate_message("Could not find the destination '@destination'. Try using 'drush bam-destinations' to get a list of available destinations.", array('@destination' => $destination_id), 'error');
- return;
- }
-
- $out = array(array(
- dt('Filename'),
- dt('Date'),
- dt('Age'),
- dt('Size'),
- ));
-
- $files = $destination->list_files();
- $i = 0;
- foreach ((array)$files as $file) {
- // Show only files that can be restored from.
- if ($file->is_recognized_type()) {
- $info = $file->info();
- $out[] = array(
- check_plain($info['filename']),
- format_date($info['filetime'], 'small'),
- format_interval(time() - $info['filetime'], 1),
- format_size($info['filesize']),
- );
- }
- }
- if (count($out) > 1) {
- drush_print_table($out, TRUE);
- }
- else {
- drush_print(dt('There are no backup files to display.'));
- }
-}
-
-/**
- * Send a message to the drush log.
- */
-function _backup_migrate_message_drush($message, $replace, $type) {
- // Use drush_log to display to the user.
- drush_log(strip_tags(dt($message, $replace)), str_replace('status', 'notice', $type));
- // Watchdog log the message as well for admins.
- _backup_migrate_message_log($message, $replace, $type);
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/crud.inc b/sites/all/modules/contrib/backup_migrate/includes/crud.inc
deleted file mode 100644
index 29b1ef03..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/crud.inc
+++ /dev/null
@@ -1,660 +0,0 @@
- array(
- 'class' => 'backup_migrate_destination',
- 'include' => 'destinations',
- ),
- 'profile' => array(
- 'class' => 'backup_migrate_profile',
- 'include' => 'profiles',
- ),
- 'schedule' => array(
- 'class' => 'backup_migrate_schedule',
- 'include' => 'schedules',
- ),
- );
- return $out;
-}
-
-/**
- * Get a generic object of the given type to be used for static-like functions.
- *
- * I'm not using actual static method calls since they don't work on variables prior to PHP 5.3.0
- */
-function backup_migrate_crud_type_load($type) {
- $out = NULL;
- $types = backup_migrate_crud_types();
- if (!empty($types[$type])) {
- $info = $types[$type];
- if ($info['include']) {
- backup_migrate_include($info['include']);
- }
- $out = new $info['class'];
- }
- return $out;
-}
-
-
-/**
- * Get the menu items handled by the CRUD code.
- */
-function backup_migrate_crud_menu() {
- $items = array();
- foreach (backup_migrate_crud_types() as $type => $info) {
- $type = backup_migrate_crud_type_load($type);
- $items += (array)$type->get_menu_items();
- }
- return $items;
-}
-
-/**
- * Page callback to create a new item.
- */
-function backup_migrate_crud_ui_create() {
- if ($type = backup_migrate_crud_type_load(arg(BACKUP_MIGRATE_MENU_DEPTH))) {
- $item = $type->create(array());
- return drupal_get_form('backup_migrate_crud_edit_form', $item);
- }
-}
-
-/**
- * Page callback to list all items.
- */
-function backup_migrate_crud_ui_list() {
- $out = '';
- if ($type = backup_migrate_crud_type_load(arg(BACKUP_MIGRATE_MENU_DEPTH))) {
- $out = $type->get_list();
- }
- return $out;
-}
-
-/**
- * Page callback to edit an item.
- */
-function backup_migrate_crud_ui_edit($item_id = NULL) {
- if ($type = backup_migrate_crud_type_load(arg(BACKUP_MIGRATE_MENU_DEPTH))) {
- if ($item_id && $item = $type->item($item_id)) {
- return drupal_get_form('backup_migrate_crud_edit_form', $item);
- }
- drupal_goto(BACKUP_MIGRATE_MENU_PATH. '/' . arg(BACKUP_MIGRATE_MENU_DEPTH));
- }
-}
-
-/**
- * A form callback to edit an item.
- */
-function backup_migrate_crud_edit_form($form, $form_state, $item) {
- $form = $item->edit_form();
- $form['item'] = array(
- '#type' => 'value',
- '#value' => $item,
- );
- $form['#validate'][] = 'backup_migrate_crud_edit_form_validate';
- $form['#submit'][] = 'backup_migrate_crud_edit_form_submit';
-
- return $form;
-}
-
-/**
- * Validate the item edit form.
- */
-function backup_migrate_crud_edit_form_validate($form, &$form_state) {
- $item = $form_state['values']['item'];
- $item->edit_form_validate($form, $form_state);
-}
-
-/**
- * Submit the item edit form.
- */
-function backup_migrate_crud_edit_form_submit($form, &$form_state) {
- $item = $form_state['values']['item'];
- $item->edit_form_submit($form, $form_state);
- if (empty($form_state['redirect'])) {
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . '/'. $item->type_name;
- }
-}
-
-
-/**
- * Page callback to delete an item.
- */
-function backup_migrate_crud_ui_delete($item_id = NULL) {
- if ($type = backup_migrate_crud_type_load(arg(BACKUP_MIGRATE_MENU_DEPTH))) {
- if ($item_id && $item = $type->item($item_id)) {
- return drupal_get_form('backup_migrate_crud_delete_confirm_form', $item);
- }
- drupal_goto('admin/content/backup_migrate/'. arg(BACKUP_MIGRATE_MENU_DEPTH));
- }
-}
-
-/**
- * Ask confirmation for deletion of a item.
- */
-function backup_migrate_crud_delete_confirm_form($form, &$form_state, $item) {
- $form['item'] = array(
- '#type' => 'value',
- '#value' => $item,
- );
- $message = $item->delete_confirm_message();
- return confirm_form($form, t('Are you sure?'), BACKUP_MIGRATE_MENU_PATH . '/'. $item->type_name, $message, t('Delete'), t('Cancel'));
-}
-
-/**
- * Delete a item after confirmation.
- */
-function backup_migrate_crud_delete_confirm_form_submit($form, &$form_state) {
- if ($form_state['values']['confirm']) {
- $item = $form_state['values']['item'];
- $item->delete();
- }
- $form_state['redirect'] = BACKUP_MIGRATE_MENU_PATH . "/". $item->type_name;
-}
-
-/**
- * Export an item.
- */
-function backup_migrate_crud_ui_export($item_id = NULL) {
- if ($type = backup_migrate_crud_type_load(arg(BACKUP_MIGRATE_MENU_DEPTH))) {
- if ($item_id && $item = $type->item($item_id)) {
- return drupal_get_form('backup_migrate_crud_export_form', $item->export());
- }
- drupal_goto(BACKUP_MIGRATE_MENU_PATH . '/' . arg(BACKUP_MIGRATE_MENU_DEPTH));
- }
-}
-
-/**
- * Ask confirmation for deletion of a destination.
- */
-function backup_migrate_crud_export_form($form, &$form_state, $export) {
- $form['export'] = array(
- '#title' => t('Exported content'),
- '#type' => 'textarea',
- '#rows' => min(30, count(explode("\n", $export))),
- '#value' => $export,
- );
- return $form;
-}
-
-/**
- * Get all items of the given type.
- */
-function backup_migrate_crud_get_items($type) {
- if ($type = backup_migrate_crud_type_load($type)) {
- return $type->all_items();
- }
-}
-
-
-/**
- * Get an item of the specified type.
- */
-function backup_migrate_crud_get_item($type, $id) {
- if ($type = backup_migrate_crud_type_load($type)) {
- return $type->item($id);
- }
-}
-
-/**
- * Create a new item of the given type.
- */
-function backup_migrate_crud_create_item($type, $params) {
- if ($type = backup_migrate_crud_type_load($type)) {
- return $type->create($params);
- }
-}
-
-/**
- * A base class for items which can be stored in the database, listed, edited, deleted etc.
- */
-class backup_migrate_item {
- var $db_table = '';
- var $type_name = '';
- var $storage = FALSE;
- var $default_values = array();
- var $singular = 'item';
- var $plural = 'items';
-
- /**
- * Constructor, set the basic info pulled from the db or generated programatically.
- */
- function __construct($params = array()) {
- $this->from_array((array)$params + (array)$this->get_default_values());
- }
-
- /**
- * Get the default values for standard parameters.
- */
- function get_default_values() {
- return $this->default_values;
- }
-
- /**
- * Save the item to the database.
- */
- function save() {
- if (!$this->get_id()) {
- $this->generate_id();
- }
- $data = $this->to_array();
- drupal_write_record($this->db_table, $data, !empty($this->storage) ? $this->get_primary_key() : array());
- }
-
- /**
- * Delete the item from the database.
- */
- function delete() {
- $keys = (array)$this->get_primary_key();
- db_query('DELETE FROM {' . $this->db_table . '} WHERE ' . $keys[0] . ' = :id', array(':id' => $this->get_id()));
- }
-
-
- /**
- * Load an existing item from an array.
- */
- function from_array($params) {
- foreach ($params as $key => $value) {
- if (method_exists($this, 'set_'. $key)) {
- $this->{'set_'. $key}($value);
- }
- else {
- $this->{$key} = $value;
- }
- }
- }
-
- /**
- * Return as an array of values.
- */
- function to_array() {
- $out = array();
- // Return fields as specified in the schema.
- $schema = $this->get_schema();
- if (!empty($schema['fields']) && is_array($schema['fields'])) {
- foreach ($schema['fields'] as $field => $info) {
- $out[$field] = $this->get($field);
- }
- }
- return $out;
- }
-
- /**
- * Return as an exported array of values.
- */
- function export() {
- $out = $this->to_array();
- ob_start();
- var_export($out);
- $out = ob_get_contents();
- ob_end_clean();
- return $out;
- }
-
- /**
- * Load an existing item from an database (serialized) array.
- */
- function load_row($data) {
- $params = array();
- $schema = $this->get_schema();
- // Load fields as specified in the schema.
- foreach ($schema['fields'] as $field => $info) {
- $params[$field] = empty($info['serialize']) ? $data[$field] : unserialize($data[$field]);
- }
- $this->from_array($params);
- }
-
-
- /**
- * Decode a loaded db row (unserialize necessary fields).
- */
- function decode_db_row($data) {
- $params = array();
- $schema = $this->get_schema();
- // Load fields as specified in the schema.
- foreach ($schema['fields'] as $field => $info) {
- $params[$field] = empty($info['serialize']) ? $data[$field] : unserialize($data[$field]);
- }
- return $params;
- }
-
- /**
- * Return the fields which must be serialized before saving to the db.
- */
- function get_serialized_fields() {
- $out = array();
- $schema = $this->get_schema();
- foreach ($schema['fields'] as $field => $info) {
- if (!empty($info['serialize'])) {
- $out[] = $field;
- }
- }
- return $out;
- }
-
- /**
- * Get the primary key field title from the schema.
- */
- function get_primary_key() {
- $schema = $this->get_schema();
- return @$schema['primary key'];
- }
-
- /**
- * Get the schema for the item type.
- */
- function get_schema() {
- return drupal_get_schema($this->db_table);
- }
-
- /**
- * Get the primary id for this item (if any is set).
- *
- * We only handle single field keys since that's all we need.
- */
- function get_id() {
- $keys = (array)$this->get_primary_key();
- return !empty($this->{$keys[0]}) ? (string)$this->{$keys[0]} : '';
- }
-
- /**
- * Set the primary id for this item (if any is set).
- */
- function set_id($id) {
- $keys = (array)$this->get_primary_key();
- if (!empty($keys[0])) {
- return $this->{$keys[0]} = $id;
- }
- return NULL;
- }
-
- /**
- * Return a random (very very likely unique) string id for a new item.
- */
- function generate_id() {
- $this->set_id(md5(uniqid(mt_rand(), true)));
- }
-
- /**
- * Get the name of the item.
- */
- function get_name() {
- return @$this->name;
- }
-
- /**
- * Get the member with the given key.
- */
- function get($key) {
- if (method_exists($this, 'get_'. $key)) {
- return $this->{'get_'. $key}();
- }
- return @$this->{$key};
- }
-
- /* UI Stuff */
-
- /**
- * Get the action links for a destination.
- */
- function get_action_links() {
- $out = array('edit' => '', 'delete' => '');
-
- $item_id = $this->get_id();
-
- if (@$this->storage == BACKUP_MIGRATE_STORAGE_DB || @$this->storage == BACKUP_MIGRATE_STORAGE_OVERRIDEN) {
- $out['edit'] = l(t("edit"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/edit/$item_id");
- }
- else if (@$this->storage == BACKUP_MIGRATE_STORAGE_NONE) {
- $out['edit'] = l(t("override"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/edit/$item_id");
- }
- if (@$this->storage == BACKUP_MIGRATE_STORAGE_DB) {
- $out['delete'] = l(t("delete"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/delete/$item_id");
- }
- else if (@$this->storage == BACKUP_MIGRATE_STORAGE_OVERRIDEN) {
- $out['delete'] = l(t("revert"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/delete/$item_id");
- }
-
- // Export link disabled until we have an import function.
- //$out['export'] = l(t("export"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/export/$item_id");
-
- return $out;
- }
-
- /**
- * Get a table of all items of this type.
- */
- function get_list() {
- $items = $this->all_items();
- $rows = array();
- foreach ($items as $item) {
- if ($row = $item->get_list_row()) {
- $rows[] = $row;
- }
- }
- if (count($rows)) {
- $out = theme('table', array('header' => $this->get_list_header(), 'rows' => $rows));
- }
- else {
- $out = t('There are no !items to display.', array('!items' => $this->plural));
- }
- return $out;
- }
-
- /**
- * Get the columns needed to list the type.
- */
- function get_list_column_info() {
- return array(
- 'actions' => array('title' => t('Operations'), 'html' => TRUE),
- );
- }
-
- /**
- * Get header for a lost of this type.
- */
- function get_list_header() {
- $out = array();
- foreach ($this->get_list_column_info() as $key => $col) {
- $out[] = $col['title'];
- }
- return $out;
- }
-
- /**
- * Get a row of data to be used in a list of items of this type.
- */
- function get_list_row() {
- $out = array();
- foreach ($this->get_list_column_info() as $key => $col) {
- $out[$key] = empty($col['html']) ? check_plain($this->get($key)) : $this->get($key);
- }
- return $out;
- }
-
- /**
- * Get the rendered action links for a destination.
- */
- function get_actions() {
- $links = $this->get_action_links();
- return implode(" ", $links);
- }
-
- /**
- * Get the edit form for the item.
- */
- function edit_form() {
- $form = array();
- $form['item'] = array(
- '#type' => 'value',
- '#value' => $this,
- );
- $form['id'] = array(
- '#type' => 'value',
- '#value' => $this->get_id(),
- );
- $form['actions'] = array('#prefix' => '', '#suffix' => '
', '#weight' => 99);
- $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save !type', array('!type' => t($this->singular))));
- $form['actions']['cancel'] = array('#markup' => l(t('Cancel'), BACKUP_MIGRATE_MENU_PATH . '/destination'));
- return $form;
- }
-
- /**
- * Validate the edit form for the item.
- */
- function edit_form_validate($form, &$form_state) {
- }
-
- /**
- * Submit the edit form for the item.
- */
- function edit_form_submit($form, &$form_state) {
- $this->from_array($form_state['values']);
- $this->save();
- _backup_migrate_message('!type saved', array('!type' => t(ucwords($this->singular))));
- }
-
- /**
- * Get the message to send to the user when confirming the deletion of the item.
- */
- function delete_confirm_message() {
- return t('Are you sure you want to delete this !type?', array('!type' => t($item->singular)));
- }
-
- /* Static Functions */
-
- /**
- * This function is not supposed to be called. It is just here to help the po extractor out.
- */
- function strings() {
- // Help the pot extractor find these strings.
- t('List !type');
- t('Create !type');
- t('Delete !type');
- t('Edit !type');
- t('Export !type');
- }
-
- /**
- * Get the menu items for manipulating this type.
- */
- function get_menu_items() {
- $type = $this->type_name;
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type] = array(
- 'title' => ucwords($this->plural),
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('crud', 'backup_migrate_crud_ui_list', TRUE),
- 'access arguments' => array('administer backup and migrate'),
- 'weight' => 2,
- 'type' => MENU_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type .'/list'] = array(
- 'title' => 'List !type',
- 'title arguments' => array('!type' => t(ucwords($this->plural))),
- 'weight' => 1,
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type .'/list/add'] = array(
- 'title' => 'Add !type',
- 'title arguments' => array('!type' => t(ucwords($this->singular))),
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('crud', 'backup_migrate_crud_ui_create', TRUE),
- 'access arguments' => array('administer backup and migrate'),
- 'weight' => 2,
- 'type' => MENU_LOCAL_ACTION,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type .'/list/delete'] = array(
- 'title' => 'Delete !type',
- 'title arguments' => array('!type' => t(ucwords($this->singular))),
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('crud', 'backup_migrate_crud_ui_delete', TRUE),
- 'access arguments' => array('administer backup and migrate'),
- 'type' => MENU_CALLBACK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type .'/list/edit'] = array(
- 'title' => 'Edit !type',
- 'title arguments' => array('!type' => t(ucwords($this->singular))),
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('crud', 'backup_migrate_crud_ui_edit', TRUE),
- 'access arguments' => array('administer backup and migrate'),
- 'type' => MENU_CALLBACK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/' . $type .'/list/export'] = array(
- 'title' => 'Export !type',
- 'title arguments' => array('!type' => t(ucwords($this->singular))),
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('crud', 'backup_migrate_crud_ui_export', TRUE),
- 'access arguments' => array('administer backup and migrate'),
- 'type' => MENU_CALLBACK,
- );
- return $items;
- }
-
-
- /**
- * Create a new items with the given input. Doesn't load the parameters, but could use them to determine what type to create.
- */
- function create($params = array()) {
- $type = get_class($this);
- return new $type($params);
- }
-
- /**
- * Get all of the given items.
- */
- function all_items() {
- static $cache = array();
-
- // Allow other modules to declare destinations programatically.
- $items = array();
- foreach (module_implements($this->db_table) as $module) {
- $fn = $module . '_' . $this->db_table;
- $items += $fn();
- }
-
- // Get any items stored as a variable. This allows destinations to be defined in settings.php
- $defaults = (array)variable_get($this->db_table .'_defaults', array());
- foreach ($defaults as $info) {
- if (is_array($info) && $item = $this->create($info)) {
- $items[$item->get_id()] = $item;
- }
- }
-
- // Get the items from the db.
- $result = db_query("SELECT * FROM {{$this->db_table}}", array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($result as $info) {
- $info = $this->decode_db_row($info);
- if ($item = $this->create($info)) {
- $item->storage = empty($items[$item->get_id()]) ? BACKUP_MIGRATE_STORAGE_DB : BACKUP_MIGRATE_STORAGE_OVERRIDEN;
- $items[$item->get_id()] = $item;
- }
- }
-
- // Allow other modules to alter the items. This should maybe be before the db override code above
- // but then the filters are not able to set defaults for missing values. Other modules should just
- // be careful not to overwrite the user's UI changes in an unexpected way.
- drupal_alter($this->db_table, $items);
-
- return $items;
- }
-
- /**
- * A particular item.
- */
- function item($item_id) {
- $items = $this->all_items();
- return !empty($items[$item_id]) ? $items[$item_id] : NULL;
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.browser.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.browser.inc
deleted file mode 100644
index a33be2a8..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.browser.inc
+++ /dev/null
@@ -1,74 +0,0 @@
- $file->uri));
- backup_migrate_temp_files_add($file->uri);
- return $out;
- }
- return NULL;
- }
-}
-
-/**
- * A destination type for browser download.
- *
- * @ingroup backup_migrate_destinations
- */
-class backup_migrate_destination_browser_download extends backup_migrate_destination_browser {
- var $supported_ops = array('manual backup');
- function __construct() {
- $params = array();
- $params['name'] = "Download";
- $params['destination_id'] = 'download';
- parent::__construct($params);
- }
-
- /**
- * File save destination callback.
- */
- function save_file($file, $settings) {
- backup_migrate_include('files');
- $file->transfer();
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.db.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.db.inc
deleted file mode 100644
index d6834034..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.db.inc
+++ /dev/null
@@ -1,303 +0,0 @@
-set_source($this->get_id());
-
- // Restore the file to the source database.
- $file = backup_migrate_perform_restore($this->get_id(), $file, $settings);
-
- return $file;
- }
-
- /**
- * Destination configuration callback.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['scheme']['#title'] = t('Database type');
-// $form['scheme']['#options'] = array($GLOBALS['db_type'] => $GLOBALS['db_type']);
- $form['scheme']['#description'] = t('The type of the database. Drupal only supports one database type at a time, so this must be the same as the current database type.');
- $form['path']['#title'] = t('Database name');
- $form['path']['#description'] = t('The name of the database. The database must exist, it will not be created for you.');
- $form['user']['#description'] = t('Enter the name of a user who has write access to the database.');
- return $form;
- }
-
- /**
- * Validate the configuration form. Make sure the db info is valid.
- */
- function edit_form_validate($form, &$form_state) {
- if (!preg_match('/[a-zA-Z0-9_\$]+/', $form_state['values']['path'])) {
- form_set_error('path', t('The database name is not valid.'));
- }
- parent::edit_form_validate($form, $form_state);
- }
-
- /**
- * Get the form for the settings for this destination.
- *
- * Return the default tables whose data can be ignored. These tables mostly contain
- * info which can be easily reproducted (such as cache or search index)
- * but also tables which can become quite bloated but are not necessarily extremely
- * important to back up or migrate during development (such ass access log and watchdog)
- */
- function backup_settings_default() {
- $core = array(
- 'cache',
- 'cache_admin_menu',
- 'cache_browscap',
- 'cache_content',
- 'cache_filter',
- 'cache_calendar_ical',
- 'cache_location',
- 'cache_menu',
- 'cache_page',
- 'cache_reptag',
- 'cache_views',
- 'cache_views_data',
- 'cache_block',
- 'cache_update',
- 'cache_form',
- 'cache_bootstrap',
- 'cache_field',
- 'cache_image',
- 'cache_path',
- 'sessions',
- 'search_dataset',
- 'search_index',
- 'search_keywords_log',
- 'search_total',
- 'watchdog',
- 'accesslog',
- 'devel_queries',
- 'devel_times',
- );
- $nodata_tables = array_merge($core, module_invoke_all('devel_caches'));
- return array(
- 'nodata_tables' => $nodata_tables,
- 'exclude_tables' => array(),
- 'utils_lock_tables' => FALSE,
- );
- }
-
- /**
- * Get the form for the backup settings for this destination.
- */
- function backup_settings_form($settings) {
- $tables = $this->get_table_names();
- $form['#description'] = t("You may omit specific tables, or specific table data from the backup file. Only omit data that you know you will not need such as cache data, or tables from other applications. Excluding tables can break your Drupal install, so do not change these settings unless you know what you're doing .");
- $form['exclude_tables'] = array(
- "#type" => "select",
- "#multiple" => TRUE,
- "#title" => t("Exclude the following tables altogether"),
- "#options" => $tables,
- "#default_value" => $settings['exclude_tables'],
- "#description" => t("The selected tables will not be added to the backup file."),
- );
- $form['nodata_tables'] = array(
- "#type" => "select",
- "#multiple" => TRUE,
- "#title" => t("Exclude the data from the following tables"),
- "#options" => $tables,
- "#default_value" => $settings['nodata_tables'],
- "#description" => t("The selected tables will have their structure backed up but not their contents. This is useful for excluding cache data to reduce file size."),
- );
- $form['utils_lock_tables'] = array(
- '#type' => 'checkbox',
- '#title' => t('Lock tables during backup'),
- '#default_value' => !empty($settings['utils_lock_tables']) ? $settings['utils_lock_tables'] : NULL,
- '#description' => t('This can help reduce data corruption, but will make your site unresponsive.'),
- );
- return $form;
- }
-
- /**
- * Backup from this source.
- */
- function backup_to_file($file, $settings) {
- $file->push_type($this->get_file_type_id());
-
- backup_migrate_filters_invoke_all('pre_backup', $this, $file, $settings);
- //$this->lock_tables($settings);
-
- // Switch to a different db if specified.
- $success = $this->_backup_db_to_file($file, $settings);
-
- //$this->unlock_tables($settings);
- backup_migrate_filters_invoke_all('post_backup', $this, $file, $settings, $success);
-
- return $success ? $file : FALSE;
- }
-
- /**
- * Restore to this source.
- */
- function restore_from_file($file, &$settings) {
- $num = 0;
- $type = $this->get_file_type_id();
- // Open the file using the file wrapper. Check that the dump is of the right type (allow .sql for legacy reasons).
- if ($file->type_id() !== $this->get_file_type_id() && $file->type_id() !== 'sql') {
- _backup_migrate_message("Unable to restore from file %file because a %type file can't be restored to this database.", array("%file" => $file->filepath(), '%type' => $file->type_id()), 'error');
- }
- else {
- backup_migrate_filters_invoke_all('pre_restore', $file, $settings);
-
- // Restore the database.
- $num = $this->_restore_db_from_file($file, $settings);
- $settings->performed_action = $num ? t('%num SQL commands executed.', array('%num' => $num)) : '';
-
- backup_migrate_filters_invoke_all('post_restore', $file, $settings, $num);
- }
- return $num;
- }
-
- /**
- * Get the db connection for the specified db.
- */
- function _get_db_connection() {
- if (!$this->connection) {
- $target = $key = '';
- $parts = explode(':', $this->get_id());
- // One of the predefined databases (set in settings.php)
- if ($parts[0] == 'db') {
- $key = empty($parts[1]) ? 'default' : $parts[1];
- $target = empty($parts[2]) ? 'default' : $parts[2];
- }
- // Another db url.
- else {
- // If the url is specified build it into a connection info array.
- if (!empty($this->dest_url)) {
- $info = array(
- 'driver' => empty($this->dest_url['scheme']) ? NULL : $this->dest_url['scheme'],
- 'host' => empty($this->dest_url['host']) ? NULL : $this->dest_url['host'],
- 'port' => empty($this->dest_url['port']) ? NULL : $this->dest_url['port'],
- 'username' => empty($this->dest_url['user']) ? NULL : $this->dest_url['user'],
- 'password' => empty($this->dest_url['pass']) ? NULL : $this->dest_url['pass'],
- 'database' => empty($this->dest_url['path']) ? NULL : $this->dest_url['path'],
- );
- $key = uniqid('backup_migrate_tmp_');
- $target = 'default';
- Database::addConnectionInfo($key, $target, $info);
- }
- // No database selected. Assume the default.
- else {
- $key = $target = 'default';
- }
- }
- if ($target && $key) {
- try {
- $this->connection = Database::getConnection($target, $key);
- }
- catch (PDOException $e) {
- return NULL;
- }
- }
- }
- return $this->connection;
- }
-
- /**
- * Backup the databases to a file.
- */
- function _backup_db_to_file($file, $settings) {
- // Must be overridden.
- }
-
- /**
- * Backup the databases to a file.
- */
- function _restore_db_from_file($file, $settings) {
- // Must be overridden.
- }
-
- /**
- * Get a list of tables in the database.
- */
- function get_table_names() {
- // Must be overridden.
- $out = $this->_get_table_names();
- return $out;
- }
-
- /**
- * Get a list of tables in the database.
- */
- function _get_table_names() {
- // Must be overridden.
- return array();
- }
-
- /**
- * Lock the database in anticipation of a backup.
- */
- function lock_tables($settings) {
- if ($settings->filters['utils_lock_tables']) {
- $tables = array();
- foreach ($this->get_table_names() as $table) {
- // There's no need to lock excluded or structure only tables because it doesn't matter if they change.
- if (empty($settings->filters['exclude_tables']) || !in_array($table, (array)$settings->filters['exclude_tables'])) {
- $tables[] = $table;
- }
- }
- $this->_lock_tables($tables);
- }
- }
-
- /**
- * Lock the list of given tables in the database.
- */
- function _lock_tables($tables) {
- // Must be overridden.
- }
-
- /**
- * Unlock any tables that have been locked.
- */
- function unlock_tables($settings) {
- if ($settings->filters['utils_lock_tables']) {
- $this->_unlock_tables();
- }
- }
-
- /**
- * Unlock the list of given tables in the database.
- */
- function _unlock_tables($tables) {
- // Must be overridden.
- }
-
- /**
- * Get the file type for to backup this destination to.
- */
- function get_file_type_id() {
- return 'sql';
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.db.mysql.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.db.mysql.inc
deleted file mode 100644
index ffde3f57..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.db.mysql.inc
+++ /dev/null
@@ -1,419 +0,0 @@
- array(
- "extension" => "sql",
- "filemime" => "text/x-sql",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- "mysql" => array(
- "extension" => "mysql",
- "filemime" => "text/x-sql",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- );
- }
-
- /**
- * Declare any mysql databases defined in the settings.php file as a possible destination.
- */
- function destinations() {
- $out = array();
- global $databases;
- foreach ((array)$databases as $db_key => $target) {
- foreach ((array)$target as $tgt_key => $info) {
- // Only mysql/mysqli supported by this destination.
- $key = $db_key . ':' . $tgt_key;
- if ($info['driver'] === 'mysql') {
- $url = $info['driver'] . '://' . $info['username'] . ':' . $info['password'] . '@' . $info['host'] . (isset($info['port']) ? ':' . $info['port'] : '') . '/' . $info['database'];
- if ($destination = backup_migrate_create_destination('mysql', array('url' => $url))) {
- // Make sure the connection is valid.
- if ($destination->_get_db_connection()) {
- // Treat the default database differently because it is probably the only one available.
- if ($key == 'default:default') {
- $destination->set_id('db');
- $destination->set_name(t('Default Database'));
- // Dissalow backing up to the default database because that's confusing and potentially dangerous.
- $destination->remove_op('scheduled backup');
- $destination->remove_op('manual backup');
- }
- else {
- $destination->set_id('db:'. $key);
- $destination->set_name($key .": ". $destination->get_display_location());
- }
- $out[$destination->get_id()] = $destination;
- }
- }
- }
- }
- }
- return $out;
- }
-
- /**
- * Get the file type for to backup this destination to.
- */
- function get_file_type_id() {
- return 'mysql';
- }
-
- /**
- * Get the form for the backup settings for this destination.
- */
- function backup_settings_form($settings) {
- $form = parent::backup_settings_form($settings);
-
- $form['use_mysqldump'] = array(
- "#type" => "checkbox",
- "#title" => t("Use mysqldump command"),
- "#default_value" => !empty($settings['use_mysqldump']),
- "#description" => t("Use the mysqldump command line tool if available. This can be faster for large databases but will not work on all servers. EXPERIMENTAL"),
- );
-
- return $form;
- }
-
-
- /**
- * Backup the databases to a file.
- *
- * Returns a list of sql commands, one command per line.
- * That makes it easier to import without loading the whole file into memory.
- * The files are a little harder to read, but human-readability is not a priority
- */
- function _backup_db_to_file($file, $settings) {
- if (!empty($settings->filters['use_mysqldump']) && $this->_backup_db_to_file_mysqldump($file, $settings)) {
- return TRUE;
- }
-
- $lines = 0;
- $exclude = !empty($settings->filters['exclude_tables']) ? $settings->filters['exclude_tables'] : array();
- $nodata = !empty($settings->filters['nodata_tables']) ? $settings->filters['nodata_tables'] : array();
- if ($file->open(TRUE)) {
- $file->write($this->_get_sql_file_header());
- $alltables = $this->_get_tables();
- foreach ($alltables as $table) {
- if (_backup_migrate_check_timeout()) {
- return FALSE;
- }
- if ($table['name'] && !isset($exclude[$table['name']])) {
- $file->write($this->_get_table_structure_sql($table));
- $lines++;
- if (!in_array($table['name'], $nodata)) {
- $lines += $this->_dump_table_data_sql_to_file($file, $table);
- }
- }
- }
- $file->write($this->_get_sql_file_footer());
- $file->close();
- return $lines;
- }
- else {
- return FALSE;
- }
- }
-
-
- /**
- * Backup the databases to a file using the mysqldump command.
- */
- function _backup_db_to_file_mysqldump($file, $settings) {
- $success = FALSE;
- $nodata_tables = array();
- $alltables = $this->_get_tables();
-
-
- $command = 'mysqldump --result-file=%file --opt -Q --host=%host --port=%port --user=%user --password=%pass %db';
- $args = array(
- '%file' => $file->filepath(),
- '%host' => $this->dest_url['host'],
- '%port' => !empty($this->dest_url['port']) ? $this->dest_url['port'] : '3306',
- '%user' => $this->dest_url['user'],
- '%pass' => $this->dest_url['pass'],
- '%db' => $this->dest_url['path'],
- );
-
- // Ignore the excluded and no-data tables.
- if (!empty($settings->filters['exclude_tables'])) {
- $db = $this->dest_url['path'];
- foreach ((array)$settings->filters['exclude_tables'] as $table) {
- if (isset($alltables[$table])) {
- $command .= ' --ignore-table='. $db .'.'. $table;
- }
- }
- foreach ((array)$settings->filters['nodata_tables'] as $table) {
- if (isset($alltables[$table])) {
- $nodata_tables[] = $table;
- $command .= ' --ignore-table='. $db .'.'. $table;
- }
- }
- }
- $success = backup_migrate_exec($command, $args);
-
- // Get the nodata tables.
- if ($success && !empty($nodata_tables)) {
- $tables = implode(' ', array_unique($nodata_tables));
- $command = "mysqldump --no-data --opt -Q --host=%host --port=%port --user=%user --password=%pass %db $tables >> %file";
- $success = backup_migrate_exec($command, $args);
- }
- return $success;
- }
-
- /**
- * Backup the databases to a file.
- */
- function _restore_db_from_file($file, $settings) {
- $num = 0;
-
- if ($file->open() && $conn = $this->_get_db_connection()) {
- // Read one line at a time and run the query.
- while ($line = $this->_read_sql_command_from_file($file)) {
- if (_backup_migrate_check_timeout()) {
- return FALSE;
- }
- if ($line) {
- // Prepeare and exexute the statement instead of the api function to avoid substitution of '{' etc.
- $stmt = $conn->prepare($line);
- $stmt->execute();
- $num++;
- }
- }
- // Close the file with fclose/gzclose.
- $file->close();
- }
- else {
- drupal_set_message(t("Unable to open file %file to restore database", array("%file" => $file->filepath())), 'error');
- $num = FALSE;
- }
- return $num;
- }
-
-
- /**
- * Read a multiline sql command from a file.
- *
- * Supports the formatting created by mysqldump, but won't handle multiline comments.
- */
- function _read_sql_command_from_file($file) {
- $out = '';
- while ($line = $file->read()) {
- $first2 = substr($line, 0, 2);
- $first3 = substr($line, 0, 2);
-
- // Ignore single line comments. This function doesn't support multiline comments or inline comments.
- if ($first2 != '--' && ($first2 != '/*' || $first3 == '/*!')) {
- $out .= ' ' . trim($line);
- // If a line ends in ; or */ it is a sql command.
- if (substr($out, strlen($out) - 1, 1) == ';') {
- return trim($out);
- }
- }
- }
- return trim($out);
- }
-
- /**
- * Get a list of tables in the database.
- */
- function _get_table_names() {
- $out = array();
- foreach ($this->_get_tables() as $table) {
- $out[$table['name']] = $table['name'];
- }
- return $out;
- }
-
- /**
- * Lock the list of given tables in the database.
- */
- function _lock_tables($tables) {
- if ($tables) {
- $tables_escaped = array();
- foreach ($tables as $table) {
- $tables_escaped[] = '`'. db_escape_table($table) .'` WRITE';
- }
- $this->query('LOCK TABLES '. implode(', ', $tables_escaped));
- }
- }
-
- /**
- * Unlock all tables in the database.
- */
- function _unlock_tables($settings) {
- $this->query('UNLOCK TABLES');
- }
-
- /**
- * Get a list of tables in the db.
- */
- function _get_tables() {
- $out = array();
- // get auto_increment values and names of all tables
- $tables = $this->query("show table status", array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($tables as $table) {
- // Lowercase the keys because between Drupal 7.12 and 7.13/14 the default query behavior was changed.
- // See: http://drupal.org/node/1171866
- $table = array_change_key_case($table);
- $out[$table['name']] = $table;
- }
- return $out;
- }
-
- /**
- * Get the sql for the structure of the given table.
- */
- function _get_table_structure_sql($table) {
- $out = "";
- $result = $this->query("SHOW CREATE TABLE `". $table['name'] ."`", array(), array('fetch' => PDO::FETCH_ASSOC));
- foreach ($result as $create) {
- // Lowercase the keys because between Drupal 7.12 and 7.13/14 the default query behavior was changed.
- // See: http://drupal.org/node/1171866
- $create = array_change_key_case($create);
- $out .= "DROP TABLE IF EXISTS `". $table['name'] ."`;\n";
- // Remove newlines and convert " to ` because PDO seems to convert those for some reason.
- $out .= strtr($create['create table'], array("\n" => ' ', '"' => '`'));
- if ($table['auto_increment']) {
- $out .= " AUTO_INCREMENT=". $table['auto_increment'];
- }
- $out .= ";\n";
- }
- return $out;
- }
-
- /**
- * Get the sql to insert the data for a given table
- */
- function _dump_table_data_sql_to_file($file, $table) {
- $rows_per_line = variable_get('backup_migrate_data_rows_per_line', 30);
- $bytes_per_line = variable_get('backup_migrate_data_bytes_per_line', 2000);
-
- $lines = 0;
- $data = $this->query("SELECT * FROM `". $table['name'] ."`", array(), array('fetch' => PDO::FETCH_ASSOC));
- $rows = $bytes = 0;
-
- // Escape backslashes, PHP code, special chars
- $search = array('\\', "'", "\x00", "\x0a", "\x0d", "\x1a");
- $replace = array('\\\\', "''", '\0', '\n', '\r', '\Z');
-
- $line = array();
- foreach ($data as $row) {
- // DB Escape the values.
- $items = array();
- foreach ($row as $key => $value) {
- $items[] = is_null($value) ? "null" : "'". str_replace($search, $replace, $value) ."'";
- }
-
- // If there is a row to be added.
- if ($items) {
- // Start a new line if we need to.
- if ($rows == 0) {
- $file->write("INSERT INTO `". $table['name'] ."` VALUES ");
- $bytes = $rows = 0;
- }
- // Otherwise add a comma to end the previous entry.
- else {
- $file->write(",");
- }
-
- // Write the data itself.
- $sql = implode(',', $items);
- $file->write('('. $sql .')');
- $bytes += strlen($sql);
- $rows++;
-
- // Finish the last line if we've added enough items
- if ($rows >= $rows_per_line || $bytes >= $bytes_per_line) {
- $file->write(";\n");
- $lines++;
- $bytes = $rows = 0;
- }
- }
- }
- // Finish any unfinished insert statements.
- if ($rows > 0) {
- $file->write(";\n");
- $lines++;
- }
-
- return $lines;
- }
-
- /**
- * Get the db connection for the specified db.
- */
- function _get_db_connection() {
- if (!$this->connection) {
- if ($this->connection = parent::_get_db_connection()) {
- // Set the sql mode because the default is ANSI,TRADITIONAL which is not aware of collation or storage engine.
- $this->connection->exec("SET sql_mode=''");
- }
- }
- return $this->connection;
- }
-
- /**
- * Run a db query on this destination's db.
- */
- function query($query, $args = array(), $options = array()) {
- if ($conn = $this->_get_db_connection()) {
- return $conn->query($query, $args, $options);
- }
- }
-
- /**
- * The header for the top of the sql dump file. These commands set the connection
- * character encoding to help prevent encoding conversion issues.
- */
- function _get_sql_file_header() {
- return "/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=NO_AUTO_VALUE_ON_ZERO */;
-
-SET NAMES utf8;
-
-";
- }
-
- /**
- * The footer of the sql dump file.
- */
- function _get_sql_file_footer() {
- return "
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-";
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.email.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.email.inc
deleted file mode 100644
index fd82c737..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.email.inc
+++ /dev/null
@@ -1,140 +0,0 @@
-filepath());
- $max = variable_get('backup_migrate_max_email_size', 20971520);
- if ($size > $max) {
- _backup_migrate_message('Could not email the file @file because it is @size and Backup and Migrate only supports emailing files smaller than @max.', array('@file' => $file->filename(), '@size' => format_size($size), '@max' => format_size($max)), 'error');
- return FALSE;
- }
- $attachment = new stdClass();
- $attachment->filename = $file->filename();
- $attachment->path = $file->filepath();
- _backup_migrate_destination_email_mail_backup($attachment, $this->get_location());
- return $file;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['location'] = array(
- "#type" => "textfield",
- "#title" => t("Email Address"),
- "#default_value" => $this->get_location(),
- "#required" => TRUE,
- "#description" => t('Enter the email address to send the backup files to. Make sure the email sever can handle large file attachments'),
- );
- return $form;
- }
-
- /**
- * Validate the configuration form. Make sure the email address is valid.
- */
- function settings_form_validate($values) {
- if (!valid_email_address($values['location'])) {
- form_set_error('[location]', t('The e-mail address %mail is not valid.', array('%mail' => $form_state['values']['location'])));
- }
- }
-}
-
-/**
- * @function
- * Temporary mail handler class.
- *
- * Defines a mail class to send a message with an attachment. Eventually Drupal
- * core should provide this functionality, at which time this code will be
- * removed.
- *
- * More info on sending email at .
- * This function taken from dba.module.
- *
- * @param $attachment
- * An object which contains two variables "path" the path to the file and
- * filename and "filename" which is just the filename.
- */
-function _backup_migrate_destination_email_mail_backup($attachment, $to) {
- // Send mail
- $attach = fread(fopen($attachment->path, "r"), filesize($attachment->path));
- $mail = new mime_mail();
- $mail->from = variable_get('site_mail', ini_get('sendmail_from'));
- $mail->headers = 'Errors-To: [EMAIL='. $mail->from .']'. $mail->from .'[/EMAIL]';
- $mail->to = $to;
- $mail->subject = t('Database backup from !site: !file', array('!site' => variable_get('site_name', 'drupal'), '!file' => $attachment->filename));
- $mail->body = t('Database backup attached.') ."\n\n";
-
- $mail->add_attachment("$attach", $attachment->filename, "Content-Transfer-Encoding: base64 /9j/4AAQSkZJRgABAgEASABIAAD/7QT+UGhvdG9zaG", NULL, TRUE);
- $mail->send();
-}
-
-class mime_mail {
- var $parts;
- var $to;
- var $from;
- var $headers;
- var $subject;
- var $body;
-
- function mime_mail() {
- $this->parts = array();
- $this->to = "";
- $this->from = "";
- $this->headers = "";
- $this->subject = "";
- $this->body = "";
- }
-
- function add_attachment($message, $name = "", $ctype = "application/octet-stream", $encode = NULL, $attach = FALSE) {
- $this->parts[] = array(
- "ctype" => $ctype,
- "message" => $message,
- "encode" => $encode,
- "name" => $name,
- "attach" => $attach,
- );
- }
-
- function build_message($part) {
- $message = $part["message"];
- $message = chunk_split(base64_encode($message));
- $encoding = "base64";
- $disposition = $part['attach'] ? "Content-Disposition: attachment; filename=$part[name]\n" : '';
- return "Content-Type: ". $part["ctype"] . ($part["name"] ? "; name = \"". $part["name"] ."\"" : "") ."\nContent-Transfer-Encoding: $encoding\n$disposition\n$message\n";
- }
-
- function build_multipart() {
- $boundary = "b". md5(uniqid(time()));
- $multipart = "Content-Type: multipart/mixed; boundary = $boundary\n\nThis is a MIME encoded message.\n\n--$boundary";
- for ($i = sizeof($this->parts) - 1; $i >= 0; $i--) {
- $multipart .= "\n". $this->build_message($this->parts[$i]) ."--$boundary";
- }
- return $multipart .= "--\n";
- }
-
- function send() {
- $mime = "";
- if (!empty($this->from)) $mime .= "From: ". $this->from ."\n";
- if (!empty($this->headers)) $mime .= $this->headers ."\n";
- if (!empty($this->body)) $this->add_attachment($this->body, "", "text/plain");
- $mime .= "MIME-Version: 1.0\n". $this->build_multipart();
- mail(trim($this->to), $this->subject, "", $mime);
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.file.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.file.inc
deleted file mode 100644
index 93691fc2..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.file.inc
+++ /dev/null
@@ -1,274 +0,0 @@
-get_location());
- }
-
- /**
- * File save destination callback.
- */
- function _save_file($file, $settings) {
- if ($dir = $this->get_location()) {
- if ($dir = $this->check_dir($dir)) {
- $filepath = rtrim($dir, "/") ."/". $file->filename();
- if (file_unmanaged_move($file->filepath(), $filepath)) {
-
- // chmod, chown and chgrp the file if needed.
- if ($chmod = $this->settings('chmod')) {
- if (!@drupal_chmod($filepath, octdec($chmod))) {
- _backup_migrate_message('Unable to set the file mode for: @file', array('@file' => $filepath), 'error');
- }
- }
- if ($chgrp = $this->settings('chgrp')) {
- if (!@chgrp($filepath, $chgrp)) {
- _backup_migrate_message('Unable to set the file group for: @file', array('@file' => $filepath), 'error');
- }
- }
- return $file;
- }
- else {
- _backup_migrate_message('Unable to save the file to the directory: @dir', array('@dir' => $dir), 'error');
- }
- }
- }
- }
-
- /**
- * Determine if we can read the given file.
- */
- function can_read_file($file_id) {
- return $this->op('restore') && is_readable($this->get_filepath($file_id));
- }
-
- /**
- * File load destination callback.
- */
- function load_file($file_id) {
- $filepath = $this->get_filepath($file_id);
- if (file_exists($filepath)) {
- backup_migrate_include('files');
- return new backup_file(array('filepath' => $filepath));
- }
- }
-
- /**
- * File list destination callback.
- */
- function _list_files() {
- $files = array();
- if ($dir = $this->get_realpath()) {
- if ($handle = @opendir($dir)) {
- backup_migrate_include('files');
- while (FALSE !== ($file = readdir($handle))) {
- $filepath = $dir ."/". $file;
- $files[$file] = new backup_file(array('filepath' => $filepath));
- }
- }
- }
- return $files;
- }
-
- /**
- * File delete destination callback.
- */
- function _delete_file($file_id) {
- $filepath = $this->get_filepath($file_id);
- file_unmanaged_delete($filepath);
- }
-
- /**
- * Get the filepath from the given file id.
- */
- function get_filepath($file_id) {
- if ($dir = $this->get_realpath()) {
- $filepath = rtrim($dir, '/') .'/'. $file_id;
- return $filepath;
- }
- return FALSE;
- }
-
- /**
- * Get the form for the settings for the files destination.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['location'] = array(
- "#type" => "textfield",
- "#title" => t("Directory path"),
- "#default_value" => $this->get_location(),
- "#required" => TRUE,
- "#description" => t('Enter the path to the directory to save the backups to. Use a relative path to pick a path relative to your Drupal root directory. The web server must be able to write to this path.'),
- );
- $form['settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Advanced Settings'),
- '#tree' => TRUE,
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- if (function_exists('chmod')) {
- $form['settings']['chmod'] = array(
- '#type' => 'textfield',
- '#title' => t('Change file mode (chmod)'),
- '#size' => 5,
- '#default_value' => $this->settings('chmod'),
- '#description' => t('If you enter a value here, backup files will be chmoded with the mode you specify. Specify the mode in octal form (e.g. 644 or 0644) or leave blank to disable this feature.'),
- );
- }
- if (function_exists('chgrp')) {
- $form['settings']['chgrp'] = array(
- '#type' => 'textfield',
- '#title' => t('Change file group (chgrp)'),
- '#size' => 5,
- '#default_value' => $this->settings('chgrp'),
- '#description' => t('If you enter a value here, backup files will be chgrped to the group you specify. Leave blank to disable this feature.'),
- );
- }
- return $form;
- }
-
- /**
- * Validate the form for the settings for the files destination.
- */
- function edit_form_validate($form, &$form_state) {
- $values = $form_state['values'];
- if (isset($values['settings']['chmod']) && !empty($values['settings']['chmod']) && !preg_match('/0?[0-7]{3}/', $values['settings']['chmod'])) {
- form_set_error('chmod', t('You must enter a valid chmod octal value (e.g. 644 or 0644) in the change mode field, or leave it blank.'));
- }
- parent::edit_form_validate($form, $form_state);
- }
-
- /**
- * Submit the form for the settings for the files destination.
- */
- function edit_form_submit($form, &$form_state) {
- // Add a 0 to the start of a 3 digit file mode to make it proper PHP encoded octal.
- if (strlen($form_state['values']['settings']['chmod']) == 3) {
- $form_state['values']['settings']['chmod'] = '0' . $form_state['values']['settings']['chmod'];
- }
- parent::edit_form_submit($form, $form_state);
- }
-
- /**
- * Prepare the destination directory for the backups.
- */
- function check_dir($directory) {
- if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
- // Unable to create destination directory.
- _backup_migrate_message("Unable to create or write to the save directory '%directory'. Please check the file permissions that directory and try again.", array('%directory' => $directory), "error");
- return FALSE;
- }
- // If the destination directory is within the webroot, then secure it as best we can.
- if ($this->dir_in_webroot($directory)) {
- $directory = $this->check_web_dir($directory);
- }
-
- return $directory;
- }
-
- /**
- * Check that a web accessible directory has been properly secured, othewise attempt to secure it.
- */
- function check_web_dir($directory) {
- // If the directory is specified with an absolute path, strip the site root.
- $directory = substr(drupal_realpath($directory), strlen(drupal_realpath($_SERVER['DOCUMENT_ROOT']) . base_path()));
-
- file_create_htaccess($directory, TRUE);
-
- // Check the user agent to make sure we're not responding to a request from drupal itself.
- // That should prevent infinite loops which could be caused by poormanscron in some circumstances.
- if (strpos($_SERVER['HTTP_USER_AGENT'], 'Drupal') !== FALSE) {
- return FALSE;
- }
-
- // Check to see if the destination is publicly accessible
- $test_contents = "this file should not be publicly accessible";
- // Create the the text.txt file if it's not already there.
- if (!is_file($directory .'/test.txt') || file_get_contents($directory .'/test.txt') != $test_contents) {
- if ($fp = fopen($directory .'/test.txt', 'w')) {
- @fputs($fp, $test_contents);
- fclose($fp);
- }
- else {
- $message = t("Security notice: Backup and Migrate was unable to write a test text file to the destination directory %directory, and is therefore unable to check the security of the backup destination. Backups to the server will be disabled until the destination becomes writable and secure.", array('%directory' => $directory));
- drupal_set_message($message, "error");
- return FALSE;
- }
- }
-
- // Attempt to read the test file via http. This may fail for other reasons,
- // so it's not a bullet-proof check.
- if ($this->test_file_readable_remotely($directory .'/test.txt', $test_contents)) {
- $message = t("Security notice: Backup and Migrate will not save backup files to the server because the destination directory is publicly accessible. If you want to save files to the server, please secure the '%directory' directory", array('%directory' => $directory));
- drupal_set_message($message, "error");
- return FALSE;
- }
- return $directory;
- }
-
- /**
- * Check if the given directory is within the webroot and is therefore web accessible.
- */
- function dir_in_webroot($directory) {
- if (strpos(drupal_realpath($directory), realpath($_SERVER['DOCUMENT_ROOT'])) !== FALSE) {
- return TRUE;
- }
- return FALSE;
- }
-
- /**
- * Check if a file can be read remotely via http.
- */
- function test_file_readable_remotely($path, $contents) {
- $url = $GLOBALS['base_url'] . '/' . str_replace('\\', '/', $path);
- $result = drupal_http_request($url);
- if (!empty($result->data) && strpos($result->data, $contents) !== FALSE) {
- return TRUE;
- }
- return FALSE;
- }
-}
-
-/**
- * The manual files directory.
- */
-class backup_migrate_destination_files_manual extends backup_migrate_destination_files {
- var $supported_ops = array('manual backup', 'restore', 'list files', 'configure', 'delete');
- function __construct($params = array()) {
- $dir = 'private://backup_migrate/manual';
- parent::__construct($params + array('location' => $dir, 'name' => t('Manual Backups Directory')));
- }
-}
-
-/**
- * The scheduled files directory.
- */
-class backup_migrate_destination_files_scheduled extends backup_migrate_destination_files {
- var $supported_ops = array('scheduled backup', 'restore', 'list files', 'configure', 'delete');
- function __construct($params = array()) {
- $dir = 'private://backup_migrate/scheduled';
- parent::__construct($params + array('location' => $dir, 'name' => t('Scheduled Backups Directory')));
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.ftp.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.ftp.inc
deleted file mode 100644
index 306b1bac..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.ftp.inc
+++ /dev/null
@@ -1,436 +0,0 @@
-ftp_object();
- if (drupal_ftp_file_to_ftp($file->filepath(), $file->filename(), '.', $ftp)) {
- return $file;
- }
- return FALSE;
- }
-
- /**
- * Load from the ftp destination.
- */
- function load_file($file_id) {
- backup_migrate_include('files');
- $file = new backup_file(array('filename' => $file_id));
- $this->ftp_object();
- if (drupal_ftp_ftp_to_file($file->filepath(), $file_id, '.', $this->ftp)) {
- return $file;
- }
- return FALSE;
- }
-
- /**
- * Delete from the ftp destination.
- */
- function _delete_file($file_id) {
- $this->ftp_object();
- drupal_ftp_delete_file($file_id, $this->ftp);
- }
-
- function _list_files() {
- backup_migrate_include('files');
- $files = array();
- $this->ftp_object();
- $ftp_files = drupal_ftp_file_list('.', $this->ftp);
- foreach ($ftp_files as $file) {
- $files[$file['filename']] = new backup_file($file);
- }
- return $files;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['scheme']['#type'] = 'value';
- $form['scheme']['#value'] = 'ftp';
- $form['port'] = array(
- "#type" => "textfield",
- "#title" => t("Port"),
- "#default_value" => @$this->dest_url['port'] ? $this->dest_url['port'] : '21',
- "#weight" => 15,
- );
- $form['pasv'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use PASV transfers'),
- '#default_value' => $this->get_pasv(),
- '#weight' => 50,
- );
- return $form;
- }
-
- function set_pasv($value) {
- $this->settings['pasv'] = (bool)$value;
- }
-
- function get_pasv() {
- return isset($this->settings['pasv']) ? $this->settings['pasv'] : FALSE;
- }
-
- function ftp_object() {
- if (!$this->ftp) {
- $this->dest_url['port'] = empty($this->dest_url['port']) ? '21' : $this->dest_url['port'];
- $this->dest_url['pasv'] = $this->get_pasv();
- $this->ftp = drupal_ftp_ftp_object($this->dest_url['host'], $this->dest_url['port'], $this->dest_url['user'], $this->dest_url['pass'], $this->dest_url['path'], $this->dest_url['pasv']);
- }
- return $this->ftp;
- }
-}
-
-// The FTP code below was taken from the ftp module by Aaron Winborn.
-
-// Inspired by http://www.devarticles.com/c/a/PHP/My-FTP-Wrapper-Class-for-PHP/
-// It's been drupalized, however, and most of the bugs from that example have been fixed.
-// - winborn 2007-06-22 - 2007-06-28
-
-define('DRUPAL_FTP_FT_DIRECTORY', 0);
-define('DRUPAL_FTP_FT_FILE', 1);
-
-/**
- * creates a new ftp object. if any elements of ftp_map are missing, they'll be filled with the server defaults.
- */
-function drupal_ftp_ftp_object($server, $port, $user, $pass, $dir, $pasv) {
- $ftp = new stdClass();
-
- $ftp->__server = $server;
- $ftp->__port = $port;
- $ftp->__user = $user;
- $ftp->__password = $pass;
- $ftp->__directory = $dir;
- $ftp->__pasv = $pasv;
-
- return $ftp;
-}
-
-/**
- * The drupal_ftp_connect function
- * This function connects to an FTP server and attempts to change into the directory specified by
- * the fourth parameter, $directory.
- */
-function drupal_ftp_connect(&$ftp) {
- if (is_NULL($ftp)) {
- $ftp = drupal_ftp_ftp_object();
- }
-
- if (empty($ftp->__conn) && !drupal_ftp_connected($ftp)) {
- // Attempt to connect to the remote server
- $ftp->__conn = @ftp_connect($ftp->__server, $ftp->__port);
-
- if (!$ftp->__conn) {
- _backup_migrate_message('FTP Error: Couldn\'t connect to server @server', array('@server' => $ftp->__server), 'error');
- return FALSE;
- }
-
- // Attempt to login to the remote server
- $ftp->__login = @ftp_login($ftp->__conn, $ftp->__user, $ftp->__password);
-
- if (!$ftp->__login) {
- _backup_migrate_message('FTP Error: Couldn\'t login as user @ftp_user to @server', array('@ftp_user' => $ftp->__user, '@server' => $ftp->__server), 'error');
- return FALSE;
- }
-
- // Attempt to change into the working directory
- $chdir = @ftp_chdir($ftp->__conn, $ftp->__directory);
-
- if (!$chdir) {
- _backup_migrate_message('FTP Error: Couldn\'t change into the @directory directory', array('@directory' => $ftp->__directory), 'error');
- return FALSE;
- }
-
- // Set PASV - if needed
- if ($ftp->__pasv) {
- $pasv = @ftp_pasv($ftp->__conn, TRUE);
- if (!$pasv) {
- _backup_migrate_message('FTP Error: Couldn\'t set PASV mode', array(), 'error');
- return FALSE;
- }
- }
- }
-
- // Everything worked OK, return TRUE
- return TRUE;
-}
-
-/**
- * The drupal_ftp_connected function
- * This function queries the FTP server with the ftp_systype command to check if the connection is still alive.
- * It returns TRUE on success or FALSE on disconnection.
- */
-function drupal_ftp_connected(&$ftp) {
- // Attempt to call the ftp_systype to see if the connect
- // to the FTP server is still alive and kicking
-
- if (is_NULL($ftp)) {
- $ftp = drupal_ftp_ftp_object();
- return FALSE;
- }
-
- if (!@ftp_systype($ftp->__conn)) {
- // The connection is dead
- return FALSE;
- }
- else {
- // The connection is still alive
- return TRUE;
- }
-}
-
-/**
- * This function tries to retrieve the contents of a file from the FTP server.
- * Firstly it changes into the $directory directory, and then attempts to download the file $filename.
- * The file is saved locally and its contents are returned to the caller of the function.
- */
-function drupal_ftp_ftp_to_file($file, $filename, $directory, &$ftp) {
- // Change into the remote directory and retrieve the content
- // of a file. Once retrieve, return this value to the caller
-
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- // We are now connected, so let's retrieve the file contents.
- // Firstly, we change into the directory
- $chdir = @ftp_chdir($ftp->__conn, $directory);
-
- if (!$chdir) {
- _backup_migrate_message('FTP Error: Couldn\'t change into directory: @directory', array('@directory' => $directory), 'error');
- return FALSE;
- }
-
- // We have changed into the directory, let's attempt to get the file
- $fp = @fopen($file, 'wb');
- $get_file = @ftp_fget($ftp->__conn, $fp, $filename, FTP_BINARY);
- fclose($fp);
-
- $fp = NULL;
-
- if (!$get_file) {
- _backup_migrate_message('FTP Error: Unable to download file: @filename from @directory', array('@filename' => $filename, '@directory' => $directory), 'error');
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- * Send a file to an FTP server.
- */
-function drupal_ftp_file_to_ftp($file, $ftp_filename, $ftp_directory, &$ftp) {
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- if ($source = drupal_realpath($file)) {
- // Now we can try to write to the remote file
- $complete_filename = $ftp_directory .'/'. $ftp_filename;
- $put_file = @ftp_put($ftp->__conn, $complete_filename, $source, FTP_BINARY);
- if (!$put_file) {
- _backup_migrate_message('FTP Error: Couldn\'t write to @complete_filename when trying to save file on the ftp server.', array('@complete_filename' => $complete_filename), 'error');
- return FALSE;
- }
-
- // Everything worked OK
- return TRUE;
- }
- else {
- _backup_migrate_message('FTP Error: Couldn\'t find @file.', array('@file'), 'error');
- return FALSE;
- }
-}
-
-/**
- * The drupal_ftp_change_directory Function
- * This function simply changes into the $directory folder on the FTP server.
- * If a connection or permission error occurs then _backup_migrate_message() will contain the error message.
- */
-function drupal_ftp_change_directory($directory, &$ftp) {
- // Switch to another directory on the web server. If we don't
- // have permissions then an error will occur
-
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- // Try and change into another directory
- $chdir = ftp_chdir($ftp->__conn, $directory);
-
- if (!$chdir) {
- _backup_migrate_message('FTP Error: Couldn\'t change into directory: @directory', array('@directory', $directory), 'error');
- return FALSE;
- }
- else {
- // Changing directories worked OK
- return TRUE;
- }
-}
-
-/**
- * The drupal_ftp_file_list Function
- * This function will change into the $directory folder and get a list of files and directories contained in that folder.
- * This function still needs a lot of work, but should work in most cases.
- */
-function drupal_ftp_file_list($directory, &$ftp) {
- // This function will attempt to change into the specified
- // directory and retrieve a list of files as an associative
- // array. This list will include file name, size and date last modified
-
- $file_array = array();
-
- // Can we switch to the desired directory?
- if (!drupal_ftp_change_directory($directory, $ftp)) {
- return FALSE;
- }
-
- // We are in the directory, let's retrieve a list of files
- // This is slower than parsing the raw return values, but it is faster.
- $file_list = ftp_nlist($ftp->__conn, $directory);
-
- // Save the list of files
- if (@is_array($file_list)) {
- // Interate through the array
- foreach ($file_list as $file) {
- $file_array[] = array(
- 'filename' => $file,
- 'filesize' => ftp_size($ftp->__conn, $directory ."/". $file),
- 'filetime' => ftp_mdtm($ftp->__conn, $directory ."/". $file),
- );
- }
- }
- sort($file_array);
- return $file_array;
-}
-
-/**
- * The drupal_ftp_create_directory Function
- * This function tries to make a new directory called $folder_name on the FTP server.
- * If it can create the folder, then the folder is given appropriate rights with the CHMOD command.
- */
-function drupal_ftp_create_directory($folder_name, &$ftp) {
- // Makes a new folder on the web server via FTP
-
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- $create_result = @ftp_mkdir($ftp->__conn, $folder_name);
-
- if ($create_result == TRUE) {
- // Can we change the files permissions?
- $exec_result = @ftp_site($ftp->__conn, 'chmod 0777 '. $folder_name .'/');
-
- if ($exec_result == TRUE) {
- return TRUE;
- }
- else {
- _backup_migrate_message('FTP Error: Couldn\'t set owner permissions on @folder.', array('@folder', $folder_name), 'error');
- return FALSE;
- }
- }
- else {
- _backup_migrate_message('FTP Error: Couldn\'t create new folder @folder.', array('@folder', $folder_name), 'error');
- return FALSE;
- }
-}
-
-/**
- * The drupal_ftp_delete_file Function
- * This function attempts to delete a file called $filename from the FTP server.
- */
-function drupal_ftp_delete_file($filename, &$ftp) {
- // Remove the specified file from the FTP server
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- $delete_result = @ftp_delete($ftp->__conn, $filename);
-
- if ($delete_result == TRUE) {
- // The file/folder was renamed successfully
- return TRUE;
- }
- else {
- // Couldn't delete the selected file
- _backup_migrate_message('FTP Error: Couldn\'t delete the selected file: @filename', array('@filename' => $filename), 'error');
- return FALSE;
- }
-}
-
-/**
- * The drupal_ftp_delete_folder Function
- * This function was one of the hardest to write. It recursively deletes all files and folders from a directory called $folder_name.
- */
-function drupal_ftp_delete_folder($folder_name, &$ftp) {
- if (!@drupal_ftp_connect($ftp)) {
- return FALSE;
- }
-
- @ftp_chdir($ftp->__conn, $folder_name);
- $location = @ftp_pwd($ftp->__conn);
-
- $directories = array();
- $files = array();
- $dir_counter = 0;
- $file_counter = 0;
- $content = @ftp_nlist($ftp->__conn, ".");
-
- for ($i = 0; $i < sizeof($content); $i++) {
- // If we can change into this then it's a directory.
- // If not, it's a file
- if ($content[$i] != "." && $content[$i] != "..") {
- if (@ftp_chdir($ftp->__conn, $content[$i])) {
- // We have a directory
- $directories[] = $content[$i];
- $dir_counter++;
- @ftp_cdup($ftp->__conn);
- }
- else {
- // We have a file
- $files[] = $content[$i];
- $file_counter++;
- }
- }
- }
-
- for ($j = 0; $j < $file_counter; $j++) {
- @ftp_delete($ftp->__conn, $files[$j]);
- }
-
- for ($j = 0; $j < $dir_counter; $j++) {
- if ($directories[$j] != "." OR $directories[$j] != "..") {
- $location = ftp_pwd($ftp->__conn);
- drupal_ftp_delete_folder($directories[$j], $ftp);
- @ftp_cdup ($ftp->__conn);
- @ftp_rmdir($ftp->__conn, $directories[$j]);
- }
- }
-
- // Lastly, we change into the directory that we want to delete and see
- // if we can cdup. If we can, we delete it.
- @ftp_chdir($ftp->__conn, $folder_name);
- @ftp_cdup($ftp->__conn);
- @ftp_rmdir($ftp->__conn, $folder_name);
-
- // Did the recursive folder/file deletion work?
- return TRUE;
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.inc
deleted file mode 100644
index 93b27c25..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.inc
+++ /dev/null
@@ -1,1170 +0,0 @@
- array(
- 'description' => t('!link is the cloud backup service by the maintainers of Backup and Migrate.', array('!link' => l(t('NodeSquirrel'), 'http://nodesquirrel.com'))),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.nodesquirrel.inc',
- 'class' => 'backup_migrate_destination_nodesquirrel',
- 'type_name' => t('NodeSquirrel.com'),
- 'can_create' => TRUE,
- ),
- );
- }
- if (variable_get('backup_migrate_allow_backup_to_file', TRUE)) {
- $out += array(
- 'file' => array(
- 'description' => t('Save the backup files to any local directory the web server can write to.'),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.file.inc',
- 'class' => 'backup_migrate_destination_files',
- 'type_name' => t('Server Directory'),
- 'can_create' => TRUE,
- ),
- 'file_manual' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.file.inc',
- 'type_name' => t('Server Directory'),
- 'class' => 'backup_migrate_destination_files_manual',
- ),
- 'file_scheduled' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.file.inc',
- 'type_name' => t('Server Directory'),
- 'class' => 'backup_migrate_destination_files_scheduled',
- ),
- );
- }
- $out += array(
- 'browser_download' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.browser.inc',
- 'class' => 'backup_migrate_destination_browser_download',
- ),
- 'browser_upload' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.browser.inc',
- 'class' => 'backup_migrate_destination_browser_upload',
- ),
- 'db' => array(
- 'type_name' => t('Database'),
- 'description' => t('Import the backup directly into another database. Database destinations can also be used as a source to backup from.'),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.db.inc',
- 'class' => 'backup_migrate_destination_db',
- 'can_create' => FALSE,
- ),
- 'mysql' => array(
- 'type_name' => t('MySQL Database'),
- 'description' => t('Import the backup directly into another MySQL database. Database destinations can also be used as a source to backup from.'),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.db.mysql.inc',
- 'class' => 'backup_migrate_destination_db_mysql',
- 'can_create' => TRUE,
- ),
- 'ftp' => array(
- 'description' => t('Save the backup files to any a directory on an FTP server.'),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.ftp.inc',
- 'class' => 'backup_migrate_destination_ftp',
- 'type_name' => t('FTP Directory'),
- 'can_create' => TRUE,
- ),
- 's3' => array(
- 'description' => t('Save the backup files to a bucket on your !link.', array('!link' => l(t('Amazon S3 account'), 'http://aws.amazon.com/s3/'))),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.s3.inc',
- 'class' => 'backup_migrate_destination_s3',
- 'type_name' => t('Amazon S3 Bucket'),
- 'can_create' => TRUE,
- ),
- 'email' => array(
- 'type_name' => t('Email'),
- 'description' => t('Send the backup as an email attachment to the specified email address.'),
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/destinations.email.inc',
- 'class' => 'backup_migrate_destination_email',
- 'can_create' => TRUE,
- ),
- );
-
- return $out;
-}
-
-/**
- * Implementation of hook_backup_migrate_destinations().
- *
- * Get the built in backup destinations and those in the db.
- */
-function backup_migrate_backup_migrate_destinations() {
- $out = array();
-
- // Add the default, out of the box destinations for new users.
- if (variable_get('backup_migrate_allow_backup_to_file', TRUE)) {
- if (variable_get('file_private_path', FALSE)) {
- $out['manual'] = backup_migrate_create_destination('file_manual', array('destination_id' => 'manual'));
- $out['scheduled'] = backup_migrate_create_destination('file_scheduled', array('destination_id' => 'scheduled'));
- }
- else {
- _backup_migrate_message('You must specify a private file system path in the !settings to backup to the server.', array('!settings' => l(t('file system settings'), 'admin/config/media/file-system')), 'warning');
- }
- }
- // Add the browser destination for downloading to the desktop.
- if (variable_get('backup_migrate_allow_backup_to_download', TRUE)) {
- $out['download'] = backup_migrate_create_destination('browser_download');
- }
- $out['upload'] = backup_migrate_create_destination('browser_upload');
-
- if ($secret_key = variable_get('nodesquirrel_secret_key', '')) {
- $out['nodesquirrel'] = backup_migrate_create_destination('nodesquirrel', array('destination_id' => 'nodesquirrel'));
- $out['nodesquirrel']->settings['secret_key'] = $secret_key;
- }
-
- // Expose the configured databases as sources.
- backup_migrate_include('filters');
- $out += backup_migrate_filters_invoke_all('destinations');
-/*
- global $db_url;
- $urls = is_array($db_url) ? $db_url : array('default' => $db_url);
- foreach ((array)$urls as $key => $url) {
- // Only mysql is currently supported. If more DBMs's are implemented, theis will need to be abstacted.
- if (strpos($url, 'mysql') === 0) {
- if ($destination = backup_migrate_create_destination('mysql', array('url' => $url))) {
- // Treat the default database differently because it is probably the only one available.
- if ($key == 'default') {
- $destination->set_id('db');
- $destination->set_name(t('Default Database'));
- // Dissalow backing up to the default database because that's confusing and potentially dangerous.
- unset($destination->supported_ops['scheduled backup']);
- unset($destination->supported_ops['manual backup']);
- }
- else {
- $destination->set_id('db:'. $key);
- $destination->set_name($key .": ". $destination->get_display_location());
- }
- $out[$destination->get_id()] = $destination;
- }
- }
- }
-*/
- return $out;
-}
-
-/**
- * Get all the available backup destination.
- *
- * @param $op
- * The operation which will be performed on the destination. Hooks can use this
- * to return only those destinations appropriate for the given op.
- * Options include:
- * 'manual backup' - destinations available for manual backup
- * 'scheduled backup' - destinations available for schedules backup
- * 'list files' - destinations whose backup files can be listed
- * 'restore' - destinations whose files can be restored from
- * 'all' - all available destinations should be returned
- */
-function backup_migrate_get_destinations($op = 'all') {
- static $destinations = NULL;
-
- // Get the list of destinations and cache them locally.
- if ($destinations === NULL) {
- $destinations = backup_migrate_crud_get_items('destination');
- }
-
- // Return all if that's what was asked for.
- if ($op == 'all') {
- return $destinations;
- }
-
- // Return only those destinations which support the given op.
- $out = array();
- foreach ($destinations as $key => $destination) {
- if ($destination->op($op)) {
- $out[$key] = $destination;
- }
- }
- return $out;
-}
-
-/**
- * Get the destination of the given id.
- */
-function backup_migrate_get_destination($id) {
- $destinations = backup_migrate_get_destinations('all');
- return empty($destinations[$id]) ? NULL : $destinations[$id];
-}
-
-/**
- * Create a destination object of the given type with the given params.
- */
-function backup_migrate_create_destination($destination_type, $params = array()) {
- $params['type'] = $destination_type;
- // Create a new dummy destination to call the create method on because the base item create is not static.
- $destination = new backup_migrate_destination();
- return $destination->create($params);
-}
-
-/**
- * Load a file from a destination and return the file info.
- */
-function backup_migrate_destination_get_file($destination_id, $file_id) {
- if ($destination = backup_migrate_get_destination($destination_id)) {
- return $destination->load_file($file_id);
- }
- return NULL;
-}
-
-/**
- * Check if a file exists in the given destination.
- */
-function backup_migrate_destination_file_exists($destination_id, $file_id) {
- if ($destination = backup_migrate_get_destination($destination_id)) {
- return $destination->file_exists($file_id);
- }
- return NULL;
-}
-
-/**
- * Send a file to the destination specified by the settings array.
- */
-function backup_migrate_destination_save_file($file, &$settings) {
- if ($destination = $settings->get_destination()) {
- $file = $destination->save_file($file, $settings);
- return $file;
- }
- return NULL;
-}
-
-/**
- * Delete a file in the given destination.
- */
-function backup_migrate_destination_delete_file($destination_id, $file_id) {
- if ($destination = backup_migrate_get_destination($destination_id)) {
- return $destination->delete_file($file_id);
- }
-}
-
-/**
- * Get the action links for a file on a given destination.
- */
-function _backup_migrate_destination_get_file_links($destination_id, $file_id) {
- $out = array();
- if ($destination = backup_migrate_get_destination($destination_id)) {
- $out = $destination->get_file_links($file_id);
- }
- return $out;
-}
-
-/* UI Menu Callbacks */
-
-/**
- * List the backup files in the given destination.
- */
-function backup_migrate_ui_destination_display_files($destination_id = NULL) {
- drupal_add_css(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.css');
-
- $rows = $sort = array();
- if ($destination = backup_migrate_get_destination($destination_id)) {
- // Refresh the file listing cache if requested.
- if (isset($_GET['refresh'])) {
- $destination->file_cache_clear();
- drupal_goto($_GET['q']);
- }
-
- drupal_set_title(t('@title Files', array('@title' => $destination->get_name())));
- $headers = array(
- array('data' => t('Filename'), 'field' => 'filename'),
- array('data' => t('Date'), 'field' => 'filetime'),
- array('data' => t('Age'), 'field' => 'filetime', 'sort' => 'desc'),
- array('data' => t('Size'), 'field' => 'filesize'),
- );
-
- $sort_order = tablesort_get_order($headers);
- $sort_key = $sort_order['sql'] ? $sort_order['sql'] : 'filetime';
- $sort_dir = tablesort_get_sort($headers) == 'desc' ? SORT_DESC : SORT_ASC;
-
- $files = $destination->list_files();
-
- $i = 0;
- $ops = 0;
- foreach ((array)$files as $file) {
- $info = $file->info();
- $operations = $destination->get_file_links($file->file_id());
-
- $description = '';
- // Add the description as a new row.
- if (!empty($info['description'])) {
- $description = ' '. $info['description'] .'
';
- }
-
- // Show only files that can be restored from.
- if ($file->is_recognized_type()) {
- $sort[] = $info[$sort_key];
- $rows[] = array_merge(array(
- check_plain($info['filename']) . $description,
- format_date($info['filetime'], 'small'),
- format_interval(time() - $info['filetime'], 1),
- format_size($info['filesize']),
- ), $operations);
- }
- $ops = max($ops, count($operations));
- }
-
- // Add the operations if any
- if ($ops) {
- $headers[] = array('data' => t('Operations'), 'colspan' => $ops);
- }
-
- array_multisort($sort, $sort_dir, $rows);
-
- if ($rows) {
- $out = theme('table', array('header' => $headers, 'rows' => $rows));
- }
- else {
- $out = t('There are no backup files to display.');
- }
- if ($destination->cache_files && $destination->fetch_time) {
- drupal_add_css(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.css');
- $out .= ''. t('This listing was fetched !time ago. !refresh', array('!time' => format_interval(time() - $destination->fetch_time, 1), '!refresh' => l(t('fetch now'), $_GET['q'], array('query' => array('refresh' => 'true'))))) .'
';
- }
- return $out;
- }
- drupal_goto(BACKUP_MIGRATE_MENU_PATH . "/destination");
-}
-
-/**
- * Download a file to the browser.
- */
-function backup_migrate_ui_destination_download_file($destination_id = NULL, $file_id = NULL) {
- if ($file = backup_migrate_destination_get_file($destination_id, $file_id)) {
- backup_migrate_include('files');
- $file->transfer();
- }
- drupal_goto(BACKUP_MIGRATE_MENU_PATH);
-}
-
-/**
- * Restore a backup file from a destination.
- */
-function backup_migrate_ui_destination_restore_file($destination_id = NULL, $file_id = NULL) {
- if (backup_migrate_destination_file_exists($destination_id, $file_id)) {
- return drupal_get_form('backup_migrate_ui_destination_restore_file_confirm', $destination_id, $file_id);
- }
- drupal_goto(user_access('access backup files') ? BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id : BACKUP_MIGRATE_MENU_PATH);
-}
-
-/**
- * Ask confirmation for file restore.
- */
-function backup_migrate_ui_destination_restore_file_confirm($form, &$form_state, $destination_id, $file_id) {
- $sources = _backup_migrate_get_destination_form_item_options('source');
- if (count($sources) > 1) {
- $form['source_id'] = array(
- "#type" => "select",
- "#title" => t("Database"),
- "#options" => _backup_migrate_get_destination_form_item_options('source'),
- "#description" => t("Choose the database to restore to. Any database destinations you have created and any databases specified in your settings.php can be restored to."),
- "#default_value" => 'db',
- );
- }
- else {
- $form['source_id'] = array(
- "#type" => "value",
- "#value" => 'db',
- );
- }
-
- $form['destination_id'] = array('#type' => 'value', '#value' => $destination_id);
- $form['file_id'] = array('#type' => 'value', '#value' => $file_id);
- $form = confirm_form($form, t('Are you sure you want to restore the database?'), BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id, t('Are you sure you want to restore the database from the backup file %file_id? This will delete some or all of your data and cannot be undone. Always test your backups on a non-production server! ', array('%file_id' => $file_id)), t('Restore'), t('Cancel'));
- drupal_set_message(t('Restoring will delete some or all of your data and cannot be undone. Always test your backups on a non-production server! '), 'warning', FALSE);
- $form = array_merge_recursive($form, backup_migrate_filters_settings_form(backup_migrate_filters_settings_default('restore'), 'restore'));
- $form['actions']['#weight'] = 100;
-
- // Add the advanced fieldset if there are any fields in it.
- if (@$form['advanced']) {
- $form['advanced']['#type'] = 'fieldset';
- $form['advanced']['#title'] = t('Advanced Options');
- $form['advanced']['#collapsed'] = true;
- $form['advanced']['#collapsible'] = true;
- }
-
- return $form;
-}
-
-/**
- * Do the file restore.
- */
-function backup_migrate_ui_destination_restore_file_confirm_submit($form, &$form_state) {
- $destination_id = $form_state['values']['destination_id'];
- $file_id = $form_state['values']['file_id'];
- if ($destination_id && $file_id) {
- backup_migrate_perform_restore($destination_id, $file_id, $form_state['values']);
- }
- $redir = user_access('access backup files') ? BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id : BACKUP_MIGRATE_MENU_PATH;
- $form_state['redirect'] = $redir;
-}
-
-/**
- * Menu callback to delete a file from a destination.
- */
-function backup_migrate_ui_destination_delete_file($destination_id = NULL, $file_id = NULL) {
- if (backup_migrate_destination_file_exists($destination_id, $file_id)) {
- return drupal_get_form('backup_migrate_ui_destination_delete_file_confirm', $destination_id, $file_id);
- }
- drupal_goto(BACKUP_MIGRATE_MENU_PATH);
-}
-
-/**
- * Ask confirmation for file deletion.
- */
-function backup_migrate_ui_destination_delete_file_confirm($form, &$form_state, $destination_id, $file_id) {
- $form['destination_id'] = array('#type' => 'value', '#value' => $destination_id);
- $form['file_id'] = array('#type' => 'value', '#value' => $file_id);
- return confirm_form($form, t('Are you sure you want to delete the backup file?'), BACKUP_MIGRATE_MENU_PATH . '/destination/list/files/'. $destination_id, t('Are you sure you want to delete the backup file %file_id? This action cannot be undone. ', array('%file_id' => $file_id)), t('Delete'), t('Cancel'));
-}
-
-/**
- * Delete confirmed, perform the delete.
- */
-function backup_migrate_ui_destination_delete_file_confirm_submit($form, &$form_state) {
- if (user_access('delete backup files')) {
- $destination_id = $form_state['values']['destination_id'];
- $file_id = $form_state['values']['file_id'];
- backup_migrate_destination_delete_file($destination_id, $file_id);
- _backup_migrate_message('Database backup file deleted: %file_id', array('%file_id' => $file_id));
- }
- $form_state['redirect'] = user_access('access backup files') ? BACKUP_MIGRATE_MENU_PATH . "/destination/list/files/". $destination_id : BACKUP_MIGRATE_MENU_PATH;
-}
-
-/* Utilities */
-
-/**
- * Get the source options as a form element.
- */
-function _backup_migrate_get_source_form($source_id = 'db') {
- backup_migrate_include('destinations');
-
- $form = array();
- $sources = _backup_migrate_get_source_pulldown($source_id);
- if (count($sources['#options']) > 1) {
- $form['source'] = array(
- "#type" => "fieldset",
- "#title" => t("Backup Source"),
- "#collapsible" => TRUE,
- "#collapsed" => FALSE,
- "#tree" => FALSE,
- );
- $sources['#description'] = t("Choose the database to backup. Any database destinations you have created and any databases specified in your settings.php can be backed up.");
-
- $form['source']['source_id'] = $sources;
- }
- else {
- $form = array();
- $form['source']['source_id'] = array(
- "#type" => "value",
- "#value" => $source_id,
- );
- }
- return $form;
-}
-
-/**
- * Get pulldown to select existing source options.
- */
-function _backup_migrate_get_source_pulldown($source_id = NULL) {
- backup_migrate_include('destinations');
- $sources = _backup_migrate_get_destination_form_item_options('source');
- $form = array(
- "#type" => "select",
- "#title" => t("Backup Source"),
- "#options" => _backup_migrate_get_destination_form_item_options('source'),
- "#default_value" => $source_id,
- );
- return $form;
-}
-
-/**
- * Get the destination options as an options array for a form item.
- */
-function _backup_migrate_get_destination_form_item_options($op) {
- $out = array();
- foreach (backup_migrate_get_destinations($op) as $key => $destination) {
- $out[$key] = $destination->get_name();
- }
- return $out;
-}
-
-/**
- * A base class for creating destinations.
- */
-class backup_migrate_destination extends backup_migrate_item {
- var $db_table = "backup_migrate_destinations";
- var $type_name = "destination";
- var $default_values = array('settings' => array());
- var $singular = 'destination';
- var $plural = 'destinations';
- var $cache_files = FALSE;
- var $fetch_time = NULL;
- var $cache_expire = 86400; // 24 hours
-
- var $destination_type = "";
- var $supported_ops = array();
-
- /**
- * This function is not supposed to be called. It is just here to help the po extractor out.
- */
- function strings() {
- // Help the pot extractor find these strings.
- t('Destination');
- t('Destinations');
- t('destinations');
- t('destination');
- }
-
- function ops() {
- return $this->supported_ops;
- }
-
- /**
- * Does this destination support the given operation.
- */
- function op($op) {
- $ops = (array)$this->ops();
- return in_array($op, $ops);
- }
-
- /**
- * Remove the given op from the support list.
- */
- function remove_op($op) {
- $key = array_search($op, $this->supported_ops);
- if ($key !== FALSE) {
- unset($this->supported_ops[$key]);
- }
- }
-
- function get_name() {
- return @$this->name;
- }
-
- function set_name($name) {
- return $this->name = $name;
- }
-
- function set_type($type) {
- $this->type = $type;
- }
-
- function set_location($location) {
- $this->location = $location;
- }
-
- function get_location() {
- return @$this->location;
- }
-
- function get_display_location() {
- return $this->get_location();
- }
-
- function file_types() {
- return array();
- }
-
- function settings($key = NULL) {
- $out = $this->settings;
- if ($key) {
- $out = isset($out[$key]) ? $out[$key] : NULL;
- }
- return $out;
- }
-
- /**
- * Get the type name of this destination for display to the user.
- */
- function get_destination_type_name() {
- if ($type = $this->destination_type) {
- $types = backup_migrate_get_destination_types();
- return isset($types[$type]['type_name']) ? $types[$type]['type_name'] : $type;
- }
- }
-
- /**
- * Save the given file to the destination.
- */
- function save_file($file, $settings) {
- // This must be overriden.
- $this->file_cache_clear();
-
- // Save the file metadata if the destination supports it.
- $this->save_file_info($file, $settings);
- return $this->_save_file($file, $settings);
- }
-
- /**
- * Save the given file to the destination.
- */
- function _save_file($file, $settings) {
- // This must be overriden.
- return $file;
- }
-
- /**
- * Save the file metadata
- */
- function save_file_info($file, $settings) {
- $info = $this->create_info_file($file);
- // Save the info file and the actual file.
- return $this->_save_file($info, $settings);
- }
-
- /**
- * Load the file with the given destination specific id and return as a backup_file object.
- */
- function load_file($file_id) {
- // This must be overriden.
- return NULL;
- }
-
- /**
- * Check if a file exists in the given destination.
- */
- function file_exists($file_id) {
- // Check if the file exists in the list of available files. Actual destination types may have more efficient ways of doing this.
- $files = $this->list_files();
- return isset($files[$file_id]);
- }
-
- /**
- * List all the available files in the given destination with their destination specific id.
- */
- function list_files() {
- $out = NULL;
- if ($this->cache_files) {
- $out = $this->file_cache_get();
- }
- if ($out === NULL) {
- $out = $this->_list_files();
- $out = $this->load_files_info($out);
- if ($this->cache_files) {
- $this->file_cache_set($out);
- }
- }
- return $out;
- }
-
- /**
- * List all the available files in the given destination with their destination specific id.
- */
- function _list_files() {
- return array();
- }
-
- /**
- * Load up the file's metadata from the accompanying .info file if applicable.
- */
- function load_files_info($files) {
- foreach ($files as $key => $file) {
- if (isset($files[$key . '.info'])) {
- // See if there is an info file with the same name as the backup.
- $info = drupal_parse_info_file($files[$key . '.info']->filepath());
- // Allow the stored metadata to override the detected metadata.
- $file->file_info = $info + $file->file_info;
- // Remove the metadata file from the list
- unset($files[$key . '.info']);
- }
- }
-
- return $files;
- }
-
- /**
- * Create an ini file and write the meta data.
- */
- function create_info_file($file) {
- $info = $this->_file_info_file($file);
- $data = _backup_migrate_array_to_ini($file->file_info);
- $info->put_contents($data);
- return $info;
- }
-
- /**
- * Create the info file object.
- */
- function _file_info_file($file) {
- $info = new backup_file(array('filename' => $this->_file_info_filename($file->file_id())));
- return $info;
- }
-
- /**
- * Determine the file name of the info file for a file.
- */
- function _file_info_filename($file_id) {
- return $file_id . '.info';
- }
-
- /**
- * Cache the file list.
- */
- function file_cache_set($files) {
- cache_set('backup_migrate_file_list:'. $this->get_id(), $files, 'cache', time() + $this->cache_expire);
- }
-
- /**
- * Retrieve the file list.
- */
- function file_cache_get() {
- backup_migrate_include('files');
- $cache = cache_get('backup_migrate_file_list:'. $this->get_id());
- if (!empty($cache->data) && $cache->created > (time() - $this->cache_expire)) {
- $this->fetch_time = $cache->created;
- return $cache->data;
- }
- $this->fetch_time = 0;
- return NULL;
- }
-
- /**
- * Retrieve the file list.
- */
- function file_cache_clear() {
- if ($this->cache_files) {
- $this->file_cache_set(NULL);
- }
- }
-
- /**
- * Delete the file with the given destination specific id.
- */
- function delete_file($file_id) {
- $this->file_cache_clear();
- $this->_delete_file($file_id);
- $this->_delete_file($this->_file_info_filename($file_id));
- }
-
- /**
- * Delete the file with the given destination specific id.
- */
- function _delete_file($file_id) {
- // This must be overriden.
- }
-
- /**
- * Get the edit form for the item.
- */
- function edit_form() {
- if (get_class($this) !== 'backup_migrate_destination') {
- $form = parent::edit_form();
- $form['name'] = array(
- "#type" => "textfield",
- "#title" => t("Destination name"),
- "#default_value" => $this->get_name(),
- "#required" => TRUE,
- );
- $form['type'] = array(
- "#type" => "value",
- "#default_value" => $this->destination_type,
- );
- }
- else {
- $types = backup_migrate_get_destination_types();
- $items = array();
- // If no (valid) node type has been provided, display a node type overview.
- foreach ($types as $key => $type) {
- if (@$type['can_create']) {
- $type_url_str = str_replace('_', '-', $key);
- $out = ''. l($type['type_name'], BACKUP_MIGRATE_MENU_PATH . "/destination/list/add/$type_url_str", array('attributes' => array('title' => t('Add a new @s destination.', array('@s' => $type['type_name']))))) .' ';
- $out .= ''. filter_xss_admin($type['description']) .' ';
- $items[] = $out;
- }
- }
- if (count($items)) {
- $output = t('Choose the type of destination you would like to create:') .''. implode('', $items) .' ';
- }
- else {
- $output = t('No destination types available.');
- }
- $form['select_type'] = array(
- '#type' => 'markup',
- '#markup' => $output,
- );
- }
- return $form;
- }
-
- /**
- * Get the message to send to the user when confirming the deletion of the item.
- */
- function delete_confirm_message() {
- return t('Are you sure you want to delete the destination %name? Backup files already saved to this destination will not be deleted.', array('%name' => $this->get_name()));
- }
-
-
- /**
- * Get the columns needed to list the type.
- */
- function get_list_column_info() {
- $out = parent::get_list_column_info();
- $out = array(
- 'name' => array('title' => t('Name')),
- 'destination_type_name' => array('title' => t('Type')),
- 'display_location' => array('title' => t('Location')),
- ) + $out;
- return $out;
- }
-
- /**
- * Get a row of data to be used in a list of items of this type.
- */
- function get_list_row() {
- $out = parent::get_list_row();
-
- // Supress destinations with no actions as there's no value in showing them (and they may confuse new users).
- if (empty($out['actions'])) {
- return NULL;
- }
- return $out;
- }
-
- /**
- * Get the action links for a destination.
- */
- function get_action_links() {
- $out = parent::get_action_links();
- $item_id = $this->get_id();
-
- // Don't display the download/delete/restore ops if they are not available for this destination.
- if ($this->op('list files') && user_access("access backup files")) {
- $out = array('list files' => l(t("list files"), BACKUP_MIGRATE_MENU_PATH . "/$this->type_name/list/files/". $item_id)) + $out;
- }
- if (!$this->op('configure') || !user_access('administer backup and migrate')) {
- unset($out['edit']);
- }
- return $out;
- }
-
- /**
- * Get the action links for a file on a given destination.
- */
- function get_file_links($file_id) {
- $out = array('download' => '', 'restore' => '', 'delete' => '');
-
- // Don't display the download/delete/restore ops if they are not available for this destination.
- $can_read = $this->can_read_file($file_id);
- $can_delete = $this->can_delete_file($file_id);
-
- $destination_id = $this->get_id();
- if ($can_read && user_access("access backup files")) {
- $out['download'] = l(t("download"), BACKUP_MIGRATE_MENU_PATH . "/destination/downloadfile/". $destination_id .'/'. $file_id);
- }
- if ($can_read && user_access("restore from backup")) {
- $out['restore'] = l(t("restore"), BACKUP_MIGRATE_MENU_PATH . "/destination/restorefile/". $destination_id .'/'. $file_id);
- }
- if ($can_delete && user_access("delete backup files")) {
- $out['delete'] = l(t("delete"), BACKUP_MIGRATE_MENU_PATH . "/destination/deletefile/". $destination_id .'/'. $file_id);
- }
- return $out;
- }
-
- /**
- * Determine if we can read the given file.
- */
- function can_read_file($file_id) {
- return $this->op('restore');
- }
-
- /**
- * Determine if we can read the given file.
- */
- function can_delete_file($file_id) {
- return $this->op('delete');
- }
-
- /**
- * Get the form for the settings for this destination type.
- */
- function settings_default() {
- return array();
- }
-
- /**
- * Get the form for the settings for this destination.
- */
- function settings_form($form) {
- return $form;
- }
-
- /**
- * Validate the form for the settings for this destination.
- */
- function settings_form_validate($form_values) {
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function settings_form_submit($form_values) {
- return $form_values;
- }
-
-
- /**
- * Create a new destination of the correct type.
- */
- function create($params = array()) {
- $out = NULL;
- $types = backup_migrate_get_destination_types();
-
- // Get the type passed in in the params, or if none, check the url for a valid type name.
- // This is to allow new destination type to be specified in the path.
- $destination_type = !empty($params['type']) ? $params['type'] : arg(BACKUP_MIGRATE_MENU_DEPTH + 3);
-
- if ($destination_type && ($type = @$types[$destination_type])) {
- // Include the necessary file if specified by the type.
- if (!empty($type['file'])) {
- require_once './'. $type['file'];
- }
- $out = new $type['class']($params + array('destination_type' => $destination_type));
- }
- if (empty($out)) {
- $out = new backup_migrate_destination();
- }
- return $out;
- }
-
- /**
- * Add the menu items specific to the destination type.
- */
- function get_menu_items() {
- $items = parent::get_menu_items();
- $items[BACKUP_MIGRATE_MENU_PATH . '/destination/list/files'] = array(
- 'title' => 'Destination Files',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('destinations', 'backup_migrate_ui_destination_display_files', TRUE),
- 'access arguments' => array('access backup files'),
- 'type' => MENU_LOCAL_TASK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/destination/deletefile'] = array(
- 'title' => 'Delete File',
- 'description' => 'Delete a backup file',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('destinations', 'backup_migrate_ui_destination_delete_file', TRUE),
- 'access arguments' => array('delete backup files'),
- 'type' => MENU_CALLBACK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/destination/restorefile'] = array(
- 'title' => 'Restore from backup',
- 'description' => 'Restore database from a backup file on the server',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('destinations', 'backup_migrate_ui_destination_restore_file', TRUE),
- 'access arguments' => array('restore from backup'),
- 'type' => MENU_CALLBACK,
- );
- $items[BACKUP_MIGRATE_MENU_PATH . '/destination/downloadfile'] = array(
- 'title' => 'Download File',
- 'description' => 'Download a backup file',
- 'page callback' => 'backup_migrate_menu_callback',
- 'page arguments' => array('destinations', 'backup_migrate_ui_destination_download_file', TRUE),
- 'access arguments' => array('access backup files'),
- 'type' => MENU_CALLBACK,
- );
- return $items;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_default() {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form($settings) {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form_validate($form, &$form_state) {
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function backup_settings_form_submit($form, &$form_state) {
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_default() {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_form($settings) {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_form_validate($form_values) {
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function restore_settings_form_submit($form_values) {
- return $form_values;
- }
-}
-
-/**
- * A base class for creating destinations.
- */
-class backup_migrate_destination_remote extends backup_migrate_destination {
- /**
- * The location is a URI so parse it and store the parts.
- */
- function get_location() {
- return $this->url(FALSE);
- }
-
- /**
- * The location to display is the url without the password.
- */
- function get_display_location() {
- return $this->url(TRUE);
- }
-
- /**
- * Return the location with the password.
- */
- function set_location($location) {
- $this->location = $location;
- $this->set_url($location);
- }
-
- /**
- * Get a url from the parts.
- */
- function url($hide_password = TRUE) {
- return $this->glue_url($this->dest_url, $hide_password);
- }
-
- /**
- * Glue a URLs component parts back into a URL.
- */
- function glue_url($parts, $hide_password = TRUE) {
- // Obscure the password if we need to.
- $parts['pass'] = $hide_password ? "" : $parts['pass'];
-
- // Assemble the URL.
- $out = "";
- $out .= $parts['scheme'] .'://';
- $out .= $parts['user'] ? urlencode($parts['user']) : '';
- $out .= ($parts['user'] && $parts['pass']) ? ":". urlencode($parts['pass']) : '';
- $out .= ($parts['user'] || $parts['pass']) ? "@" : "";
- $out .= $parts['host'];
- $out .= !empty($parts['port']) ? ':'. $parts['port'] : '';
- $out .= "/". $parts['path'];
- return $out;
- }
-
- /**
- * Break a URL into it's component parts.
- */
- function set_url($url) {
- $parts = (array)parse_url($url);
- $parts['user'] = urldecode(@$parts['user']);
- $parts['pass'] = urldecode(@$parts['pass']);
- $parts['path'] = urldecode(@$parts['path']);
- $parts['path'] = ltrim(@$parts['path'], "/");
- $this->dest_url = $parts;
- }
-
- /**
- * Destination configuration callback.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['scheme'] = array(
- "#type" => "value",
- "#title" => t("Scheme"),
- "#default_value" => @$this->dest_url['scheme'] ? $this->dest_url['scheme'] : 'mysql',
- "#required" => TRUE,
-// "#options" => array($GLOBALS['db_type'] => $GLOBALS['db_type']),
- "#weight" => 0,
- );
- $form['host'] = array(
- "#type" => "textfield",
- "#title" => t("Host"),
- "#default_value" => @$this->dest_url['host'] ? $this->dest_url['host'] : 'localhost',
- "#required" => TRUE,
- "#weight" => 10,
- );
- $form['path'] = array(
- "#type" => "textfield",
- "#title" => t("Path"),
- "#default_value" => @$this->dest_url['path'],
- "#required" => TRUE,
- "#weight" => 20,
- );
- $form['user'] = array(
- "#type" => "textfield",
- "#title" => t("Username"),
- "#default_value" => @$this->dest_url['user'],
- "#required" => TRUE,
- "#weight" => 30,
- );
- $form['pass'] = array(
- "#type" => "password",
- "#title" => t("Password"),
- "#default_value" => @$this->dest_url['pass'],
- '#description' => '',
- "#weight" => 40,
- );
- if (@$this->dest_url['pass']) {
- $form['old_password'] = array(
- "#type" => "value",
- "#value" => @$this->dest_url['pass'],
- );
- $form['pass']["#description"] .= t(' You do not need to enter a password unless you wish to change the currently saved password.');
- }
- return $form;
- }
-
- /**
- * Submit the configuration form. Glue the url together and add the old password back if a new one was not specified.
- */
- function edit_form_submit($form, &$form_state) {
- $form_state['values']['pass'] = $form_state['values']['pass'] ? $form_state['values']['pass'] : $form_state['values']['old_password'];
- $form_state['values']['location'] = $this->glue_url($form_state['values'], FALSE);
- parent::edit_form_submit($form, $form_state);
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.nodesquirrel.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.nodesquirrel.inc
deleted file mode 100644
index 1db67100..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.nodesquirrel.inc
+++ /dev/null
@@ -1,713 +0,0 @@
-confirm_destination()) {
- return $destination;
- }
- }
- return FALSE;
-}
-
-/**
- * Get the NS destination for the given key.
- */
-function nodesquirrel_get_destination($secret_key) {
- if ($secret_key) {
- backup_migrate_include('destinations');
- $destination = backup_migrate_create_destination('nodesquirrel', array('destination_id' => 'nodesquirrel'));
- $destination->settings['secret_key'] = $secret_key;
- return $destination;
- }
- return NULL;
-}
-
-/**
- * Get a helper link to activate a site and create a tree.
- */
-function nodesquirrel_get_activate_help_text() {
- $activate_link = nodesquirrel_get_activate_link();
- return array(
- '#type' => 'item',
- '#title' => t('Need a Secret Key?'),
- '#markup' => t('Visit !nodesquirrel.', array('!nodesquirrel' => $activate_link)),
- '#description' => t('Don\'t worry if you don\'t have an account yet. You can create one when you get there.'),
- );
-}
-
-/**
- * Get a helper link to activate a site and create a tree.
- */
-function nodesquirrel_get_activate_link() {
- $activate_link = l('nodesquirrel.com/activate', variable_get('nodesquirrel_activate_url', 'http://manage.nodesquirrel.com/activate'), array('query' => array('url' => url('', array('absolute' => TRUE)), 'email' => variable_get('site_mail', ''), 'configure' => url($_GET['q'], array('absolute' => TRUE)))));
- return $activate_link;
-}
-
-/**
- * Get a helper link to activate a site and create a tree.
- */
-function nodesquirrel_get_manage_link($destination) {
- $url = variable_get('nodesquirrel_manage_url', 'http://manage.nodesquirrel.com') . '/backups/' . $destination->_get_destination();
- return l($url, $url);
-}
-
-/**
- * NodeSquirrel settings form.
- */
-function nodesquirrel_settings($form_state) {
- _backup_migrate_message_callback('_backup_migrate_message_browser');
-
- $form = array();
-
- $key = variable_get('nodesquirrel_secret_key', '');
- $destination = nodesquirrel_check_secret_key($key);
-
- $form['intro'] = array(
- '#type' => 'markup',
- '#markup' => t('For better protection, back your site up regularly to a location not on your web server. !nodesquirrel is the cloud backup service built by the maintainers of Backup and Migrate. You can also !add such as FTP or Amazon S3. Additional 3rd party options are available and many are listed on the !bam.', array('!nodesquirrel' => l(t('NodeSquirrel'), 'http://nodesquirrel.com'), '!add' => l(t('add other offsite destinations'), BACKUP_MIGRATE_MENU_PATH . '/destination/list/add'), '!bam' => l(t('Backup and Migrate project page'), 'http://drupal.org/project/backup_migrate'))),
- );
-
- $form['nodesquirrel_status'] = array(
- '#type' => 'fieldset',
- '#title' => t('NodeSquirrel Status'),
- );
- $form['nodesquirrel_status']['status'] = array(
- '#type' => 'item',
- '#title' => t('NodeSquirrel Status'),
- '#markup' => t('Not Configured'),
- );
-
- // Warn the user if the key they entered is invalid.
- if ($key && empty($destination)) {
- $form['nodesquirrel_status']['status']['#value'] = t('Your secret key does not seem to be valid. Please check that you entered it correctly or visit !ns to generate a new key.', array('!ns' => nodesquirrel_get_activate_link()));
- }
- else if (!empty($destination)) {
- $form['nodesquirrel_status']['manage'] = array(
- '#type' => 'item',
- '#title' => t('Management Console'),
- '#markup' => nodesquirrel_get_manage_link($destination),
- '#description' => t('You can use the NodeSquirrel management console to add and edit your sites, reset your secret key, download and delete backups, and modify your NodeSquirrel account.'),
- );
- $form['nodesquirrel_status']['status']['#markup'] = t('Ready to Backup');
- if (user_access('perform backup')) {
- $form['nodesquirrel_status']['status']['#markup'] .= ' ' . l('(' . t('backup now') . ')', BACKUP_MIGRATE_MENU_PATH);
- }
- }
-
- $form['nodesquirrel_credentials'] = array(
- '#type' => 'fieldset',
- '#title' => t('NodeSquirrel Credentials'),
- );
- $form['nodesquirrel_credentials']['nodesquirrel_secret_key'] = array(
- '#type' => 'textfield',
- '#title' => t('Secret Key'),
- '#size' => 80,
- '#default_value' => variable_get('nodesquirrel_secret_key', ''),
- );
- if (empty($destination)) {
- $form['nodesquirrel_credentials']['secret_key_help'] = nodesquirrel_get_activate_help_text();
- }
-
- // If the schedule has been overriden it must be edited in the schedule tab.
- backup_migrate_include('crud');
- $item = backup_migrate_crud_get_item('schedule', 'nodesquirrel');
- if ($item && $item->storage == BACKUP_MIGRATE_STORAGE_OVERRIDEN) {
- $form['nodesquirrel_schedule']['#options'] = array('' => t('- Overriden -'));
- $form['nodesquirrel_schedule']['#disabled'] = TRUE;
- $form['nodesquirrel_schedule']['#description'] = t('Your NodeSquirrel schedule has been overriden and must be edited in the !schedule.', array('!schedule' => l(t('Schedules tab'), BACKUP_MIGRATE_MENU_PATH . '/schedule/list/edit/nodesquirrel')));
- }
-
- return system_settings_form($form);
-}
-
-/**
- * A destination for sending database backups to the NodeSquirel backup service.
- *
- * @ingroup backup_migrate_destinations
- */
-class backup_migrate_destination_nodesquirrel extends backup_migrate_destination {
- var $supported_ops = array('scheduled backup', 'manual backup', 'restore', 'list files', 'configure', 'delete');
- var $cache_files = TRUE;
- // Don't generate a metadata file as NodeSquirrel can save metadata natively.
- var $save_metadata = FALSE;
-
- /**
- * Get the destination name. Provide a default.
- */
- function get_name() {
- if (empty($this->name)) {
- return t('NodeSquirrel');
- }
- return $this->name;
- }
-
- /**
- * Save to the NodeSquirrel destination.
- */
- function save_file($file, $settings) {
- if ($destination = $this->_get_destination()) {
- srand((double)microtime()*1000000);
-
- $filename = $file->filename();
- $filesize = filesize($file->filepath());
- $ticket = $this->_xmlrpc('backups.getUploadTicket', array($destination, $filename, $filesize, $file->file_info));
-
- if ($ticket) {
-
- $url = $ticket['url'];
-
- // If the ticket requires authentication add our username/password to the url.
- if (!empty($ticket['auth']) && $ticket['auth'] = 'basic') {
- $parts = parse_url($ticket['url']);
- list($parts['user'], $parts['pass']) = $this->get_user_pass();
- $url = $this->glue_url($parts, FALSE);
- }
-
- $out = $this->_post_file($url, 'POST', $ticket['params'], $file);
-
- if ($out->code == 200) {
- // Confirm the upload.
- $confirm = $this->_xmlrpc('backups.confirmUpload', array($destination, $filename, $filesize));
-
- if ($confirm['success']) {
- // Set a message with a link to the manage console.
- $url = variable_get('nodesquirrel_manage_url', 'http://manage.nodesquirrel.com') . '/backups/' . $this->_get_destination();
- _backup_migrate_message('Your backup has been saved to your NodeSquirrel account. View it at !account', array('!account' => l($url, $url)));
-
- return $file;
- }
- else {
- _backup_migrate_message('The backup file never made it to the NodeSquirrel backup server. There may have been a network problem. Please try again later');
- }
- }
- else {
- $error = !empty($out->headers['x-bams-error']) ? $out->headers['x-bams-error'] : $out->error;
- _backup_migrate_message('The NodeSquirrel server returned the following error: %err', array('%err' => $error), 'error');
- }
- }
- else if ($err = xmlrpc_error()) {
- // XMLRPC errors are already handled by the server function below.
- }
- else {
- _backup_migrate_message('The NodeSquirrel server refused the backup but did not specify why. Maybe the server is down.');
- }
- }
- return NULL;
- }
-
- /**
- * Load from the NodeSquirrel destination.
- */
- function load_file($file_id) {
- if ($destination = $this->_get_destination()) {
- backup_migrate_include('files');
- $file = new backup_file(array('filename' => $file_id));
-
- $ticket = $this->_xmlrpc('backups.getDownloadTicket', array($destination, $file_id));
-
- if ($ticket && $url = $ticket['url']) {
- // If the ticket requires authentication add our username/password to the url.
- if (!empty($ticket['auth']) && $ticket['auth'] = 'basic') {
- $parts = parse_url($ticket['url']);
- $parts['user'] = @$this->dest_url['user'];
- $parts['pass'] = @$this->dest_url['pass'];
- $url = $this->glue_url($parts, FALSE);
- }
-
- $out = drupal_http_request($url);
-
- if ($out->code == 200) {
- file_put_contents($file->filepath(), $out->data);
- return $file;
- }
- else {
- $error = !empty($out->headers['x-bams-error']) ? $out->headers['x-bams-error'] : $out->error;
- _backup_migrate_message('The server returned the following error: %err', array('%err' => $error), 'error');
- }
- }
- }
- return NULL;
- }
-
- /**
- * Delete from the NodeSquirrel destination.
- */
- function delete_file($file_id) {
- if ($destination = $this->_get_destination()) {
- $result = $this->_xmlrpc('backups.deleteFile', array($destination, $file_id));
- }
- }
-
- /**
- * List the files in the remote destination.
- */
- function _list_files() {
- $files = array();
- backup_migrate_include('files');
-
- if ($destination = $this->_get_destination()) {
- $file_list = $this->_xmlrpc('backups.listFiles', array($destination));
- foreach ((array)$file_list as $file) {
- $files[$file['filename']] = new backup_file($file);
- }
- }
-
- return $files;
- }
-
- /**
- * List the files in the remote destination.
- */
- function check_limits() {
- if (empty($this->limits)) {
- $this->limits = $this->_xmlrpc('backups.getLimits', array($this->_get_destination()));
- }
- return $this->limits;
- }
-
- /**
- * Check that a destination is valid.
- */
- function confirm_destination() {
- return $this->check_limits();
- }
-
- /**
- * Get the form for the settings for this destination.
- */
- function edit_form() {
- $form = parent::edit_form();
-
- $form['settings'] = array('#tree' => TRUE);
- $activate_link = l('nodesquirrel.com/activate', variable_get('nodesquirrel_activate_url', 'http://manage.nodesquirrel.com/activate'), array('query' => array('url' => url('', array('absolute' => TRUE)), 'email' => variable_get('site_mail', ''), 'configure' => url($_GET['q'], array('absolute' => TRUE)))));
-
- // Retrieve the key from the settings or get it from the get string if this is an auto-config action.
- $key = $this->settings('secret_key');
- if (!empty($_GET['key']) && preg_match(NODESQUIRREL_SECRET_KEY_PATTERN, $_GET['key'])) {
- $key = $_GET['key'];
- }
-
- $form['settings']['secret_key'] = array(
- '#type' => 'textfield',
- '#title' => t('Secret Key'),
- '#default_value' => $key,
- );
- $form['settings']['location'] = array('#type' => 'value', '#value' => '');
-
- $form['settings']['secret_key_help'] = array(
- '#type' => 'item',
- '#title' => t('Need a Secret Key?'),
- '#markup' => t('Visit !nodesquirrel.', array('!nodesquirrel' => $activate_link)),
- );
-
- return $form;
- }
-
-
-
- /**
- * Submit the configuration form. Glue the url together and add the old password back if a new one was not specified.
- */
- function edit_form_validate($form, &$form_state) {
- $key = trim($form_state['values']['settings']['secret_key']);
- if ($key) {
- if (!preg_match(NODESQUIRREL_SECRET_KEY_PATTERN, $key)) {
- form_set_error('secret_key', 'The secret key you entered is not the right format. Please make sure you copy it exactly.');
- return;
- }
- $this->settings['secret_key'] = check_plain($key);
-
- $limits = $this->check_limits();
-
- if (!$limits) {
- $err = xmlrpc_error();
- if (!empty($err->code) && $err->code == '401') {
- form_set_error('user', 'Could not login to server. Please check that your secret key is correct.');
- }
- else {
- form_set_error('', 'There was an error retrieving the specified site. Please check that your secret key is correct.');
- }
- }
- }
- }
-
- /**
- * Submit the configuration form. Glue the url together and add the old password back if a new one was not specified.
- */
- function edit_form_submit($form, &$form_state) {
- $form_state['values']['secret_key'] = check_plain($form_state['values']['settings']['secret_key']);
- parent::edit_form_submit($form, $form_state);
- }
-
- /**
- * Get the destination id or warn the user that it has not been set.
- */
- function _get_destination($warn = TRUE) {
- list($id, $key) = $this->get_user_pass();
- return $id;
- }
-
- /**
- * Get the destination id or warn the user that it has not been set.
- */
- function _get_private_key($warn = TRUE) {
- list($id, $key) = $this->get_user_pass();
- return $key;
- }
-
- /**
- * Break the secret key into the public/private key (user/pass).
- */
- function get_user_pass() {
- $key = $this->settings('secret_key');
- // The username is the first 32 chars.
- $user = substr($key, 0, 32);
- // The pass is the last 32 chars. There may be a separating character.
- $pass = substr($key, strlen($key) - 32);
- return array($user, $pass);
- }
-
- function get_display_location() {
- return t('NodeSquirrel.com');
- }
-
- function add_scheme($url) {
- return 'http://' . $url;
- }
-
- /**
- * Get the form for the settings for this destination.
- */
- function _xmlrpc($method, $args = array()) {
- // Retrieve the severs or read them from a stored variable.
- $servers = $this->_get_endpoints();
-
- // Do the actual call.
- return $this->__xmlrpc($method, $args, $servers);
- }
-
- /**
- * Get the form for the settings for this destination.
- */
- function __xmlrpc($method, $args, $servers, $retry = 3) {
- if ($servers && --$retry > 0) {
- // Add the key authentication arguments if we can.
- if ($this->_sign_request($args)) {
- $url = reset($servers);
- // Try each available server in order.
- while ($url) {
-
- $url = $this->add_scheme($url);
-
- $out = xmlrpc($url, array($method => $args));
-
- // Check for errors.
- $err = xmlrpc_error();
- if ($err && $err->is_error) {
- switch ($err->code) {
- case '500':
- case '503':
- case '404':
- // Some sort of server error. Try the next one.
- $url = next($servers);
-
- // If we're at the end of the line then try refetching the urls
- if (!$url) {
- $servers = $this->_get_endpoints(TRUE, $retry);
- return $this->__xmlrpc($method, $args, $servers, $retry);
- }
- break;
- case '300':
- // 'Multiple Choices' means that the existing server list needs to be refreshed.
- $servers = $this->_get_endpoints(TRUE, $retry);
- return $this->__xmlrpc($method, $args, $servers, $retry);
- break;
- case '401':
- case '403':
- // Authentication failed.
- _backup_migrate_message('Couldn\'t log in to NodeSquirrel. The server error was: %err', array('%err' => $err->message), 'error');
- return FALSE;
- break;
- default:
- // Some sort of client error. Don't try the next server because it'll probably say the same thing.
- _backup_migrate_message('The NodeSquirrel server returned the following error: %err', array('%err' => $err->message), 'error');
- return FALSE;
- break;
- }
- }
- // No error, return the result.
- else {
- return $out;
- }
- }
- }
- }
- }
-
- /**
- * Genrate a hash with a given secret key, timestamp and random value.
- */
- function _get_hash($time, $nonce) {
- if ($private_key = $this->_get_private_key()) {
- $message = $time . ':' . $nonce . ':' . $private_key;
- // Use HMAC-SHA1 to authenticate the call.
- $hash = base64_encode(
- pack('H*', sha1((str_pad($private_key, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
- pack('H*', sha1((str_pad($private_key, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) .
- $message))))
- );
- return $hash;
- }
- _backup_migrate_message('You must enter a valid private key to use NodeSquirrel.', array(), 'error');
- return FALSE;
- }
-
- /**
- * Genrate a hash with a given secret key, timestamp and random value.
- */
- function _sign_request(&$args) {
- $nonce = md5(mt_rand());
- $time = time();
- $hash = $this->_get_hash($time, $nonce);
- if ($hash) {
- array_unshift($args, $nonce);
- array_unshift($args, $time);
- array_unshift($args, $hash);
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- /**
- * Retrieve the list of servers.
- */
- function _get_endpoints($refresh = FALSE, $retry = 3) {
- $servers = (array)variable_get('nodesquirrel_endpoint_urls', array());
-
- // No servers saved or a force refreshr required.
- if ($refresh || empty($servers)) {
- $servers = array_unique(array_merge($servers, variable_get('nodesquirrel_default_endpoint_urls', array('api.nodesquirrel.com/services/xmlrpc'))));
- // Call the get endpoints method but use the default or previous servers to avoid infinite loops.
- $new_servers = $this->__xmlrpc('backups.getEndpoints', array($this->_get_destination(), 'xmlrpc'), $servers, $retry);
- if ($new_servers) {
- variable_set('nodesquirrel_endpoint_urls', $new_servers);
- $servers = $new_servers;
- }
- }
- return $servers;
- }
-
- /**
- * Post a file via http.
- *
- * This looks a lot like a clone of drupal_http_request but it can post a large
- * file without reading the whole file into memory.
- */
- function _post_file($url, $method = 'GET', $params = array(), $file = NULL, $retry = 3) {
- global $db_prefix;
-
- $result = new stdClass();
-
- // Parse the URL and make sure we can handle the schema.
- $uri = parse_url($url);
-
- if ($uri == FALSE) {
- $result->error = 'unable to parse URL';
- $result->code = -1001;
- return $result;
- }
-
- if (!isset($uri['scheme'])) {
- $result->error = 'missing schema';
- $result->code = -1002;
- return $result;
- }
-
- switch ($uri['scheme']) {
- case 'http':
- case 'feed':
- $port = isset($uri['port']) ? $uri['port'] : 80;
- $host = $uri['host'] . ($port != 80 ? ':'. $port : '');
- $fp = @fsockopen($uri['host'], $port, $errno, $errstr, 15);
- break;
- case 'https':
- // Note: Only works for PHP 4.3 compiled with OpenSSL.
- $port = isset($uri['port']) ? $uri['port'] : 443;
- $host = $uri['host'] . ($port != 443 ? ':'. $port : '');
- $fp = @fsockopen('ssl://'. $uri['host'], $port, $errno, $errstr, 20);
- break;
- default:
- $result->error = 'invalid schema '. $uri['scheme'];
- $result->code = -1003;
- return $result;
- }
-
- // Make sure the socket opened properly.
- if (!$fp) {
- // When a network error occurs, we use a negative number so it does not
- // clash with the HTTP status codes.
- $result->code = -$errno;
- $result->error = trim($errstr);
-
- // Mark that this request failed. This will trigger a check of the web
- // server's ability to make outgoing HTTP requests the next time that
- // requirements checking is performed.
- // @see system_requirements()
- variable_set('drupal_http_request_fails', TRUE);
-
- return $result;
- }
-
- // Construct the path to act on.
- $path = isset($uri['path']) ? $uri['path'] : '/';
- if (isset($uri['query'])) {
- $path .= '?'. $uri['query'];
- }
-
- // Prepare the data payload.
- $boundary = '---------------------------'. substr(md5(rand(0,32000)),0,10);
- $data_footer = "\r\n--$boundary--\r\n";
-
- $data_header = '';
- foreach ($params as $key => $value) {
- $data_header .="--$boundary\r\n";
- $data_header .= "Content-Disposition: form-data; name=\"".$key."\"\r\n";
- $data_header .= "\r\n".$value."\r\n";
- $data_header .="--$boundary\r\n";
- }
-
- // Add the file header to the post payload.
- $data_header .="--$boundary\r\n";
- $data_header .= "Content-Disposition: form-data; name=\"file\"; filename=\"". $file->filename() ."\"\r\n";
- $data_header .= "Content-Type: application/octet-stream;\r\n";
- $data_header .= "\r\n";
-
- // Calculate the content length.
- $content_length = strlen($data_header . $data_footer) + filesize($file->filepath());
-
- //file_get_contents($file->filepath()));
-
- // Create HTTP request.
- $defaults = array(
- // RFC 2616: "non-standard ports MUST, default ports MAY be included".
- // We don't add the port to prevent from breaking rewrite rules checking the
- // host that do not take into account the port number.
- 'Host' => "Host: $host",
- 'Content-type' => "Content-type: multipart/form-data, boundary=$boundary",
- 'User-Agent' => 'User-Agent: NodeSquirrel Client/1.x (+http://www.nodesquirrel.com) (Drupal '. VERSION .'; Backup and Migrate 2.x)',
- 'Content-Length' => 'Content-Length: '. $content_length
- );
-
- // If the server url has a user then attempt to use basic authentication
- if (isset($uri['user'])) {
- $defaults['Authorization'] = 'Authorization: Basic '. base64_encode($uri['user'] . (!empty($uri['pass']) ? ":". $uri['pass'] : ''));
- }
-
- $request = $method .' '. $path ." HTTP/1.0\r\n";
- $request .= implode("\r\n", $defaults);
- $request .= "\r\n\r\n";
- $result->request = $request;
-
- // Write the headers and start of the headers
- fwrite($fp, $request);
- fwrite($fp, $data_header);
-
- // Copy the file 512k at a time to prevent memory issues.
- if ($fp_in = fopen($file->filepath(), 'rb')) {
- while (!feof($fp_in)) {
- fwrite($fp, fread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- @fclose($fp_in);
-
- // Finish the write.
- fwrite($fp, $data_footer);
-
- // Fetch response.
- $response = '';
- while (!feof($fp) && $chunk = fread($fp, 1024)) {
- $response .= $chunk;
- }
- fclose($fp);
-
- // Parse response.
- list($split, $result->data) = explode("\r\n\r\n", $response, 2);
- $split = preg_split("/\r\n|\n|\r/", $split);
-
- list($protocol, $code, $status_message) = explode(' ', trim(array_shift($split)), 3);
- $result->protocol = $protocol;
- $result->status_message = $status_message;
-
- $result->headers = array();
-
- // Parse headers.
- while ($line = trim(array_shift($split))) {
- list($header, $value) = explode(':', $line, 2);
- if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
- // RFC 2109: the Set-Cookie response header comprises the token Set-
- // Cookie:, followed by a comma-separated list of one or more cookies.
- $result->headers[$header] .= ','. trim($value);
- }
- else {
- $result->headers[$header] = trim($value);
- }
- }
-
- $responses = array(
- 100 => 'Continue', 101 => 'Switching Protocols',
- 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
- 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
- 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
- 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
- );
- // RFC 2616 states that all unknown HTTP codes must be treated the same as the
- // base code in their class.
- if (!isset($responses[$code])) {
- $code = floor($code / 100) * 100;
- }
-
- switch ($code) {
- case 200: // OK
- case 304: // Not modified
- break;
- case 301: // Moved permanently
- case 302: // Moved temporarily
- case 307: // Moved temporarily
- $location = $result->headers['Location'];
-
- if ($retry) {
- $result = drupal_http_request($result->headers['Location'], $headers, $method, $data, --$retry);
- $result->redirect_code = $result->code;
- }
- $result->redirect_url = $location;
-
- break;
- default:
- $result->error = $status_message;
- }
-
- $result->code = $code;
- return $result;
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/destinations.s3.inc b/sites/all/modules/contrib/backup_migrate/includes/destinations.s3.inc
deleted file mode 100644
index 67ee7718..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/destinations.s3.inc
+++ /dev/null
@@ -1,183 +0,0 @@
-s3_object()) {
- $path = $file->filename();
- if ($s3->putObject($s3->inputFile($file->filepath(), FALSE), $this->get_bucket(), $this->remote_path($file->filename()), S3::ACL_PRIVATE)) {
- return $file;
- }
- }
- return FALSE;
- }
-
- /**
- * Load from the s3 destination.
- */
- function load_file($file_id) {
- backup_migrate_include('files');
- $file = new backup_file(array('filename' => $file_id));
- if ($s3 = $this->s3_object()) {
- $data = $s3->getObject($this->get_bucket(), $this->remote_path($file_id), $file->filepath());
- if (!$data->error) {
- return $file;
- }
- }
- return NULL;
- }
-
- /**
- * Delete from the s3 destination.
- */
- function _delete_file($file_id) {
- if ($s3 = $this->s3_object()) {
- $s3->deleteObject($this->get_bucket(), $this->remote_path($file_id));
- }
- }
-
- /**
- * List all files from the s3 destination.
- */
- function _list_files() {
- backup_migrate_include('files');
- $files = array();
- if ($s3 = $this->s3_object()) {
- $s3_files = $s3->getBucket($this->get_bucket(), $this->get_subdir());
- foreach ((array)$s3_files as $id => $file) {
- $info = array(
- 'filename' => $this->local_path($file['name']),
- 'filesize' => $file['size'],
- 'filetime' => $file['time'],
- );
- $files[$info['filename']] = new backup_file($info);
- }
- }
- return $files;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function edit_form() {
- // Check for the library.
- $this->s3_object();
-
- $form = parent::edit_form();
- $form['scheme']['#type'] = 'value';
- $form['scheme']['#value'] = 'https';
- $form['host']['#default_value'] = 's3.amazonaws.com';
-
- $form['path']['#title'] = 'S3 Bucket';
- $form['path']['#default_value'] = $this->get_bucket();
- $form['path']['#description'] = 'This bucket must already exist. It will not be created for you.';
-
- $form['user']['#title'] = 'Access Key ID';
- $form['pass']['#title'] = 'Secret Access Key';
-
- $form['subdir'] = array(
- '#type' => 'textfield',
- '#title' => t('Subdirectory'),
- '#default_value' => $this->get_subdir(),
- '#weight' => 25
- );
- $form['settings']['#weight'] = 50;
-
- return $form;
- }
-
- /**
- * Submit the form for the settings for the s3 destination.
- */
- function edit_form_submit($form, &$form_state) {
- // Append the subdir onto the path.
-
- if (!empty($form_state['values']['subdir'])) {
- $form_state['values']['path'] .= '/'. trim($form_state['values']['subdir'], '/');
- }
- parent::edit_form_submit($form, $form_state);
- }
-
- /**
- * Generate a filepath with the correct prefix.
- */
- function remote_path($path) {
- if ($subdir = $this->get_subdir()) {
- $path = $subdir .'/'. $path;
- }
- return $path;
- }
-
- /**
- * Generate a filepath with the correct prefix.
- */
- function local_path($path) {
- if ($subdir = $this->get_subdir()) {
- $path = str_replace($subdir .'/', '', $path);
- }
- return $path;
- }
-
- /**
- * Get the bucket which is the first part of the path.
- */
- function get_bucket() {
- $parts = explode('/', @$this->dest_url['path']);
- return $parts[0];
- }
-
- /**
- * Get the bucket which is the first part of the path.
- */
- function get_subdir() {
- // Support the older style of subdir saving.
- if ($subdir = $this->settings('subdir')) {
- return $subdir;
- }
- $parts = explode('/', @$this->dest_url['path']);
- array_shift($parts);
- return implode('/', array_filter($parts));
- }
-
- function s3_object() {
- // Try to use libraries module if available to find the path.
- if (function_exists('libraries_get_path')) {
- $library_paths[] = libraries_get_path('s3-php5-curl');
- }
- else {
- $library_paths[] = 'sites/all/libraries/s3-php5-curl';
- }
- $library_paths[] = drupal_get_path('module', 'backup_migrate') . '/includes/s3-php5-curl';
- $library_paths[] = drupal_get_path('module', 'backup_migrate') . '/includes';
-
- foreach($library_paths as $path) {
- if (file_exists($path . '/S3.php')) {
- require_once $path . '/S3.php';
- if (!$this->s3 && !empty($this->dest_url['user'])) {
- $this->s3 = new S3($this->dest_url['user'], $this->dest_url['pass'], FALSE, $this->dest_url['host']);
- }
- return $this->s3;
- }
- }
- drupal_set_message(t('Due to drupal.org code hosting policies, the S3 library needed to use an S3 destination is no longer distributed with this module. You must download the library from !link and place it in one of these locations: %locations.', array('%locations' => implode(', ', $library_paths), '!link' => l('http://undesigned.org.za/2007/10/22/amazon-s3-php-class', 'http://undesigned.org.za/2007/10/22/amazon-s3-php-class'))), 'error', FALSE);
- return NULL;
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/files.inc b/sites/all/modules/contrib/backup_migrate/includes/files.inc
deleted file mode 100644
index d7a61c2a..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/files.inc
+++ /dev/null
@@ -1,452 +0,0 @@
-getDirectoryPath();
- $expire = time() - variable_get('backup_migrate_cleanup_time', 21600);
- if (file_exists($dir) && is_dir($dir) && is_readable($dir) && $handle = opendir($dir)) {
- while (FALSE !== ($file = @readdir($handle))) {
- // Delete 'backup_migrate_' files in the temp directory that are older than the expire time.
- // We should only attempt to delete writable files to prevent errors in shared environments.
- // This could still cause issues in shared environments with poorly configured file permissions.
- if (strpos($file, 'backup_migrate_') === 0 && is_writable("$dir/$file") && @filectime("$dir/$file") < $expire) {
- unlink("$dir/$file");
- }
- }
- closedir($handle);
- }
-}
-
-/**
- * Return a list of backup filetypes.
- */
-function _backup_migrate_filetypes() {
- backup_migrate_include('filters');
-
- $out = backup_migrate_filters_file_types();
-
- foreach ($out as $key => $info) {
- $out[$key]['id'] = empty($info['id']) ? $key : $info['id'];
- }
- return $out;
-}
-
-/**
- * Adjust the length of a filename to allow for a string to be appended,
- * staying within the maximum filename limit.
- */
-function _backup_migrate_filename_append_prepare($filename, $append_str) {
- $max_name_len = BACKUP_MIGRATE_FILENAME_MAXLENGTH - drupal_strlen($append_str);
- if (drupal_strlen($filename) > $max_name_len) {
- $filename = drupal_substr($filename, 0, $max_name_len);
- }
- return $filename;
-}
-
-/**
- * Construct a filename using token and some cleaning.
- */
-function _backup_migrate_construct_filename($filename, $timestamp='') {
- if (module_exists('token')) {
- $filename = token_replace($filename);
- }
- $filename = preg_replace("/[^a-zA-Z0-9\.\-_]/", "", $filename);
- $filename = _backup_migrate_filename_append_prepare($filename, $timestamp);
- $filename .= '-' . $timestamp;
- $filename = trim($filename, '-');
-
- if (drupal_strlen($filename) == 0) {
- $filename = 'untitled';
- }
-
- return $filename;
-}
-
-/**
- * Construct a default filename using the site's name.
- */
-function _backup_migrate_default_filename() {
- if (module_exists('token')) {
- return '[site:name]';
- }
- else {
- // Cleaning the string isn't strictly necessary but it looks better in the settings field.
- return variable_get('site_name', 'backup_migrate');
- }
-}
-
-/**
- * An output buffer callback which simply throws away the buffer instead of sending it to the browser.
- */
-function _backup_migrate_file_dispose_buffer($buffer) {
- return "";
-}
-
-
-/**
- * A backup file which allows for saving to and reading from the server.
- */
-class backup_file {
- var $file_info = array();
- var $type = array();
- var $ext = array();
- var $path = "";
- var $name = "";
- var $handle = NULL;
-
- /**
- * Construct a file object given a file path, or create a temp file for writing.
- */
- function backup_file($params = array()) {
- if (isset($params['filepath']) && file_exists($params['filepath'])) {
- $this->set_filepath($params['filepath']);
- }
- else {
- $this->set_file_info($params);
- $this->temporary_file();
- }
- }
-
- /**
- * Get the file_id if the file has been saved to a destination.
- */
- function file_id() {
- // The default file_id is the filename. Destinations can override the file_id if needed.
- return isset($this->file_info['file_id']) ? $this->file_info['file_id'] : $this->filename();
- }
-
- /**
- * Get the current filepath.
- */
- function filepath() {
- return drupal_realpath($this->path);
- }
-
- /**
- * Get the final filename.
- */
- function filename($name = NULL) {
- if ($name) {
- $this->name = $name;
- }
- return $this->name .'.'. $this->extension();
- }
-
- /**
- * Set the current filepath.
- */
- function set_filepath($path) {
- $this->path = $path;
- $params = array(
- 'filename' => basename($path),
- );
- if (file_exists($path)) {
- $params['filesize'] = filesize($path);
- $params['filetime'] = filectime($path);
- }
- $this->set_file_info($params);
- }
-
- /**
- * Get one or all pieces of info for the file.
- */
- function info($key = NULL) {
- if ($key) {
- return @$this->file_info[$key];
- }
- return $this->file_info;
- }
-
- /**
- * Get the file extension.
- */
- function extension() {
- return implode(".", $this->ext);
- }
-
- /**
- * Get the file type.
- */
- function type() {
- return $this->type;
- }
-
- /**
- * Get the file mimetype.
- */
- function mimetype() {
- return @$this->type['filemime'] ? $this->type['filemime'] : 'application/octet-stream';
- }
-
- /**
- * Get the file mimetype.
- */
- function type_id() {
- return @$this->type['id'];
- }
-
-
- /**
- * Can this file be used to backup to.
- */
- function can_backup() {
- return @$this->type['backup'];
- }
-
- /**
- * Can this file be used to restore to.
- */
- function can_restore() {
- return @$this->type['restore'];
- }
-
- /**
- * Can this file be used to restore to.
- */
- function is_recognized_type() {
- return @$this->type['restore'] || @$this->type['backup'];
- }
-
- /**
- * Open a file for reading or writing.
- */
- function open($write = FALSE, $binary = FALSE) {
- if (!$this->handle) {
- $path = $this->filepath();
-
- // Check if the file can be read/written.
- if ($write && ((file_exists($path) && !is_writable($path)) || !is_writable(dirname($path)))) {
- _backup_migrate_message('The file %path cannot be written to.', array('%path' => $path), 'error');
- return FALSE;
- }
- if (!$write && !is_readable($path)) {
- _backup_migrate_message('The file %path cannot be read.', array('%path' => $path), 'error');
- return FALSE;
- }
-
- // Open the file.
- $mode = ($write ? "w" : "r") . ($binary ? "b" : "");
- $this->handle = fopen($path, $mode);
- return $this->handle;
- }
- return NULL;
- }
-
- /**
- * Close a file when we're done reading/writing.
- */
- function close() {
- fclose($this->handle);
- $this->handle = NULL;
- }
-
- /**
- * Write a line to the file.
- */
- function write($data) {
- if (!$this->handle) {
- $this->handle = $this->open(TRUE);
- }
- if ($this->handle) {
- fwrite($this->handle, $data);
- }
- }
-
- /**
- * Read a line from the file.
- */
- function read($size = NULL) {
- if (!$this->handle) {
- $this->handle = $this->open();
- }
- if ($this->handle && !feof($this->handle)) {
- return $size ? fread($this->handle, $size) : fgets($this->handle);
- }
- return NULL;
- }
-
- /**
- * Write data to the file.
- */
- function put_contents($data) {
- file_put_contents($this->filepath(), $data);
- }
-
- /**
- * Read data from the file.
- */
- function get_contents() {
- return file_get_contents($this->filepath());
- }
-
- /**
- * Transfer file using http to client. Similar to the built in file_transfer,
- * but it calls module_invoke_all('exit') so that temp files can be deleted.
- */
- function transfer() {
- $headers = array(
- array('key' => 'Content-Type', 'value' => $this->mimetype()),
- array('key' => 'Content-Disposition', 'value' => 'attachment; filename="'. $this->filename() .'"'),
- );
- if ($size = $this->info('filesize')) {
- $headers[] = array('key' => 'Content-Length', 'value' => $size);
- }
-
- // Suppress the warning you get when the buffer is empty.
- @ob_end_clean();
-
- if ($this->open(FALSE, TRUE)) {
- foreach ($headers as $header) {
- // To prevent HTTP header injection, we delete new lines that are
- // not followed by a space or a tab.
- // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
- $header['value'] = preg_replace('/\r?\n(?!\t| )/', '', $header['value']);
- drupal_add_http_header($header['key'], $header['value']);
- }
- // Transfer file in 1024 byte chunks to save memory usage.
- while ($data = $this->read(1024)) {
- print $data;
- }
- $this->close();
-
- // Ask devel.module not to print it's footer.
- $GLOBALS['devel_shutdown'] = FALSE;
- }
- else {
- drupal_not_found();
- }
-
- // Start buffering and throw away the results so that errors don't get appended to the file.
- ob_start('_backup_migrate_file_dispose_buffer');
- backup_migrate_cleanup();
- module_invoke_all('exit');
- exit();
- }
-
- /**
- * Push a file extension onto the file and return the previous file path.
- */
- function push_type($extension) {
- $types = _backup_migrate_filetypes();
- if ($type = @$types[$extension]) {
- $this->push_filetype($type);
- }
-
- $out = $this->filepath();
- $this->temporary_file();
- return $out;
- }
-
- /**
- * Push a file extension onto the file and return the previous file path.
- */
- function pop_type() {
- $out = new backup_file(array('filepath' => $this->filepath()));
- $this->pop_filetype();
- $this->temporary_file();
- return $out;
- }
-
- /**
- * Set the current file type.
- */
- function set_filetype($type) {
- $this->type = $type;
- $this->ext = array($type['extension']);
- }
-
- /**
- * Set the current file type.
- */
- function push_filetype($type) {
- $this->ext[] = $type['extension'];
- $this->type = $type;
- }
-
- /**
- * Pop the current file type.
- */
- function pop_filetype() {
- array_pop($this->ext);
- $this->detect_filetype_from_extension();
- }
-
- /**
- * Set the file info.
- */
- function set_file_info($file_info) {
- $this->file_info = $file_info;
-
- $this->ext = explode('.', @$this->file_info['filename']);
- // Remove the underscores added to file extensions by Drupal's upload security.
- foreach ($this->ext as $key => $val) {
- $this->ext[$key] = trim($val, '_');
- }
- $this->filename(array_shift($this->ext));
- $this->detect_filetype_from_extension();
- }
-
- /**
- * Get the filetype info of the given file, or false if the file is not a valid type.
- */
- function detect_filetype_from_extension() {
- $ext = end($this->ext);
- $this->type = array();
- $types = _backup_migrate_filetypes();
- foreach ($types as $key => $type) {
- if (trim($ext, "_0123456789") === $type['extension']) {
- $this->type = $type;
- $this->type['id'] = $key;
- }
- }
- }
-
- /**
- * Get a temporary file name with path.
- */
- function temporary_file() {
- $file = drupal_tempnam('temporary://', 'backup_migrate_');
- // Add the version without the extension. The tempnam function creates this for us.
- backup_migrate_temp_files_add($file);
-
- if ($this->extension()) {
- $file .= '.'. $this->extension();
- // Add the version with the extension. This is the one we will actually use.
- backup_migrate_temp_files_add($file);
- }
- $this->path = $file;
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.backup_restore.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.backup_restore.inc
deleted file mode 100644
index e9f25192..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.backup_restore.inc
+++ /dev/null
@@ -1,169 +0,0 @@
- 0, 'restore' => 0);
-
- /**
- * Get the default destinations for this filter.
- */
- function destinations() {
- $out = array();
- foreach ($this->_get_destination_types() as $destination) {
- if (method_exists($destination, 'destinations')) {
- $out += $destination->destinations();
- }
- }
- return $out;
- }
-
-
- /**
- * Get the default backup settings for this filter.
- */
- function backup_settings_default() {
- backup_migrate_include('destinations');
- $out = array();
- foreach (backup_migrate_get_destinations('source') as $destination) {
- $out['destinations'][$destination->get_id()] = $destination->backup_settings_default();
- }
- return $out;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form_validate($form, &$form_state) {
- foreach ($this->_get_destination_types() as $destination) {
- $destination->backup_settings_form_validate($form, $form_state);
- }
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function backup_settings_form_submit($form, &$form_state) {
- foreach ($this->_get_destination_types() as $destination) {
- $destination->backup_settings_form_submit($form, $form_state);
- }
- }
-
- /**
- * Get the default restore settings for this filter.
- */
- function restore_settings_default() {
- $out = array();
- foreach ($this->_get_destination_types() as $destination) {
- $out += $destination->restore_settings_default();
- }
- return $out;
- }
-
- /**
- * Get the form for the backup settings for this filter.
- */
- function backup_settings_form($settings) {
- backup_migrate_include('destinations');
- $out = array('destinations' => array(
- '#tree' => TRUE,
-
- ));
- foreach (backup_migrate_get_destinations('source') as $destination) {
- $destination_settings = (array)(@$settings['destinations'][$destination->get_id()]) + $settings;
- if ($form = $destination->backup_settings_form($destination_settings)) {
- $out['destinations'][$destination->get_id()] = array(
- '#type' => 'fieldset',
- '#title' => t('!name Backup Options', array('!name' => $destination->get('name'))),
- "#collapsible" => TRUE,
- "#collapsed" => TRUE,
- '#tree' => TRUE,
- '#parents' => array('filters', 'destinations', $destination->get_id()),
- ) + $form;
- }
- }
- return $out;
- }
-
- /**
- * Get the form for the restore settings for this filter.
- */
- function restore_settings_form($settings) {
- $form = array();
- foreach ($this->_get_destination_types() as $destination) {
- $destination->restore_settings_form($form, $settings);
- }
- return $form;
- }
-
- /**
- * Get the file types supported by this destination.
- */
- function file_types() {
- $types = array();
- foreach ($this->_get_destination_types() as $destination) {
- $types += $destination->file_types();
- }
- return $types;
- }
-
- /**
- * Backup the data from the source specified in the settings.
- */
- function backup($file, &$settings) {
- if ($source = $settings->get_source()) {
- if (!empty($settings->filters['destinations'][$source->get_id()])) {
- $settings->filters = (array)($settings->filters['destinations'][$source->get_id()]) + $settings->filters;
- }
- $file = $source->backup_to_file($file, $settings);
- return $file;
- }
- backup_migrate_backup_fail("Could not run backup because the source '%source' is missing.", array('%source' => $settings->source_id), $settings);
- return FALSE;
- }
-
- /**
- * Restore the data from to source specified in the settings.
- */
- function restore($file, &$settings) {
- if ($source = $settings->get_source()) {
- if (!empty($settings->filters['destinations'][$source->get_id()])) {
- $settings->filters = (array)($settings->filters['destinations'][$source->get_id()]) + $settings->filters;
- }
- $num = $source->restore_from_file($file, $settings);
- return $num ? $file : FALSE;
- }
- backup_migrate_restore_fail("Could not run restore because the source '%source' is missing.", array('%source' => $settings->source_id), $settings);
- return FALSE;
- }
-
- /**
- * Get a list of dummy destinations representing each of the available destination types.
- */
- function _get_destination_types() {
- backup_migrate_include('destinations');
- static $destinations = NULL;
- if (!is_array($destinations)) {
- $destinations = array();
- $types = backup_migrate_get_destination_types();
- // If no (valid) node type has been provided, display a node type overview.
- foreach ($types as $key => $type) {
- // Include the necessary file if specified by the type.
- if (!empty($type['file'])) {
- require_once './'. $type['file'];
- }
- $destinations[] = new $type['class'](array());
- }
- }
- return $destinations;
- }
-}
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.compression.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.compression.inc
deleted file mode 100644
index 6a0e1117..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.compression.inc
+++ /dev/null
@@ -1,289 +0,0 @@
- 100, 'restore' => -100);
-
- /**
- * This function is called on a backup file after the backup has been completed.
- */
- function backup($file, &$settings) {
- return $this->_backup_migrate_file_compress($file, $settings);
- }
-
- /**
- * This function is called on a backup file before importing it.
- */
- function restore($file, &$settings) {
- return $this->_backup_migrate_file_decompress($file);
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_default() {
- $options = $this->_backup_migrate_get_compression_form_item_options();
- return array('compression' => isset($options['gzip']) ? 'gzip' : 'none');
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form($settings) {
- $form = array();
- $compression_options = $this->_backup_migrate_get_compression_form_item_options();
- $form['file']['compression'] = array(
- "#type" => count($compression_options) > 1 ? "select" : 'value',
- "#title" => t("Compression"),
- "#options" => $compression_options,
- "#default_value" => $settings['compression'],
- );
- return $form;
- }
-
- /**
- * Return a list of backup filetypes.
- */
- function file_types() {
- return array(
- "gzip" => array(
- "extension" => "gz",
- "filemime" => "application/x-gzip",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- "bzip" => array(
- "extension" => "bz",
- "filemime" => "application/x-bzip",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- "bzip2" => array(
- "extension" => "bz2",
- "filemime" => "application/x-bzip",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- "zip" => array(
- "extension" => "zip",
- "filemime" => "application/zip",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- );
- }
-
- /**
- * Get the compression options as an options array for a form item.
- */
- function _backup_migrate_get_compression_form_item_options() {
- $compression_options = array("none" => t("No Compression"));
- if (@function_exists("gzencode")) {
- $compression_options['gzip'] = t("GZip");
- }
- if (@function_exists("bzcompress")) {
- $compression_options['bzip'] = t("BZip");
- }
- if (class_exists('ZipArchive')) {
- $compression_options['zip'] = t("Zip", array(), array('context' => 'compression format'));
- }
- return $compression_options;
- }
-
- /**
- * Gzip encode a file.
- */
- function _backup_migrate_gzip_encode($source, $dest, $level = 9) {
- $success = FALSE;
- if (@function_exists("gzopen")) {
- if (($fp_out = gzopen($dest, 'wb'. $level)) && ($fp_in = fopen($source, 'rb'))) {
- while (!feof($fp_in)) {
- gzwrite($fp_out, fread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- @fclose($fp_in);
- @gzclose($fp_out);
- }
- return $success;
- }
-
- /**
- * Gzip decode a file.
- */
- function _backup_migrate_gzip_decode($source, $dest) {
- $success = FALSE;
- if (@function_exists("gzopen")) {
- if (($fp_out = fopen($dest, 'wb')) && ($fp_in = gzopen($source, 'rb'))) {
- while (!feof($fp_in)) {
- fwrite($fp_out, gzread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- @gzclose($fp_in);
- @fclose($fp_out);
- }
- return $success;
- }
-
- /**
- * Bzip encode a file.
- */
- function _backup_migrate_bzip_encode($source, $dest) {
- $success = FALSE;
- if (@function_exists("bzopen")) {
- if (($fp_out = bzopen($dest, 'w')) && ($fp_in = fopen($source, 'rb'))) {
- while (!feof($fp_in)) {
- bzwrite($fp_out, fread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- else {
- $error = TRUE;
- }
- @fclose($fp_in);
- @bzclose($fp_out);
- }
- return $success;
- }
-
- /**
- * Bzip decode a file.
- */
- function _backup_migrate_bzip_decode($source, $dest) {
- $success = FALSE;
- if (@function_exists("bzopen")) {
- if (($fp_out = fopen($dest, 'w')) && ($fp_in = bzopen($source, 'r'))) {
- while (!feof($fp_in)) {
- fwrite($fp_out, gzread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- else {
- $error = TRUE;
- }
- @bzclose($fp_in);
- @fclose($fp_out);
- }
- return $success;
- }
-
- /**
- * Zip encode a file.
- */
- function _backup_migrate_zip_encode($source, $dest, $filename) {
- $success = FALSE;
- if (class_exists('ZipArchive')) {
- $zip = new ZipArchive;
- $res = $zip->open($dest, constant("ZipArchive::CREATE"));
- if ($res === TRUE) {
- $zip->addFile($source, $filename);
- $success = $zip->close();
- }
- }
- return $success;
- }
-
- /**
- * Zip decode a file.
- */
- function _backup_migrate_zip_decode($source, $dest) {
- $success = FALSE;
- if (class_exists('ZipArchive')) {
- $zip = new ZipArchive;
- if (($fp_out = fopen($dest, "w")) && ($zip->open($source))) {
- $filename = ($zip->getNameIndex(0));
- if ($fp_in = $zip->getStream($filename)) {
- while (!feof($fp_in)) {
- fwrite($fp_out, fread($fp_in, 1024 * 512));
- }
- $success = TRUE;
- }
- }
- @fclose($fp_in);
- @fclose($fp_out);
- }
- return $success;
- }
-
- /**
- * Compress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
- */
- function _backup_migrate_file_compress($file, $settings) {
- switch ($settings->filters['compression']) {
- case "gzip":
- $from = $file->push_type('gzip');
- if (!$success = $this->_backup_migrate_gzip_encode($from, $file->filepath(), 9)) {
- $file = NULL;
- }
- break;
-
- case "bzip":
- $from = $file->push_type('bzip2');
- if (!$success = $this->_backup_migrate_bzip_encode($from, $file->filepath())) {
- $file = NULL;
- }
- break;
-
- case "zip":
- $filename = $file->filename();
- $from = $file->push_type('zip');
- if (!$success = $this->_backup_migrate_zip_encode($from, $file->filepath(), $filename)) {
- $file = NULL;
- }
- break;
- }
- if (!$file) {
- _backup_migrate_message("Could not compress backup file. Try backing up without compression.", array(), 'error');
- }
-
- return $file;
- }
-
- /**
- * Decompress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
- */
- function _backup_migrate_file_decompress($file) {
- $success = FALSE;
-
- switch ($file->type_id()) {
- case "gzip":
- $from = $file->pop_type();
- $success = $this->_backup_migrate_gzip_decode($from->filepath(), $file->filepath());
- break;
-
- case "bzip":
- case "bzip2":
- $from = $file->pop_type();
- $success = $this->_backup_migrate_bzip_decode($from->filepath(), $file->filepath());
- break;
-
- case "zip":
- $from = $file->pop_type();
- $success = $this->_backup_migrate_zip_decode($from->filepath(), $file->filepath());
- break;
-
- default:
- return $file;
- break;
- }
-
- if (!$success) {
- _backup_migrate_message("Could not decompress backup file. Please check that the file is valid.", array(), 'error');
- }
- return $success ? $file : NULL;
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.encryption.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.encryption.inc
deleted file mode 100644
index 46f01c26..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.encryption.inc
+++ /dev/null
@@ -1,177 +0,0 @@
- 170, 'restore' => -170);
-
- /**
- * This function is called on a backup file after the backup has been completed.
- */
- function backup($file, &$settings) {
- return $this->file_encrypt($file, $settings);
- }
-
- /**
- * This function is called on a backup file before importing it.
- */
- function restore($file, &$settings) {
- return $this->file_decrypt($file);
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_default() {
- return array('encryption' => 'none');
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form($settings) {
- $form = array();
- $options = $this->_backup_migrate_get_encryption_form_item_options();
- if (count($options) > 1) {
- $form['file']['encryption'] = array(
- "#type" => "select",
- "#title" => t("File Encryption (EXPERIMENTAL)"),
- "#options" => $options,
- "#default_value" => @$settings['encryption'],
- '#description' => t('Encrypted files can only be restored by Backup and Migrate and only on sites with the same encryption key. This functionality is experimental, and should only be used for testing. '),
- );
- }
- else {
- $form['file']['encryption'] = array(
- "#type" => 'item',
- "#title" => t("File Encryption"),
- "#markup" => t('Install the !link to enable backup file encryption.', array('!link' => l(t('AES Encryption Module'), 'http://drupal.org/project/aes'))),
- );
- }
-
- return $form;
- }
-
- /**
- * Return a list of backup filetypes.
- */
- function file_types() {
- return array(
- "aes" => array(
- "extension" => "aes",
- "filemime" => "application/octet-stream",
- "backup" => TRUE,
- "restore" => TRUE,
- ),
- );
- }
-
- /**
- * Get the compression options as an options array for a form item.
- */
- function _backup_migrate_get_encryption_form_item_options() {
- $options = array();
- $options = array('' => t('No Encryption'));
- if (@function_exists("aes_encrypt")) {
- $options['aes'] = t("AES Encryption");
- }
- return $options;
- }
-
- /**
- * AES encrypt a file.
- */
- function aes_encrypt($source, $dest) {
- $success = FALSE;
- if (function_exists('aes_encrypt')) {
- if ($data = $source->get_contents()) {
- // Add a marker to the end of the data so we can trim the padding on decrpypt.
- $data = pack("a*H2", $data, "80");
- if ($data = aes_encrypt($data, FALSE)) {
- $dest->put_contents($data);
- $success = TRUE;
- }
- }
- }
- return $success;
- }
-
- /**
- * Gzip decode a file.
- */
- function aes_decrypt($source, $dest) {
- $success = FALSE;
- if (function_exists('aes_decrypt')) {
- if ($data = $source->get_contents()) {
- if ($data = aes_decrypt($data, FALSE)) {
- // Trim all the padding zeros plus our non-zero marker.
- $data = substr(rtrim($data, "\0"), 0, -1);
- $dest->put_contents($data);
- $success = TRUE;
- }
- }
- }
- return $success;
- }
-
- /**
- * Compress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
- */
- function file_encrypt($file, $settings) {
- if (!empty($settings->filters['encryption'])) {
- switch ($settings->filters['encryption']) {
- case "aes":
- $from = $file->push_type('aes');
- $from = new backup_file(array('filepath' => $from));
- if (!$success = $this->aes_encrypt($from, $file)) {
- $file = NULL;
- }
- break;
- }
- if (!$file) {
- _backup_migrate_message("Could not encrypt backup file. Try backing up without encryption.", array(), 'error');
- }
- }
- return $file;
- }
-
- /**
- * Decompress a file with the given settings.
- * Also updates settings to reflect new file mime and file extension.
- */
- function file_decrypt($file) {
- $success = FALSE;
- if ($file) {
- switch ($file->type_id()) {
- case "aes":
- $from = $file->pop_type();
- $success = $this->aes_decrypt($from, $file);
- break;
- default:
- return $file;
- break;
- }
-
- if (!$success) {
- if (function_exists('aes_decrypt')) {
- _backup_migrate_message("Could not decrpyt backup file. Please check that the file is valid and that the encryption key of the server matches the server that created the backup.", array(), 'error');
- }
- else {
- _backup_migrate_message('You must install the !link to restore encrypted backkups.', array('!link' => l(t('AES Encryption Module'), 'http://drupal.org/project/aes')), 'error');
- }
- }
- }
- return $success ? $file : NULL;
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.inc
deleted file mode 100644
index 679a25cd..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.inc
+++ /dev/null
@@ -1,290 +0,0 @@
-weight($op);
- }
- array_multisort($sort, SORT_ASC, SORT_NUMERIC, $filters);
- return $filters;
-}
-
-/**
- * Implementation of hook_backup_migrate_filters().
- *
- * Get the built in Backup and Migrate filters.
- */
-function backup_migrate_backup_migrate_filters() {
- return array(
- 'backup_restore' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/filters.backup_restore.inc',
- 'class' => 'backup_migrate_filter_backup_restore',
- ),
- 'compression' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/filters.compression.inc',
- 'class' => 'backup_migrate_filter_compression',
- ),
- 'encryption' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/filters.encryption.inc',
- 'class' => 'backup_migrate_filter_encryption',
- ),
- 'statusnotify' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/filters.statusnotify.inc',
- 'class' => 'backup_migrate_filter_statusnotify',
- ),
- 'utils' => array(
- 'file' => drupal_get_path('module', 'backup_migrate') .'/includes/filters.utils.inc',
- 'class' => 'backup_migrate_filter_utils',
- ),
- );
-}
-
-/**
- * Invoke the given method on all of the available filters.
- */
-function backup_migrate_filters_invoke_all() {
- $args = func_get_args();
- $op = array_shift($args);
- $out = array();
- $filters = backup_migrate_get_filters($op);
- foreach ($filters as $filter) {
- if (method_exists($filter, $op)) {
- /* call_user_func_array() ignores the function signature, so we cannot
- * use it to pass references. (Call-time pass-by-reference is deprecated
- * in PHP5.3.) Work around it, since we have unknown function signatures.
- */
- switch (count($args)) {
- case 1:
- $ret = $filter->$op($args[0]);
- break;
-
- case 2:
- $ret = $filter->$op($args[0], $args[1]);
- break;
-
- default:
- // This assumes that no functions with more than 2 arguments expect a
- // reference as argument. If so, add another 'case block'.
- $ret = call_user_func_array(array($filter, $op), $args);
- }
- $out = array_merge_recursive($out, (array) $ret);
- }
- }
- return $out;
-}
-
-/**
- * Filter a backup file before sending it to the destination.
- */
-function backup_migrate_filters_backup($file, &$settings) {
- $filters = backup_migrate_get_filters('backup');
- foreach ($filters as $filter) {
- if ($file) {
- $file = $filter->backup($file, $settings);
- }
- }
- return $file;
-}
-
-/**
- * Filter a backup file before sending it to the destination.
- */
-function backup_migrate_filters_restore($file, &$settings) {
- $filters = backup_migrate_get_filters('restore');
- foreach ($filters as $filter) {
- if ($file) {
- $file = $filter->restore($file, $settings);
- }
- }
- return $file;
-}
-
-/**
- * Get the backup settings for all of the filters.
- */
-function backup_migrate_filters_settings_form($settings, $op) {
- $out = backup_migrate_filters_invoke_all($op .'_settings_form', $settings);
- $out = backup_migrate_filters_settings_form_set_parents($out);
- return $out;
-}
-
-/**
- * Add a form parent to the filter settings so that the filter values are saved in the right table.
- */
-function backup_migrate_filters_settings_form_set_parents($form) {
- foreach (element_children($form) as $key) {
- if (!isset($form[$key]['#parents'])) {
- $form[$key]['#parents'] = array('filters', $key);
- $form[$key] = backup_migrate_filters_settings_form_set_parents($form[$key]);
- }
- }
- return $form;
-}
-
-
-/**
- * Validate all the filters.
- */
-function backup_migrate_filters_settings_form_validate($op, $form, &$form_state) {
- //backup_migrate_filters_invoke_all($op .'_settings_form_validate', $form, $form_state);
-}
-
-/**
- * Submit all of the filters.
- */
-function backup_migrate_filters_settings_form_submit($op, $form, &$form_state) {
- //backup_migrate_filters_invoke_all($op .'_settings_form_submit', $form, $form_state);
-}
-
-
-/**
- * Get the default settings for the filters.
- */
-function backup_migrate_filters_settings_default($op) {
- return backup_migrate_filters_invoke_all($op .'_settings_default');
-}
-
-/**
- * Get the file types for all of the filters.
- */
-function backup_migrate_filters_file_types() {
- return backup_migrate_filters_invoke_all('file_types');
-}
-
-/**
- * A base class for basing filters on.
- */
-class backup_migrate_filter {
- var $weight = 0;
- var $op_weights = array();
-
- /**
- * Get the weight of the filter for the given op.
- */
- function weight($op = NULL) {
- if ($op && isset($this->op_weights[$op])) {
- return $this->op_weights[$op];
- }
- return $this->weight;
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_default() {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form($settings) {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form_validate($form, &$form_state) {
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function backup_settings_form_submit($form, &$form_state) {
- return $form_state['values'];
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_default() {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_form($settings) {
- return array();
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function restore_settings_form_validate($form, &$form_state) {
- }
-
- /**
- * Submit the settings form. Any values returned will be saved.
- */
- function restore_settings_form_submit($form, &$form_state) {
- return $form_state['values'];
- }
-
- /**
- * Get a list of file types handled by this filter.
- */
- function file_types() {
- return array();
- }
-
- /**
- * Declare any default destinations for this filter.
- */
- function destinations() {
- return array();
- }
-
-
- /**
- * This function is called on a backup file after the backup has been completed.
- */
- function backup($file, &$settings) {
- return $file;
- }
-
- /**
- * This function is called on a backup file before importing it.
- */
- function restore($file, &$settings) {
- return $file;
- }
-
- /**
- * This function is called immediately prior to backup.
- */
- function pre_backup($source, $file, $settings) {
-
- }
-
- /**
- * This function is called immediately post backup.
- */
- function post_backup($source, $file, $settings) {
-
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.statusnotify.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.statusnotify.inc
deleted file mode 100644
index 3371d6c7..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.statusnotify.inc
+++ /dev/null
@@ -1,102 +0,0 @@
- FALSE,
- 'notify_failure_enable' => FALSE,
- 'notify_success_email' => variable_get('site_mail', ''),
- 'notify_failure_email' => variable_get('site_mail', ''),
- );
- }
-
- /**
- * Get the form for the settings for this filter.
- */
- function backup_settings_form($settings) {
- $form = array();
- $form['advanced']['notify_success_enable'] = array(
- "#type" => 'checkbox',
- "#title" => t("Send an email if backup succeeds"),
- "#default_value" => @$settings['notify_success_enable'],
- );
- $form['advanced']['notify_success_email'] = array(
- "#type" => "textfield",
- "#title" => t("Email Address for Success Notices"),
- "#default_value" => @$settings['notify_success_email'],
- );
- $form['advanced']['notify_failure_enable'] = array(
- "#type" => 'checkbox',
- "#title" => t("Send an email if backup fails"),
- "#default_value" => @$settings['notify_failure_enable'],
- );
- $form['advanced']['notify_failure_email'] = array(
- "#type" => "textfield",
- "#title" => t("Email Address for Failure Notices"),
- "#default_value" => @$settings['notify_failure_email'],
- );
- return $form;
- }
-
- /**
- * Send the success email.
- */
- function backup_succeed($settings) {
- if (@$settings->filters['notify_success_enable'] && $to = @$settings->filters['notify_success_email']) {
- $messages = $this->get_messages();
- $subject = t('!site backup succeeded', array('!site' => variable_get('site_name', 'Drupal site')));
- if ($messages = $this->get_messages()) {
- $body = t("The site backup has completed successfully with the following messages:\n!messages", array('!messages' => $messages));
- }
- else {
- $body = t("The site backup has completed successfully.\n");
- }
- mail($settings->filters['notify_success_email'], $subject, $body);
- }
- }
-
- /**
- * Send the failure email.
- */
- function backup_fail($settings) {
- if (@$settings->filters['notify_failure_enable'] && $to = @$settings->filters['notify_failure_email']) {
- $messages = $this->get_messages();
- $subject = t('!site backup failed', array('!site' => variable_get('site_name', 'Drupal site')));
- if ($messages = $this->get_messages()) {
- $body = t("The site backup has failed with the following messages:\n!messages", array('!messages' => $messages));
- }
- else {
- $body = t("The site backup has failed for an unknown reason.");
- }
- mail($settings->filters['notify_failure_email'], $subject, $body);
- }
- }
-
- /**
- * Render the messages and errors for the email.
- */
- function get_messages() {
- $out = "";
- $messages = _backup_migrate_messages();
- foreach ($messages as $message) {
- $out .= strip_tags(t($message['message'], $message['replace'])) . "\n";
- }
- return $out;
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/filters.utils.inc b/sites/all/modules/contrib/backup_migrate/includes/filters.utils.inc
deleted file mode 100644
index c4dce95c..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/filters.utils.inc
+++ /dev/null
@@ -1,189 +0,0 @@
- TRUE,
- 'utils_site_offline' => FALSE,
- 'utils_description' => '',
- );
- }
-
- /**
- * Get the default restore settings for this filter.
- */
- function restore_settings_default() {
- return array(
- 'utils_disable_query_log' => TRUE,
- 'utils_site_offline' => FALSE,
- );
- }
-
- /**
- * Get the form for the backup settings for this filter.
- */
- function backup_settings_form($settings) {
- $form = array();
- if (module_exists('devel') && variable_get('dev_query', 0)) {
- $form['database']['utils_disable_query_log'] = array(
- '#type' => 'checkbox',
- '#title' => t('Disable query log'),
- '#default_value' => !empty($settings['utils_disable_query_log']) ? $settings['utils_disable_query_log'] : NULL,
- '#description' => t('Disable the devel module\'s query logging during the backup operation. It will be enabled again after backup is complete. This is very highly recommended.'),
- );
- }
- $form['advanced']['utils_site_offline'] = array(
- '#type' => 'checkbox',
- '#title' => t('Take site offline'),
- '#default_value' => !empty($settings['utils_site_offline']) ? $settings['utils_site_offline'] : NULL,
- '#description' => t('Take the site offline during backup and show a maintenance message. Site will be taken back online once the backup is complete.'),
- );
- $form['advanced']['utils_site_offline_message'] = array(
- '#type' => 'textarea',
- '#title' => t('Site off-line message'),
- '#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
- '#description' => t('Message to show visitors when the site is in off-line mode.')
- );
- $form['advanced']['utils_description'] = array(
- '#type' => 'textarea',
- '#title' => t('Description'),
- '#default_value' => !empty($settings['utils_description']) ? $settings['utils_description'] : NULL,
- '#description' => t('Add a short description to the backup file.'),
- );
-
- return $form;
- }
-
- /**
- * Get the form for the restore settings for this filter.
- */
- function restore_settings_form($settings) {
- $form = array();
- if (module_exists('devel') && variable_get('dev_query', 0)) {
- $form['advanced']['utils_disable_query_log'] = array(
- '#type' => 'checkbox',
- '#title' => t('Disable query log'),
- '#default_value' => @$settings['utils_disable_query_log'],
- '#description' => t('Disable the devel module\'s query logging during the restore operation. It will be enabled again after restore is complete. This is very highly recommended.'),
- );
- }
- $form['advanced']['utils_site_offline'] = array(
- '#type' => 'checkbox',
- '#title' => t('Take site offline'),
- '#default_value' => !empty($settings['utils_site_offline']) ? $settings['utils_site_offline'] : NULL,
- '#description' => t('Take the site offline during restore and show a maintenance message. Site will be taken back online once the restore is complete.'),
- );
- $form['advanced']['utils_site_offline_message'] = array(
- '#type' => 'textarea',
- '#title' => t('Site off-line message'),
- '#default_value' => !empty($settings['utils_site_offline_message']) ? $settings['utils_site_offline_message'] : variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
- '#description' => t('Message to show visitors when the site is in off-line mode.')
- );
- return $form;
- }
-
- function pre_backup($source, $file, $settings) {
- $this->take_site_offline($settings);
- $this->disable_devel_query($settings);
- }
-
- function post_backup($source, $file, $settings) {
- $this->enable_devel_query($settings);
- $this->take_site_online($settings);
- $this->add_file_info($file, $settings);
- }
-
- function pre_restore($file, $settings) {
- $this->disable_devel_query($settings);
- $this->take_site_offline($settings);
- }
-
- function post_restore($file, $settings) {
- $this->enable_devel_query($settings);
- $this->take_site_online($settings);
- }
-
- /**
- * Disable devel query logging if it's active and the user has chosen to do so.
- */
- function disable_devel_query($settings) {
- $this->saved_devel_query = variable_get('dev_query', 0);
- if (module_exists('devel') && variable_get('dev_query', 0) && !empty($settings->filters['utils_disable_query_log'])) {
- variable_set('dev_query', 0);
- }
- }
-
- /**
- * Restore devel query to previous state.
- */
- function enable_devel_query($settings) {
- if (module_exists('devel')) {
- variable_set('dev_query', $this->saved_devel_query);
- }
- }
-
- /**
- * Add the backup metadata to the file.
- */
- function add_file_info($file, $settings) {
- $file->file_info['description'] = $settings->filters['utils_description'];
- $file->file_info['datestamp'] = time();
- $file->file_info['generator'] = 'Backup and Migrate (http://drupal.org/project/backup_migrate)';
- $file->file_info['generatorversion'] = BACKUP_MIGRATE_VERSION;
- $file->file_info['sites'] = array(
- '0' => array(
- 'version' => VERSION,
- 'name' => variable_get('site_name', ''),
- 'url' => url('', array('absolute' => TRUE)),
- ),
- );
-
- }
-
- /**
- * Take the site offline if configured to do so.
- */
- function take_site_offline($settings) {
- // Save the current state of the site in case a restore overwrites it.
- $this->saved_site_offline = variable_get('maintenance_mode', 0);
- if (@$settings->filters['utils_site_offline']) {
- $this->saved_site_offline_message = variable_get('maintenance_mode_message', NULL);
- if (!empty($settings->filters['utils_site_offline_message'])) {
- $this->saved_site_offline_message = variable_get('maintenance_mode_message', NULL);
- variable_set('maintenance_mode_message', $settings->filters['utils_site_offline_message']);
- }
- variable_set('maintenance_mode', 1);
- _backup_migrate_message('Site was taken offline.');
- }
- }
-
- /**
- * Take the site online again after backup or restore.
- */
- function take_site_online($settings) {
- // Take the site back off/online because the restored db may have changed that setting.
- variable_set('maintenance_mode', $this->saved_site_offline);
- if ($settings->filters['utils_site_offline']) {
- if (!empty($this->saved_site_offline_message)) {
- variable_set('maintenance_mode_message', $this->saved_site_offline_message);
- }
- _backup_migrate_message('Site was taken online.');
- }
- }
-}
\ No newline at end of file
diff --git a/sites/all/modules/contrib/backup_migrate/includes/profiles.inc b/sites/all/modules/contrib/backup_migrate/includes/profiles.inc
deleted file mode 100644
index da49b218..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/profiles.inc
+++ /dev/null
@@ -1,321 +0,0 @@
- $profile) {
- // Set the default values for filter setting which don't exist in the profile.
- $profiles[$id]->filters = (array)@$profile->filters + (array)backup_migrate_filters_settings_default('backup');
- }
-}
-
-/**
- * Get the profile info for the profile with the given ID, or NULL if none exists.
- */
-function backup_migrate_get_profile($profile_id) {
- $profiles = backup_migrate_get_profiles();
- return @$profiles[$profile_id];
-}
-
-/**
- * Implementation of hook_backup_migrate_profiles().
- */
-function backup_migrate_backup_migrate_profiles() {
- $out = array();
-
- // Get the module default profile.
- $out['default'] = backup_migrate_crud_create_item('profile', array('name' => t("Default Settings"), 'profile_id' => 'default'));
-
- return $out;
-}
-
-/* Utilities */
-
-/**
- * Get the available profiles as an options array for a form item.
- */
-function _backup_migrate_get_profile_form_item_options() {
- $out = array();
- foreach ((array)backup_migrate_get_profiles() as $key => $profile) {
- $out[$key] = $profile->get('name');
- }
- return $out;
-}
-
-/**
- * Get a form to configure the profile.
- */
-function _backup_migrate_ui_backup_settings_form($profile) {
- drupal_add_js(array('backup_migrate' => array('checkboxLinkText' => t('View as checkboxes'))), array('type' => 'setting'));
- drupal_add_js(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.js', array('type' => 'file', 'scope' => 'footer'));
- drupal_add_css(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.css');
-
- backup_migrate_include('files', 'destinations', 'filters');
-
- $form = array();
-
- $form['file'] = array(
- "#type" => "fieldset",
- "#title" => t("Backup File"),
- "#collapsible" => TRUE,
- "#collapsed" => FALSE,
- "#tree" => FALSE,
- );
- $form['file']['filename'] = array(
- "#type" => "textfield",
- "#title" => t("Backup file name"),
- "#default_value" => $profile->filename,
- );
- if (module_exists('token')) {
- $form['file']['filename']['#description'] = t('You can use tokens in the file name.');
-
- $form['file']['token_help'] = array(
- '#title' => t('Replacement patterns'),
- '#type' => 'fieldset',
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $form['file']['token_help']['help'] = array(
- '#theme' => 'token_tree',
- '#token_types' => array('current-date', 'site'),
- '#global_types' => FALSE,
- );
- }
-
- $form['file']['append_timestamp'] = array(
- "#type" => "checkbox",
- "#title" => t("Append a timestamp."),
- "#default_value" => $profile->append_timestamp,
- );
- $form['file']['timestamp_format'] = array(
- "#type" => "textfield",
- "#title" => t("Timestamp format"),
- "#default_value" => $profile->timestamp_format,
- "#description" => t('Should be a PHP date() format string.', array('!url' => 'http://www.php.net/date')),
- );
-
- $form['advanced'] = array('#weight' => 10);
- $form = array_merge_recursive($form, backup_migrate_filters_settings_form($profile->filters, 'backup'));
-
- // Add the advanced fieldset if there are any fields in it.
- if ($form['advanced']) {
- $form['advanced']['#type'] = 'fieldset';
- $form['advanced']['#title'] = t('Advanced Options');
- $form['advanced']['#collapsed'] = true;
- $form['advanced']['#collapsible'] = true;
- }
-
- $form['#validate'][] = '_backup_migrate_ui_backup_settings_form_validate';
- $form['#submit'][] = '_backup_migrate_ui_backup_settings_form_submit';
-
- return $form;
-}
-
-/**
- * Validate the profile form.
- */
-function _backup_migrate_ui_backup_settings_form_validate($form, &$form_state) {
- backup_migrate_filters_settings_form_validate('backup', $form, $form_state);
-}
-
-/**
- * Submit the profile form.
- */
-function _backup_migrate_ui_backup_settings_form_submit($form, &$form_state) {
- backup_migrate_filters_settings_form_submit('backup', $form, $form_state);
-}
-
-/**
- * Get the default profile.
- */
-function _backup_migrate_profile_default_profile() {
- backup_migrate_include('files', 'filters');
- return array(
- 'source_id' => 'db',
- 'filename' => _backup_migrate_default_filename(),
- 'append_timestamp' => 1,
- 'timestamp_format' => 'Y-m-d\TH-i-s',
- 'filters' => backup_migrate_filters_settings_default('backup'),
- );
-}
-
-/**
- * Get the default profile saved by the user (or the module default if none exists).
- */
-function _backup_migrate_profile_saved_default_profile($profile_id = NULL) {
- $profile_id = $profile_id ? $profile_id : variable_get("backup_migrate_profile_id", 'default');
- $profile = NULL;
- if ($profile_id) {
- $profile = backup_migrate_get_profile($profile_id);
- }
- if (!$profile) {
- $profile = backup_migrate_get_profile('default');
- }
- return $profile;
-}
-
-/**
- * A profile class for crud operations.
- */
-class backup_migrate_profile extends backup_migrate_item {
- var $db_table = "backup_migrate_profiles";
- var $type_name = "profile";
- var $singular = 'profile';
- var $plural = 'profiles';
-
- /**
- * This function is not supposed to be called. It is just here to help the po extractor out.
- */
- function strings() {
- // Help the pot extractor find these strings.
- t('Profile');
- t('Profiles');
- t('profile');
- t('profiles');
- }
-
- /**
- * Get the default values for standard parameters.
- */
- function get_default_values() {
- return _backup_migrate_profile_default_profile() + array('name' => t("Untitled Profile"));
- }
-
- /**
- * Get a table of all items of this type.
- */
- function get_list() {
- drupal_add_css(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.css');
- return parent::get_list();
- }
-
- /**
- * Get the columns needed to list the type.
- */
- function get_list_column_info() {
- $out = parent::get_list_column_info();
- $out = array(
- 'name' => array('title' => t('Name')),
- 'source_name' => array('title' => t('Source')),
- 'filename' => array('title' => t('Filename')),
- ) + $out;
- return $out;
- }
-
- /**
- * Get a row of data to be used in a list of items of this type.
- */
- function get_list_row() {
- $row = parent::get_list_row();
- if (empty($this->enabled)) {
- foreach ($row as $key => $field) {
- $row[$key] = array('data' => $field, 'class' => 'profile-list-disabled');
- }
- }
- return $row;
- }
-
- /**
- * Set the source of this setings profile. Takes either a source object or source id.
- */
- function set_source($source) {
- if (is_object($source)) {
- $this->source = $source;
- $this->source_id = $source->get_id();
- }
- else {
- $this->source_id = $source;
- unset($this->source);
- }
- }
-
- /**
- * Get the source of the profile.
- */
- function get_source() {
- backup_migrate_include('destinations');
- if (!empty($this->source_id) && (empty($this->source) || $this->source->destination_id !== $this->source_id)) {
- $this->source = backup_migrate_get_destination($this->source_id);
- }
- return empty($this->source) ? NULL : $this->source;
- }
-
- /**
- * Get the name of the source.
- */
- function get_source_name() {
- if ($source = $this->get_source()) {
- return $source->get_name();
- }
- return t("Missing");
- }
-
- /**
- * Get the destination of the profile.
- */
- function get_destination() {
- backup_migrate_include('destinations');
- if (!empty($this->destination_id) && (empty($this->destination) || $this->destination->destination_id !== $this->destination_id)) {
- $this->destination = backup_migrate_get_destination($this->destination_id);
- }
- return empty($this->destination) ? NULL : $this->destination;
- }
-
- /**
- * Get the name of the destination.
- */
- function get_destination_name() {
- if ($destination = $this->get_destination()) {
- return $destination->get_name();
- }
- return t("Missing");
- }
-
- /**
- * Get the edit form.
- */
- function edit_form() {
- $form = parent::edit_form();
- $form['name'] = array(
- "#type" => "textfield",
- "#title" => t("Profile Name"),
- '#required' => TRUE,
- "#default_value" => $this->get('name'),
- );
- $form += _backup_migrate_ui_backup_settings_form($this);
- return $form;
- }
-
- /**
- * Get the message to send to the user when confirming the deletion of the item.
- */
- function delete_confirm_message() {
- return t('Are you sure you want to delete the profile %name? Any schedules using this profile will be disabled.', array('%name' => $this->get('name')));
- }
-}
-
diff --git a/sites/all/modules/contrib/backup_migrate/includes/schedules.inc b/sites/all/modules/contrib/backup_migrate/includes/schedules.inc
deleted file mode 100644
index e04eaf7d..00000000
--- a/sites/all/modules/contrib/backup_migrate/includes/schedules.inc
+++ /dev/null
@@ -1,403 +0,0 @@
-cron();
- }
- backup_migrate_cleanup();
-}
-
-/**
- * Get all the available backup schedules.
- */
-function backup_migrate_get_schedules() {
- static $schedules = NULL;
- // Get the list of schedules and cache them locally.
- if ($schedules === NULL) {
- $schedules = backup_migrate_crud_get_items('schedule');
- }
- return $schedules;
-}
-
-/**
- * Get the schedule info for the schedule with the given ID, or NULL if none exists.
- */
-function backup_migrate_get_schedule($schedule_id) {
- $schedules = backup_migrate_get_schedules();
- return @$schedules[$schedule_id];
-}
-
-/**
- * A schedule class for crud operations.
- */
-class backup_migrate_schedule extends backup_migrate_item {
- var $db_table = "backup_migrate_schedules";
- var $type_name = 'schedule';
- var $singular = 'schedule';
- var $plural = 'schedules';
- var $default_values = array();
-
- /**
- * This function is not supposed to be called. It is just here to help the po extractor out.
- */
- function strings() {
- // Help the pot extractor find these strings.
- t('Schedule');
- t('Schedules');
- t('schedule');
- t('schedules');
- }
-
- /**
- * Get the default values for this item.
- */
- function get_default_values() {
- return array(
- 'name' => t("Untitled Schedule"),
- 'source_id' => 'db',
- 'enabled' => 1,
- 'keep' => 0,
- 'period' => 60 * 60 * 24,
- 'storage' => BACKUP_MIGRATE_STORAGE_NONE
- );
- }
-
- /**
- * Get the columns needed to list the type.
- */
- function get_list_column_info() {
- $out = parent::get_list_column_info();
- $out = array(
- 'name' => array('title' => t('Name')),
- 'destination_name' => array('title' => t('Destination'), 'html' => TRUE),
- 'profile_name' => array('title' => t('Profile'), 'html' => TRUE),
- 'frequency_description' => array('title' => t('Frequency')),
- 'keep_description' => array('title' => t('Keep')),
- 'enabled_description' => array('title' => t('Enabled')),
- 'last_run_description' => array('title' => t('Last run')),
- ) + $out;
- return $out;
- }
-
- /**
- * Get a row of data to be used in a list of items of this type.
- */
- function get_list_row() {
- drupal_add_css(drupal_get_path('module', 'backup_migrate') .'/backup_migrate.css');
- $row = parent::get_list_row();
- if (!$this->is_enabled()) {
- foreach ($row as $key => $field) {
- $row[$key] = array('data' => $field, 'class' => 'schedule-list-disabled');
- }
- }
- return $row;
- }
-
- /**
- * Is the schedule enabled and valid.
- */
- function is_enabled() {
- $destination = $this->get_destination();
- $profile = $this->get_profile();
- return (!empty($this->enabled) && !empty($destination) && !empty($profile));
- }
-
- /**
- * Get the destination object of the schedule.
- */
- function get_destination() {
- backup_migrate_include('destinations');
- return backup_migrate_get_destination($this->get('destination_id'));
- }
-
- /**
- * Get the name of the destination.
- */
- function get_destination_name() {
- if ($destination = $this->get_destination()) {
- return check_plain($destination->get_name());
- }
- return '
'. t("Missing") .'
';
- }
-
- /**
- * Get the destination of the schedule.
- */
- function get_profile() {
- backup_migrate_include('profiles');
- return backup_migrate_get_profile($this->get('profile_id'));
- }
-
- /**
- * Get the name of the source.
- */
- function get_profile_name() {
- if ($profile = $this->get_profile()) {
- return check_plain($profile->get_name());
- }
- return ''. t("Missing") .'
';
- }
-
- /**
- * Format a frequency in human-readable form.
- */
- function get_frequency_description() {
- $period = $this->get_frequency_period();
- $out = format_plural(($this->period / $period['seconds']), $period['singular'], $period['plural']);
- return $out;
- }
-
- /**
- * Format the number to keep in human-readable form.
- */
- function get_keep_description() {
- return !empty($this->keep) ? $this->keep : t('All');
- }
-
- /**
- * Format the enabled status in human-readable form.
- */
- function get_enabled_description() {
- return !empty($this->enabled) ? t('Enabled') : t('Disabled');
- }
-
- /**
- * Format the enabled status in human-readable form.
- */
- function get_last_run_description() {
- $last_run = $this->get('last_run');
- return !empty($last_run) ? format_date($last_run, 'small') : t('Never');
- }
-
- /**
- * Get the number of excluded tables.
- */
- function get_exclude_tables_count() {
- return count($this->exclude_tables) ? count($this->exclude_tables) : t("No tables excluded");
- }
-
- /**
- * Get the number of excluded tables.
- */
- function get_nodata_tables_count() {
- return count($this->nodata_tables) ? count($this->nodata_tables) : t("No data omitted");
- }
-
- /**
- * Get the edit form.
- */
- function edit_form() {
- $form = parent::edit_form();
- backup_migrate_include('destinations', 'profiles');
-
- $form['enabled'] = array(
- "#type" => "checkbox",
- "#title" => t("Enabled"),
- "#default_value" => $this->get('enabled'),
- );
- $form['name'] = array(
- "#type" => "textfield",
- "#title" => t("Schedule Name"),
- "#default_value" => $this->get('name'),
- );
-
- $form += _backup_migrate_get_source_form($this->get('source_id'));
-
- $form['profile_id'] = array(
- "#type" => "select",
- "#title" => t("Settings Profile"),
- "#options" => _backup_migrate_get_profile_form_item_options(),
- "#default_value" => $this->get('profile_id'),
- );
- $form['profile_id']['#description'] = ' '. l(t("Create new profile"), BACKUP_MIGRATE_MENU_PATH . "/profile/add");
- if (!$form['profile_id']['#options']) {
- $form['profile_id']['#options'] = array('0' => t('-- None Available --'));
- }
-
- $period_options = array();
- foreach ($this->frequency_periods() as $type => $period) {
- $period_options[$type] = $period['title'];
- }
- $default_period = $this->get_frequency_period();
- $default_period_num = $this->get('period') / $default_period['seconds'];
-
- $form['period'] = array(
- "#type" => "item",
- "#title" => t("Backup every"),
- "#prefix" => '',
- "#suffix" => '
',
- "#tree" => TRUE,
- );
- $form['period']['number'] = array(
- "#type" => "textfield",
- "#size" => 6,
- "#default_value" => $default_period_num,
- );
- $form['period']['type'] = array(
- "#type" => "select",
- "#options" => $period_options,
- "#default_value" => $default_period['type'],
- );
-
- $form['keep'] = array(
- "#type" => "textfield",
- "#size" => 6,
- "#title" => t("Number of Backup files to keep"),
- "#description" => t("The number of backup files to keep before deleting old ones. Use 0 to never delete backups. Other files in the destination directory will get deleted if you specify a limit. "),
- "#default_value" => $this->get('keep'),
- );
- $destination_options = _backup_migrate_get_destination_form_item_options('scheduled backup');
- $form['destination_id'] = array(
- "#type" => "select",
- "#title" => t("Destination"),
- "#description" => t("Choose where the backup file will be saved. Backup files contain sensitive data, so be careful where you save them."),
- "#options" => $destination_options,
- "#default_value" => $this->get('destination_id'),
- );
- $form['destination_id']['#description'] .= ' '. l(t("Create new destination"), BACKUP_MIGRATE_MENU_PATH . "/destination/add");
-
- return $form;
- }
-
- /**
- * Submit the edit form.
- */
- function edit_form_validate($form, &$form_state) {
- if (!is_numeric($form_state['values']['period']['number']) || $form_state['values']['period']['number'] <= 0) {
- form_set_error('period][number', t('Backup period must be a number greater than 0.'));
- }
- if (!is_numeric($form_state['values']['keep']) || $form_state['values']['keep'] < 0) {
- form_set_error('keep', t('Number to keep must be an integer greater than or equal to 0.'));
- }
- parent::edit_form_validate($form, $form_state);
- }
-
- /**
- * Submit the edit form.
- */
- function edit_form_submit($form, &$form_state) {
- $periods = $this->frequency_periods();
- $period = $periods[$form_state['values']['period']['type']];
- $form_state['values']['period'] = $form_state['values']['period']['number'] * $period['seconds'];
- parent::edit_form_submit($form, $form_state);
- }
-
- /**
- * Get the period of the frequency (ie: seconds, minutes etc.)
- */
- function get_frequency_period() {
- foreach (array_reverse($this->frequency_periods()) as $period) {
- if ($period['seconds'] && ($this->period % $period['seconds']) === 0) {
- return $period;
- }
- }
- }
-
- /**
- * Get a list of available backup periods. Only returns time periods which have a
- * (reasonably) consistent number of seconds (ie: no months).
- */
- function frequency_periods() {
- return array(
- 'seconds' => array('type' => 'seconds', 'seconds' => 1, 'title' => t('Seconds'), 'singular' => t('Once a second'), 'plural' => t('Every @count seconds')),
- 'minutes' => array('type' => 'minutes', 'seconds' => 60, 'title' => t('Minutes'), 'singular' => t('Once a minute'), 'plural' => t('Every @count minutes')),
- 'hours' => array('type' => 'hours', 'seconds' => 3600, 'title' => t('Hours'), 'singular' => t('Once an hour'), 'plural' => t('Every @count hours')),
- 'days' => array('type' => 'days', 'seconds' => 86400, 'title' => t('Days'), 'singular' => t('Once a day'), 'plural' => t('Every @count days')),
- 'weeks' => array('type' => 'weeks', 'seconds' => 604800, 'title' => t('Weeks'), 'singular' => t('Once a week'), 'plural' => t('Every @count weeks')),
- );
- }
-
- /**
- * Get the message to send to the user when confirming the deletion of the item.
- */
- function delete_confirm_message() {
- return t('Are you sure you want to delete the profile %name? Any schedules using this profile will be disabled.', array('%name' => $this->get('name')));
- }
-
- /**
- * Perform the cron action. Run the backup if enough time has elapsed.
- */
- function cron() {
- $now = time();
-
- // Add a small negative buffer (1% of the entire period) to the time to account for slight difference in cron run length.
- $wait_time = $this->period - ($this->period * variable_get('backup_migrate_schedule_buffer', 0.01));
-
- if ($this->is_enabled() && ($now - $this->get('last_run')) >= $wait_time) {
- if ($settings = $this->get_profile()) {
- $settings->destination_id = $this->destination_id;
- $settings->source_id = $this->source_id;
- $this->update_last_run($now);
- backup_migrate_perform_backup($settings);
- $this->remove_expired_backups();
- }
- else {
- backup_migrate_backup_fail("Schedule '%schedule' could not be run because requires a profile which is missing.", array('%schedule' => $schedule->get_name()), $settings);
- }
- }
- }
-
- /**
- * Set the last run time of a schedule to the given timestamp, or now if none specified.
- */
- function update_last_run($timestamp = NULL) {
- if ($timestamp === NULL) {
- $timestamp = time();
- }
- variable_set('backup_migrate_schedule_last_run_' . $this->get('id'), $timestamp);
- }
-
-/**
- * Set the last run time of a schedule to the given timestamp, or now if none specified.
- */
- function get_last_run($timestamp = NULL) {
- return variable_get('backup_migrate_schedule_last_run_' . $this->get('id'), 0);
- }
-
-
- /**
- * Remove older backups keeping only the number specified by the aministrator.
- */
- function remove_expired_backups() {
- backup_migrate_include('destinations');
-
- $num_to_keep = $this->keep;
- // If num to keep is not 0 (0 is infinity).
- if ($num_to_keep && ($destination = $this->get_destination())) {
- $i = 0;
- if ($destination->op('delete') && $destination_files = $destination->list_files()) {
- // Sort the files by modified time.
- foreach ($destination_files as $file) {
- if ($file->is_recognized_type() && $destination->can_delete_file($file->file_id())) {
- $files[str_pad($file->info('filetime'), 10, "0", STR_PAD_LEFT) ."-". $i++] = $file;
- }
- }
-
- // If we are beyond our limit, remove as many as we need.
- $num_files = count($files);
-
- if ($num_files > $num_to_keep) {
- $num_to_delete = $num_files - $num_to_keep;
- // Sort by date.
- ksort($files);
- // Delete from the start of the list (earliest).
- for ($i = 0; $i < $num_to_delete; $i++) {
- $file = array_shift($files);
- $destination->delete_file($file->file_id());
- }
- }
- }
- }
- }
-}
diff --git a/sites/all/modules/contrib/better_formats/LICENSE.txt b/sites/all/modules/contrib/better_formats/LICENSE.txt
deleted file mode 100644
index d159169d..00000000
--- a/sites/all/modules/contrib/better_formats/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/better_formats/README.txt b/sites/all/modules/contrib/better_formats/README.txt
deleted file mode 100644
index 08837c5a..00000000
--- a/sites/all/modules/contrib/better_formats/README.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-This very basic documentation for during development.
-Better docs will be generated closer to a full release.
-
-
-The only items currently implented in the D7 version of Better Formats are:
-
-1. Display options: When BF is enabled you will have permissions at
- admin/people/permissions to control per role display of:
- 1. format tips
- 2. format tips link
- 3. format selection for [entity]
-
- #3 is actually several permissions. There is one for each entity in your site.
-
-2. Simple field level default format.
- This allows you set a field level default format using the standard "Default Value"
- setting of a field. This is only possibly normally if you enter something in the
- text field for the field api to save the format too. BF gives you the ability
- to set the format WITHOUT having to set a value in the field.
-
- 1. At admin/config/content/formats/settings enable "Use field default" option.
- 2. Create a text type of field on one of your content types.
- 3. Ensure you set the "Text processing" option to "Filtered text".
- 4. Save the field.
- 5. Now go back and edit the field you just saved. This is required because of
- how the field default value option works.
- 6. You will now see a "Text format" dropdown below your field in the
- "Default Value" area. Set the default format in the dropdown.
- 7. Save the field. Default will now be used on all new content forms for that field.
-
diff --git a/sites/all/modules/contrib/better_formats/better_formats.admin_defaults.inc b/sites/all/modules/contrib/better_formats/better_formats.admin_defaults.inc
deleted file mode 100644
index 64363bb8..00000000
--- a/sites/all/modules/contrib/better_formats/better_formats.admin_defaults.inc
+++ /dev/null
@@ -1,240 +0,0 @@
- TRUE,
- );
-
- $nform = better_formats_get_role_default_fields('node');
- $cform = better_formats_get_role_default_fields('comment');
- $bform = better_formats_get_role_default_fields('block');
- $form = array_merge($form, $nform, $cform, $bform);
-
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save defaults'),
- );
-
- return $form;
-}
-
-/**
- * Validates better_formats_admin_filter_form.
- *
- * @see better_formats_defaults_admin_form()
- * @see better_formats_defaults_admin_form_submit()
- */
-function better_formats_defaults_admin_form_validate($form, &$form_state) {
- $formats = filter_formats();
- foreach ($formats as $fid => $format) {
- $roles[$fid] = explode(',', $format->roles);
- }
- // Get roles that have administer filters permission.
- $admin_roles = better_formats_get_roles_by_perm('administer filters');
-
- foreach ($form_state['values'] as $key => $values) {
- if (strpos($key, 'node-') === 0 || strpos($key, 'comment-') === 0 || strpos($key, 'block-') === 0) {
- list($type, $rid) = explode('-', $key);
- if (in_array($rid, $admin_roles)) {
- // Role has the 'administer filters' permission so it can use all formats.
- continue;
- }
- $fid = $values['format'];
- $site_default = filter_resolve_format(FILTER_FORMAT_DEFAULT);
- if ($fid != 0 && !in_array($rid, $roles[$fid]) && $fid !== $site_default) {
- form_set_error($key, t('Role does not have access to selected format.'));
- }
- }
- }
-}
-
-/**
- * Updates database from better_formats_admin_filter_form.
- *
- * @see better_formats_defaults_admin_form()
- * @see better_formats_defaults_admin_form_validate()
- */
-function better_formats_defaults_admin_form_submit($form, &$form_state) {
- // Update DB.
- $sql = "UPDATE {better_formats_defaults}
- SET format=%d, weight=%d
- WHERE rid=%d AND type='%s'";
-
- foreach ($form_state['values'] as $key => $values) {
- if (strpos($key, 'node-') === 0 || strpos($key, 'comment-') === 0 || strpos($key, 'block-') === 0) {
- list($type, $rid) = explode('-', $key);
- db_query($sql, $values['format'], $values['weight'], $rid, $type);
- }
- }
-
- drupal_set_message(t('Defaults have been saved.'));
-}
-
-/**
- * Builds FAPI form elements for the default format selection.
- *
- * @param $mode
- * 'node', 'comment', or 'block'. Top most level type for requested default.
- * @param $node_type
- * Type of node this request is for.
- * @return
- * FAPI array for the default select field.
- */
-function better_formats_get_role_default_fields($mode, $node_type = '') {
- $form = array();
- $format_options = better_formats_get_formats_per_role();
- $type = $types = $mode;
- $per_node_type = variable_get('better_formats_per_node_type', FALSE);
-
- if ($per_node_type && $node_type) {
- $type = $mode . '/' . $node_type;
- $types = $type . "','" . $mode;
- }
-
- // get data from db
- $sql = "SELECT bf.*, role.name
- FROM {better_formats_defaults} AS bf
- INNER JOIN {role} AS role
- ON bf.rid = role.rid
- WHERE bf.type IN ('$types')
- ORDER BY bf.type_weight DESC, bf.weight, role.rid";
- $result = db_query($sql);
-
- $roles_set = array();
-
- while ($role = db_fetch_object($result)) {
- if (in_array($role->rid, $roles_set)) {
- continue;
- }
-
- $roles_set[] = $role->rid;
- $key = $mode . '-' . $role->rid;
-
- $form[$key]['role'] = array(
- '#value' => $role->name,
- );
- $form[$key]['format'] = array(
- '#type' => 'select',
- '#options' => $format_options[$role->rid],
- '#default_value' => $role->format,
- '#attributes' => array('class' => 'bf-default-formats'),
- );
- $form[$key]['weight'] = array(
- '#type' => 'weight',
- '#delta' => 25,
- '#default_value' => $role->weight,
- );
- }
-
- return $form;
-}
-
-/**
- * Retrieve the formats available to users by role.
- *
- * Gets all formats then creates an array keyed by role IDs
- * that lists the formats available to that role. This is determined
- * by Drupal core's format permissions set at
- * admin/settings/filters/[filter_id].
- *
- * @return
- * Multi-dim array with role IDs for keys and list of allowed formats.
- *
- * @see better_formats_get_role_default_fields()
- */
-function better_formats_get_formats_per_role() {
- $formats = filter_formats();
- $roles = user_roles();
-
- // Get roles that have administer filters permission.
- $admin_roles = better_formats_get_roles_by_perm('administer filters');
-
- $site_default_format = filter_resolve_format(FILTER_FORMAT_DEFAULT);
-
- foreach ($formats as $format) {
- $roles_allowed = $format->roles ? explode(',', trim($format->roles, ',')) : array();
- foreach ($roles as $rid => $role) {
- $format_options[$rid][0] = t('Site default');
- if ($format->format == $site_default_format || in_array($rid, $admin_roles) || in_array($rid, $roles_allowed)) {
- $format_options[$rid][$format->format] = $format->name;
- }
- }
- }
-
- return $format_options;
-}
-
-/**
- * Get a list of roles that have a permission.
- *
- * @param $perm
- * Permission string to get roles for.
- * @param $reset
- * Boolean to clear static cache.
- * @return
- * An array of role IDs that have the requested permission.
- */
-function better_formats_get_roles_by_perm($perm, $reset = FALSE) {
- static $roles;
- if ($reset || !isset($roles[$perm])) {
- $sql = "SELECT rid
- FROM {permission}
- WHERE perm LIKE '%$perm%'
- ORDER BY rid";
- $result = db_query($sql);
- $roles[$perm] = array();
- while ($row = db_fetch_object($result)) {
- $roles[$perm][] = $row->rid;
- }
- }
- return $roles[$perm];
-}
-
-/**
- * Process variables for better-defaults-admin-form.tpl.php.
- *
- * @param $vars
- * The $variables array contains the following arguments:
- * - $form
- */
-function template_preprocess_better_formats_defaults_admin_form(&$vars) {
- foreach (element_children($vars['form']) as $key) {
- $form_row = &$vars['form'][$key];
-
- //$type = strpos($key, 'node-') === 0 ? 'node' : 'comment';
- $type = substr($key, 0, strpos($key, '-'));
-
- if (isset($form_row['role'])) {
- // Set special classes needed for table drag and drop.
- $form_row['weight']['#attributes']['class'] = 'better-formats-role-' . $type . '-weight';
-
- $row = new stdClass();
- $row->role = drupal_render($form_row['role']);
- $row->format_select = drupal_render($form_row['format']);
- $row->weight_select = drupal_render($form_row['weight']);
-
- $vars[$type . '_default_rows'][$key] = $row;
- }
- }
-
- $vars['form_submit'] = drupal_render($vars['form']);
-}
diff --git a/sites/all/modules/contrib/better_formats/better_formats.admin_settings.inc b/sites/all/modules/contrib/better_formats/better_formats.admin_settings.inc
deleted file mode 100644
index 39e2c0fb..00000000
--- a/sites/all/modules/contrib/better_formats/better_formats.admin_settings.inc
+++ /dev/null
@@ -1,36 +0,0 @@
- 'fieldset',
- '#title' => t('Control'),
- );
- $form['control']['better_formats_per_field_core'] = array(
- '#type' => 'checkbox',
- '#title' => t('Use field default'),
- '#description' => t('Use the core field module default value to set the default format. This will force the default format even when the default field value is empty. To set a default format you must re-edit a text field after saving it with the "Filtered text" option turned on.'),
- '#default_value' => variable_get('better_formats_per_field_core', 0),
- );
- /*
- $form['control']['better_formats_per_node_type'] = array(
- '#type' => 'checkbox',
- '#title' => t('Control formats per node type'),
- '#description' => t('Control formats allowed and default formats per node type. Global settings will be used until a content type admin page is saved.'),
- '#default_value' => variable_get('better_formats_per_node_type', 0),
- );
- */
-
- return system_settings_form($form);
-}
diff --git a/sites/all/modules/contrib/better_formats/better_formats.info b/sites/all/modules/contrib/better_formats/better_formats.info
deleted file mode 100644
index 3f247425..00000000
--- a/sites/all/modules/contrib/better_formats/better_formats.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = Better Formats
-description = Enhances the core input format system by managing input format defaults and settings.
-core = 7.x
-configure = admin/config/content/formats
-
-; Information added by drupal.org packaging script on 2012-07-26
-version = "7.x-1.0-beta1"
-core = "7.x"
-project = "better_formats"
-datestamp = "1343262404"
-
diff --git a/sites/all/modules/contrib/better_formats/better_formats.install b/sites/all/modules/contrib/better_formats/better_formats.install
deleted file mode 100644
index 3e0e56c6..00000000
--- a/sites/all/modules/contrib/better_formats/better_formats.install
+++ /dev/null
@@ -1,39 +0,0 @@
-fields(array('weight' => 100))
- ->condition('name', 'better_formats')
- ->execute();
-}
-
-/**
- * Implements of hook_uninstall().
- */
-function better_formats_uninstall() {
- // Delete settings from varible table.
- db_delete('variable')
- ->condition('name', 'better_formats%', 'LIKE')
- ->execute();
-}
-
-/**
- * Update from 6.x-1.2 to 7.x-1.0.
- */
-/*
-function better_formats_update_7000() {
-
-}
-*/
\ No newline at end of file
diff --git a/sites/all/modules/contrib/better_formats/better_formats.module b/sites/all/modules/contrib/better_formats/better_formats.module
deleted file mode 100644
index 8cfd34f1..00000000
--- a/sites/all/modules/contrib/better_formats/better_formats.module
+++ /dev/null
@@ -1,412 +0,0 @@
- array(
- 'title' => t('Show format tips'),
- 'description' => t('Toggle display of format description help.'),
- ),
- 'show more format tips link' => array(
- 'title' => t('Show more format tips link'),
- 'description' => t('Toggle display of the "More information about text formats" link.'),
- ),
- );
- foreach ($entities as $type => $info) {
- if ($info['fieldable']) {
- $perms['show format selection for ' . $type] = array(
- 'title' => t('Show format selection for @entitys', array('@entity' => $type)),
- );
- }
- }
-
- return $perms;
-}
-
-/**
- * Implements hook_menu().
- */
-function better_formats_menu() {
- $items = array();
- $items['admin/config/content/formats/settings'] = array(
- 'title' => 'Settings',
- 'description' => 'Manage text formats',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('better_formats_admin_settings_form'),
- 'access arguments' => array('administer filters'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 3,
- 'file' => 'better_formats.admin_settings.inc',
- );
- /*
- $items['admin/config/content/formats/defaults'] = array(
- 'title' => 'Defaults',
- 'description' => 'Manage text formats',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('better_formats_defaults_admin_form'),
- 'access arguments' => array('administer filters'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 2,
- 'file' => 'better_formats.admin_defaults.inc',
- );
- */
- return $items;
-}
-
-/**
- * Implements of hook_element_info_alter().
- */
-function better_formats_element_info_alter(&$type) {
- // Our process callback must run immediately after filter_process_format().
- $filter_process_format_location = array_search('filter_process_format', $type['text_format']['#process']);
- $replacement = array('filter_process_format', 'better_formats_filter_process_format');
- array_splice($type['text_format']['#process'], $filter_process_format_location, 1, $replacement);
-}
-
-/**
- * Process callback for form elements that have a text format selector attached.
- *
- * This callback runs after filter_process_format() and performs additional
- * modifications to the form element.
- *
- * @see filter_process_format()
- */
-function better_formats_filter_process_format($element) {
- // Before we make any modifications to the element, record whether or not
- // filter_process_format() has determined that (for security reasons) the
- // user is not allowed to make any changes to this field. (This will happen
- // if the user does not have permission to use the currently-assigned text
- // format.)
- $access_denied_for_security = isset($element['format']['#access']) && !$element['format']['#access'];
-
- // Now hide several parts of the element for cosmetic reasons (depending on
- // the permissions of the current user).
- $show_selection = TRUE;
- if (isset($element['#entity_type'])) {
- $show_selection = user_access('show format selection for ' . $element['#entity_type']);
- }
- $show_tips = user_access('show format tips');
- $show_tips_link = user_access('show more format tips link');
- if (!$show_selection) {
- $element['format']['format']['#access'] = FALSE;
- }
- if (!$show_tips) {
- $element['format']['guidelines']['#access'] = FALSE;
- }
- if (!$show_tips_link) {
- $element['format']['help']['#access'] = FALSE;
- }
-
- // If the element represents a field attached to an entity, we may need to
- // adjust the allowed text format options. However, we don't want to touch
- // this if filter_process_format() has determined that (for security reasons)
- // the user is not allowed to make any changes; in that case, Drupal core
- // will hide the format selector and force the field to be saved with its
- // current values, and we should not do anything to alter that process.
- if (isset($element['#entity_type']) && !$access_denied_for_security) {
- $instance_info = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
- $bf = isset($instance_info['settings']['better_formats']) ? $instance_info['settings']['better_formats'] : NULL;
-
- // Need to only do this on create forms.
- if (!empty($element['#entity']) && !empty($element['#entity_type'])) {
- list($eid, $vid, $bundle) = entity_extract_ids($element['#entity_type'], $element['#entity']);
- if (empty($eid) && isset($bf) && !empty($bf['default_order_toggle']) && !empty($bf['default_order_wrapper']['formats'])) {
- $order = $bf['default_order_wrapper']['formats'];
- uasort($order, 'better_formats_text_format_sort');
-
- $options = array();
- foreach ($order as $id => $weight) {
- if (isset($element['format']['format']['#options'][$id])) {
- $options[$id] = $element['format']['format']['#options'][$id];
- }
- }
- $element['format']['format']['#options'] = $options;
- $element['format']['format']['#default_value'] = array_shift(array_keys($options));
- }
- }
-
- if (isset($bf) && !empty($bf['allowed_formats_toggle']) && !empty($bf['allowed_formats'])) {
- // Filter the list of available formats to those allowed on this field.
- $allowed_fields = array_filter($bf['allowed_formats']);
- $options = &$element['format']['format']['#options'];
- $options = array_intersect_key($options, $allowed_fields);
-
- // If there is only one allowed format, deny access to the text format
- // selector for cosmetic reasons, just like filter_process_format() does.
- if (count($options) == 1) {
- $element['format']['format']['#access'] = FALSE;
- $show_selection = FALSE;
- }
-
- // If there are no allowed formats, we need to deny access to the entire
- // field, since it doesn't make sense to add or edit content that does
- // not have a text format.
- if (empty($options)) {
- $element['#access'] = FALSE;
- }
- // Otherwise, if the current default format is no longer one of the
- // allowed options, a new default format must be assigned.
- elseif (!isset($options[$element['format']['format']['#default_value']])) {
- // If there is no text in the field, it is safe to automatically assign
- // a new default format. We pick the first available option to be
- // consistent with what filter_default_format() does.
- if (!isset($element['value']['#default_value']) || $element['value']['#default_value']==='') {
- $formats = array_keys($options);
- $element['format']['format']['#default_value'] = reset($formats);
- }
- // Otherwise, it is unsafe to automatically assign a new default format
- // (since this will display the content in a way that was not
- // originally intended and might be dangerous, e.g. if the content
- // contains an attempted XSS attack). A human must explicitly decide
- // which new format to assign, so we force the field to be required but
- // with no default value, similar to what filter_process_format() does.
- // Although filter_process_format() limits this functionality to users
- // with the 'administer filters' permission, we can allow it for any
- // user here since we know that the user already has permission to use
- // the current format; thus, there is no danger of exposing unformatted
- // text (for example, raw PHP code) that they are otherwise not allowed
- // to see.
- else {
- $element['format']['format']['#required'] = TRUE;
- $element['format']['format']['#default_value'] = NULL;
- // Force access to the format selector (it may have been denied
- // previously for cosmetic reasons).
- $element['format']['#access'] = TRUE;
- $element['format']['format']['#access'] = TRUE;
- }
- }
- }
- }
-
- // If the user is not supposed to see the text format selector, hide all
- // guidelines except those associated with the default format. We need to do
- // this at the end, since the above code may have altered the default format.
- if (!$show_selection && isset($element['format']['format']['#default_value'])) {
- foreach (element_children($element['format']['guidelines']) as $format) {
- if ($format != $element['format']['format']['#default_value']) {
- $element['format']['guidelines'][$format]['#access'] = FALSE;
- }
- }
- }
-
- // Hide the entire text format fieldset if the user is not supposed to see
- // anything inside it.
- if (!$show_selection && !$show_tips && !$show_tips_link) {
- $element['format']['#type'] = 'container';
- }
-
- return $element;
-}
-
-/**
- * Sort text formats by weight.
- */
-function better_formats_text_format_sort($a, $b) {
- return $a['weight'] > $b['weight'];
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function better_formats_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
- $settings = $form['#instance']['settings'];
- // Only alter fields with text processing and if admin has chosen.
- $text_processing = isset($settings['text_processing']);
- if ($text_processing && variable_get('better_formats_per_field_core', 0)) {
- // Add a submit handler to save default values on empty fields.
- $form['#submit'][] = 'better_formats_form_field_ui_edit_form_submit';
- }
-
- // If the field is a format-using text field, allow the admin to configure
- // which formats are allowed here.
- if ($text_processing) {
- // We have to set an explicit weight here so that we can put the allowed
- // formats list after it.
- $form['instance']['settings']['text_processing']['#weight'] = -3;
-
- $bf_settings = isset($settings['better_formats']) ? $settings['better_formats'] : array();
- // Add in our formats table
- $form['instance']['settings'] += better_formats_field_settings_form($bf_settings);
- }
-}
-
-/**
- * Build the settings form for Field API fields.
- *
- * @param $bf_form
- * The existing better formats settings form from the form element.
- */
-function better_formats_field_settings_form($bf_form = array()) {
- $formats = filter_formats();
- $form = array();
- $form['better_formats'] = array(
- '#tree' => TRUE,
- '#type' => 'fieldset',
- '#title' => t('Text Formats'),
- '#weight' => -2,
- '#states' => array(
- 'visible' => array(
- ':input[name="instance[settings][text_processing]"]' => array('value' => '1'),
- ),
- ),
- );
-
- foreach ($formats as $format_id => $format) {
- $allowed_options[$format_id] = $format->name;
- }
-
- $allowed_toggle_default = isset($bf_form['allowed_formats_toggle']) ? $bf_form['allowed_formats_toggle'] : FALSE;
- $allowed_defaults = isset($bf_form['allowed_formats']) ? $bf_form['allowed_formats'] : array();
- if (empty($allowed_defaults)) {
- $allowed_defaults = array_keys($allowed_options);
- }
-
- $form['better_formats']['allowed_formats_toggle'] = array(
- '#type' => 'checkbox',
- '#title' => t('Limit allowed text formats'),
- '#description' => t('Check the allowed formats below. If checked available text formats can be chosen.'),
- '#weight' => 1,
- '#default_value' => $allowed_toggle_default,
- );
- $form['better_formats']['allowed_formats'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Allowed formats'),
- '#options' => $allowed_options,
- '#description' => t('Select the text formats allowed for this field. Note that not all of these may appear on the form if a user does not have permission to use them. Warning: This affects existing content which may leave you unable to edit some fields. If that happens you must allow the format that field was saved in here.'),
- '#weight' => 2,
- '#default_value' => $allowed_defaults,
- '#states' => array(
- 'visible' => array(
- ':input[name="instance[settings][text_processing]"]' => array('value' => '1'),
- ':input[name="instance[settings][better_formats][allowed_formats_toggle]"]' => array('checked' => TRUE),
- ),
- ),
- );
-
- $order_toggle_default = isset($bf_form['default_order_toggle']) ? $bf_form['default_order_toggle'] : FALSE;
- $form['better_formats']['default_order_toggle'] = array(
- '#type' => 'checkbox',
- '#title' => t('Override default order'),
- '#description' => t('Override the gloabl order that will determine the default text format a user will get only on entity creation .'),
- '#weight' => 3,
- '#default_value' => $order_toggle_default,
- );
-
- $form['better_formats']['default_order_wrapper'] = array(
- //'#tree' => TRUE,
- '#type' => 'container',
- '#theme' => 'better_formats_field_default_order',
- '#weight' => 4,
- '#states' => array(
- 'visible' => array(
- ':input[name="instance[settings][text_processing]"]' => array('value' => '1'),
- ':input[name="instance[settings][better_formats][default_order_toggle]"]' => array('checked' => TRUE),
- ),
- ),
- );
-
- foreach ($formats as $key => $format) {
- $default = isset($bf_form['default_order_wrapper']['formats'][$key]) ? $bf_form['default_order_wrapper']['formats'][$key] : NULL;
- $rows[$key]['name'] = array('#markup' => $format->name);
- $rows[$key]['weight'] = array(
- '#type' => 'weight',
- '#default_value' => isset($default['weight']) ? $default['weight'] : $format->weight,
- '#delta' => 50,
- );
- $rows[$key]['#weight'] = isset($default['weight']) ? $default['weight'] : $format->weight;
- }
- $form['better_formats']['default_order_wrapper']['formats'] = $rows;
-
- return $form;
-}
-
-/**
- * Submit handler for field instance edit form.
- *
- * Copied and slightly modifed from field_ui_field_edit_form_submit().
- * @see field_ui_field_edit_form_submit()
- */
-function better_formats_form_field_ui_edit_form_submit($form, &$form_state) {
- $instance = $form_state['values']['instance'];
- $field = $form_state['values']['field'];
-
- // Only act on fields that have text processing enabled.
- if ($instance['settings']['text_processing'] == 1) {
- // Update any field settings that have changed.
- $field_source = field_info_field($instance['field_name']);
- $field = array_merge($field_source, $field);
- field_update_field($field);
-
- // Handle the default value.
- if (isset($form['instance']['default_value_widget'])) {
- $element = $form['instance']['default_value_widget'];
-
- // Extract field values.
- $items = array();
- field_default_extract_form_values(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
- // Commenting out the below line to not remove emtpy fields.
- //field_default_submit(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items, $element, $form_state);
-
- $instance['default_value'] = $items ? $items : NULL;
- }
-
- // Retrieve the stored instance settings to merge with the incoming values.
- $instance_source = field_read_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']);
- $instance = array_merge($instance_source, $instance);
- field_update_instance($instance);
- }
- // Messaging and redirect removed as this is added in the default handler.
-}
-
-/**
- * Implements hook_theme()
- */
-function better_formats_theme() {
- return array(
- 'better_formats_field_default_order' => array(
- 'render element' => 'form',
- )
- );
-}
-
-/**
- * Theme format default by role on field settings form.
- */
-function theme_better_formats_field_default_order(&$variables) {
- $form = $variables['form'];
-
- $rows = array();
- $output = drupal_render($form['override']);
- if (is_array($form)) {
- $order_form =& $form['formats'];
- $order_form['#sorted'] = FALSE;
- foreach (element_children($order_form, TRUE) as $name) {
- $order_form[$name]['weight']['#attributes']['class'][] = 'format-order-weight';
- $rows[] = array(
- 'data' => array(
- drupal_render($order_form[$name]['name']),
- drupal_render($order_form[$name]['weight']),
- ),
- 'class' => array('draggable'),
- );
- }
- }
-
- $header = array(
- t('Format'),
- t('Weight'),
- );
-
- $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'format-order')));
- drupal_add_tabledrag('format-order', 'order', 'sibling', 'format-order-weight', NULL, NULL, TRUE);
-
- return $output;
-}
diff --git a/sites/all/modules/contrib/browserclass/LICENSE.txt b/sites/all/modules/contrib/browserclass/LICENSE.txt
deleted file mode 100755
index d159169d..00000000
--- a/sites/all/modules/contrib/browserclass/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/browserclass/README.txt b/sites/all/modules/contrib/browserclass/README.txt
deleted file mode 100644
index 4373144c..00000000
--- a/sites/all/modules/contrib/browserclass/README.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-
--- SUMMARY --
-
-This small module helps theme-developers to deal with cross-browser compatibility.
-It makes easier to handle different types of non-widespread browsers just as much as it helps with using different versions of Internet Explorer.
-
-The module extends the $body_classes variable in page.tpl.php based on the enduser's browser, with the following:
- * ie
- * ie[version]
- * opera
- * safari
- * chrome
- * netscape
- * ff
- * konqueror
- * dillo
- * chimera
- * beonex
- * aweb
- * amaya
- * icab
- * lynx
- * galeon
- * operamini
-
-and with the following platforms:
- * win
- * ipad
- * ipod
- * iphone
- * mac
- * android
- * linux
- * nokia
- * blackberry
- * freebsd
- * openbsd
- * netbsd
-
-The module checks if the device is mobile and adds "mobile" or "desktop" class.
-
-The module also makes a $browser_classes variable available in page.tpl.php, which stores the data in an array, this way the developer can make use of it as needed, if he does not wish to use the $body_classes variable.
-
-
-
--- REQUIREMENTS --
-
-None.
-
-
--- CONFIGURATION --
-
-The module has a settings page (admin/config/user-interface/browserclass), where the administrator can choose between these options:
- * always add the class with JavaScript
- * only use JavaScript if page cache is enabled
-This page is available only users with "administer browser class" permission.
-
-
-
--- DEVELOPERS --
-
-Developers can add their own classes with hook_browserclass_classes(). More information in browserclass_hook.php file.
-
-
-
--- CONTACT --
-
-Kalman Hosszu (hosszu.kalman http://drupal.org/user/267481) http://www.kalman-hosszu.com/
-
diff --git a/sites/all/modules/contrib/browserclass/browserclass.api.php b/sites/all/modules/contrib/browserclass/browserclass.api.php
deleted file mode 100644
index d87304c9..00000000
--- a/sites/all/modules/contrib/browserclass/browserclass.api.php
+++ /dev/null
@@ -1,30 +0,0 @@
- 'Browser class',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('browserclass_settings_form'),
- 'access arguments' => array('administer browser class'),
- );
-
- return $items;
-}
-
-/**
- * Implementation of hook_permission().
- *
- * @return array An array of valid permissions for the browserclass module
- */
-function browserclass_permission() {
- return array(
- 'administer browser class' => array(
- 'title' => 'Administer browser class',
- 'description' => 'Configure Browser class module, set JavaScript operation.',
- 'restrict access' => TRUE,
- ),
- );
-}
-
-/**
- * Implementation of hook_init().
- */
-function browserclass_init() {
- if (((variable_get('browserclass_operation', BROWSERCLASS_OPERATION_WITHOUT_JS) == BROWSERCLASS_OPERATION_WITH_JS)
- || variable_get('cache', 0) != 0) && ($browser_classes = browserclass_get_classes())) {
-
- drupal_add_js(drupal_get_path('module', 'browserclass') . '/browserclass.js', array('scope' => 'footer'));
- }
-}
-
-/**
- * Implementation of hook_preprocess_html().
- *
- * @param array $vars
- */
-function browserclass_preprocess_html(&$vars) {
- if ((variable_get('browserclass_operation', BROWSERCLASS_OPERATION_WITHOUT_JS) == BROWSERCLASS_OPERATION_WITHOUT_JS) &&
- (variable_get('cache', 0) == 0) && ($browser_classes = browserclass_get_classes())) {
-
- $vars['classes_array'] = array_merge($vars['classes_array'], $browser_classes);
- $vars['browser_classes'] = $browser_classes;
-
- }
-}
-
-/**
- * Build browserclass_settings_form form.
- *
- * @param array $form_state
- * @return array The created form.
- */
-function browserclass_settings_form($form_state) {
- $form = array();
-
- $form['browserclass_operation'] = array(
- '#type' => 'radios',
- '#title' => t('Operation'),
- '#options' => array(
- BROWSERCLASS_OPERATION_WITH_JS => t('Always add the class with JavaScript'),
- BROWSERCLASS_OPERATION_WITHOUT_JS => t('Only use JavaScript if page cache is enabled'),
- ),
- '#default_value' => variable_get('browserclass_operation', BROWSERCLASS_OPERATION_WITHOUT_JS),
- );
-
- return system_settings_form($form);
-}
-
-/**
- * Get classes.
- *
- * @return array of classes
- */
-function browserclass_get_classes($types = BROWSERCLASS_ALL) {
- $classes = array();
-
- // User agent doesn't set always, for example on rss readers.
- if (isset($_SERVER['HTTP_USER_AGENT'])) {
- $agent = strtolower($_SERVER['HTTP_USER_AGENT']);
-
- if ($types & BROWSERCLASS_BROWSER) {
- $classes = array_merge($classes, browserclass_check_browser($agent));
- }
-
- if ($types & BROWSERCLASS_PLATFORM) {
- $classes = array_merge($classes, browserclass_check_platform($agent));
- }
-
- if ($types & BROWSERCLASS_OTHER_CLASSES) {
- // Merge other modules classes
- $classes = array_merge($classes, module_invoke_all('browserclass_classes', $agent));
- }
-
- if ($types & BROWSERCLASS_MOBILE) {
- $classes[] = browserclass_is_mobile_devide($agent, $classes) ? 'mobile' : 'desktop';
- }
- }
-
- return $classes;
-}
-
-/**
- * Detect browser.
- *
- * @param string $agent Lowercase version of user agent.
- * @return array of detected platforms
- */
-function browserclass_check_browser($agent) {
- $classes = array();
-
- // Add ie extra class with the version number
- $ie_pattern = '/(?:\b(ms)?ie\s+|\btrident\/7\.0;.*\s+rv:)(\d+)/';
- $ie_matches = array();
- $ie_m = preg_match($ie_pattern, $agent, $ie_matches);
-
- if ($ie_m === 1) {
- $classes[] = 'ie';
-
- if (isset($ie_matches[2])) {
- $classes[] = 'ie' . $ie_matches[2];
- }
- }
-
- if (stristr($agent, 'opera') !== FALSE) {
- $classes[] = 'opera';
- $aresult = explode('/', stristr($agent, 'version'));
- if(isset($aresult[1])) {
- $aversion = explode(' ', $aresult[1]);
- $classes[] = 'opera' . _browserclass_clear_version($aversion[0]);
- }
- }
-
- // Check for chrome desktop first, then chrome mobile, lastly check for
- // safari, as these are mutually exclusive.
- if (stristr($agent, 'chrome') !== FALSE) {
- $classes[] = 'chrome';
- $aresult = explode('/', stristr($agent, 'chrome'));
- $aversion = explode(' ', $aresult[1]);
- $classes[] = 'chrome' . _browserclass_clear_version($aversion[0]);
- }
- elseif (stristr($agent, 'crios') !== FALSE) {
- $classes[] = 'chrome';
-
- $aresult = explode('/', stristr($agent, 'crios'));
- if (isset($aresult[1])) {
- $aversion = explode(' ', $aresult[1]);
- $classes[] = 'chrome' . _browserclass_clear_version($aversion[0]);
- }
- }
- elseif (stristr($agent, 'safari') !== FALSE) {
- $classes[] = 'safari';
-
- $aresult = explode('/', stristr($agent, 'version'));
- if(isset($aresult[1])) {
- $aversion = explode(' ', $aresult[1]);
- $classes[] = 'safari' . _browserclass_clear_version($aversion[0]);
- }
- }
-
- if (stristr($agent, 'netscape') !== FALSE) {
- $classes[] = 'netscape';
- if (preg_match('/navigator\/([^ ]*)/', $agent, $matches)) {
- $classes[] = 'netscape' . _browserclass_clear_version($matches[1]);
- }
- elseif (preg_match('/netscape6?\/([^ ]*)/', $agent, $matches)) {
- $classes[] = 'netscape' . _browserclass_clear_version($matches[1]);
- }
- }
-
- if (stristr($agent, 'firefox') !== FALSE) {
- $classes[] = 'ff';
-
- if(preg_match("/firefox[\/ \(]([^ ;\)]+)/", $agent, $matches)) {
- $classes[] = 'ff' . _browserclass_clear_version($matches[1]);
- }
- }
-
- if (stristr($agent, 'konqueror') !== FALSE) {
- $classes[] = 'konqueror';
- $aresult = explode(' ', stristr($agent, 'konqueror'));
- $aversion = explode('/', $aresult[0]);
- $classes[] = 'konqueror' . _browserclass_clear_version($aversion[1]);
- }
-
- if (stristr($agent, 'dillo') !== FALSE) {
- $classes[] = 'dillo';
- }
-
- if (stristr($agent, 'chimera') !== FALSE) {
- $classes[] = 'chimera';
- }
-
- if (stristr($agent, 'beonex') !== FALSE) {
- $classes[] = 'beonex';
- }
-
- if (stristr($agent, 'aweb') !== FALSE) {
- $classes[] = 'aweb';
- }
-
- if (stristr($agent, 'amaya') !== FALSE) {
- $classes[] = 'amaya';
- }
-
- if (stristr($agent, 'icab') !== FALSE) {
- $classes[] = 'icab';
- }
-
- if (stristr($agent, 'lynx') !== FALSE) {
- $classes[] = 'lynx';
- }
-
- if (stristr($agent, 'galeon') !== FALSE) {
- $classes[] = 'galeon';
- }
-
- if (stristr($agent, 'opera mini') !== FALSE) {
- $classes[] = 'operamini';
-
- $resultant = stristr($agent, 'opera mini');
- if(preg_match('/\//', $resultant)) {
- $aresult = explode('/', $resultant);
- $aversion = explode(' ', $aresult[1]);
- $classes[] = 'operamini' . _browserclass_clear_version($aversion[0]);
- }
- else {
- $aversion = explode(' ', stristr($resultant, 'opera mini'));
- $classes[] = 'operamini' . _browserclass_clear_version($aversion[1]);
- }
- }
-
- return $classes;
-}
-
-/**
- * Detect platform.
- *
- * @param string $agent Lowercase version of user agent.
- * @return array of detected platforms
- */
-function browserclass_check_platform($agent) {
- $classes = array();
-
- if (stristr($agent, 'windows') !== FALSE) {
- $classes[] = 'win';
- }
- elseif (stristr($agent, 'ipad') !== FALSE) {
- $classes[] = 'ipad';
- }
- elseif (stristr($agent, 'ipod') !== FALSE) {
- $classes[] = 'ipod';
- }
- elseif (stristr($agent, 'iphone') !== FALSE) {
- $classes[] = 'iphone';
- }
- elseif (stristr($agent, 'mac') !== FALSE) {
- $classes[] = 'mac';
- }
- elseif (stristr($agent, 'android') !== FALSE) {
- $classes[] = 'android';
- }
- elseif (stristr($agent, 'linux') !== FALSE) {
- $classes[] = 'linux';
- }
- elseif (stristr($agent, 'nokia') !== FALSE) {
- $classes[] = 'nokia';
- }
- elseif (stristr($agent, 'blackberry') !== FALSE) {
- $classes[] = 'blackberry';
- }
- elseif (stristr($agent, 'freebsd') !== FALSE) {
- $classes[] = 'freebsd';
- }
- elseif (stristr($agent, 'openbsd') !== FALSE) {
- $classes[] = 'openbsd';
- }
- elseif (stristr($agent, 'netbsd') !== FALSE) {
- $classes[] = 'netbsd';
- }
-
- return $classes;
-}
-
-function browserclass_is_mobile_devide($agent, $classes) {
- $mobile_devices = array('ipad', 'ipod', 'iphone', 'android', 'blackberry', 'operamini');
-
- foreach ($mobile_devices as $mobile) {
- if (in_array($mobile, $classes)) {
- return TRUE;
- }
- }
-
- if (isset($_SERVER['HTTP_X_WAP_PROFILE'])||isset($_SERVER['HTTP_PROFILE'])) {
- return TRUE;
- }
-
- if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|vodafone|o2|pocket|kindle|mobile|pda|psp|treo)/', $agent)) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Remove not supported characters from version.
- *
- * @param string $version
- * @return string
- */
-function _browserclass_clear_version($version) {
- $version = preg_replace('/[^0-9,.,a-z,A-Z-]/','',$version);
- return substr($version, 0, strpos($version, '.'));
-}
diff --git a/sites/all/modules/contrib/browserclass/browserclass.tokens.inc b/sites/all/modules/contrib/browserclass/browserclass.tokens.inc
deleted file mode 100644
index a0aaa6bb..00000000
--- a/sites/all/modules/contrib/browserclass/browserclass.tokens.inc
+++ /dev/null
@@ -1,139 +0,0 @@
- t('Browser classes'),
- 'description' => t('Token for browser class.'),
- );
- //Tokens for browser classes token type.
- $browserclass['browser-classes'] = array(
- 'name' => t('Browser classes'),
- 'description' => t('The current user\'s browser classes.'),
- );
-
- $browserclass['browser'] = array(
- 'name' => t('Browser'),
- 'description' => t('Type of the browser.'),
- );
-
- $browserclass['platform'] = array(
- 'name' => t('Platform'),
- 'description' => t('Type of the platform.'),
- );
-
- $browserclass['device'] = array(
- 'name' => t('Device'),
- 'description' => t('Device info.'),
- );
-
- $browserclass['hook-classes'] = array(
- 'name' => t('Extra classes'),
- 'description' => t('Extra hook classes.'),
- );
- //User tokens.
- $user['browserclass'] = array(
- 'name' => t('Browser classes'),
- 'description' => t('The current user\'s browser classes.'),
- 'type' => 'browserclass',
- );
- //Site information tokens.
- $site['browserclass'] = array(
- 'name' => t('Browser classes'),
- 'description' => t('The current user\'s browser classes.'),
- 'type' => 'browserclass',
- );
-
- return array(
- 'types' => $types,
- 'tokens' => array(
- 'browserclass' => $browserclass,
- 'user' => $user,
- 'site' => $site,
- ),
- );
-}
-
-/**
- * Implementation of hook_tokens()
- *
- * @param type $type
- * @param type $tokens
- * @param type $data
- * @param type $options
- * @return type
- */
-function browserclass_tokens($type, $tokens, $data, $options) {
- $replacements = array();
- //Browser class tokens.
- if ($type == 'browserclass') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'browser-classes':
- $browser_classes = implode(' ', browserclass_get_classes());
- $replacements[$original] = check_plain($browser_classes);
- break;
- case 'browser':
- $browser = implode(' ', browserclass_get_classes(BROWSERCLASS_BROWSER));
- $replacements[$original] = check_plain($browser);
- break;
- case 'platform':
- $platform = implode(' ', browserclass_get_classes(BROWSERCLASS_PLATFORM));
- $replacements[$original] = check_plain($platform);
- break;
- case 'device':
- $device = implode(' ', browserclass_get_classes(BROWSERCLASS_MOBILE));
- $replacements[$original] = check_plain($device);
- break;
- case 'hook-classes':
- $hook_classes = implode(' ', browserclass_get_classes(BROWSERCLASS_OTHER_CLASSES));
- $replacements[$original] = check_plain($hook_classes);
- break;
- }
- }
- }
- //User tokens.
- if ($type == 'user') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'browserclass':
- $browser_classes = implode(' ', browserclass_get_classes());
- $replacements[$original] = check_plain($browser_classes);
- break;
- }
- }
- // Chained token relationships.
- if ($browserclass_tokens = token_find_with_prefix($tokens, 'browserclass')) {
- $replacements += token_generate('browserclass', $browserclass_tokens, array(), $options);
- }
- }
-
- //Site information tokens.
- if ($type == 'site') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'browserclass':
- $browser_classes = implode(' ', browserclass_get_classes());
- $replacements[$original] = check_plain($browser_classes);
- break;
- }
- }
- // Chained token relationships.
- if ($browserclass_tokens = token_find_with_prefix($tokens, 'browserclass')) {
- $replacements += token_generate('browserclass', $browserclass_tokens, array(), $options);
- }
- }
-
- return $replacements;
-}
diff --git a/sites/all/modules/contrib/captcha/LICENSE.txt b/sites/all/modules/contrib/captcha/LICENSE.txt
deleted file mode 100644
index d159169d..00000000
--- a/sites/all/modules/contrib/captcha/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/captcha/README.txt b/sites/all/modules/contrib/captcha/README.txt
deleted file mode 100644
index 0affa5f9..00000000
--- a/sites/all/modules/contrib/captcha/README.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-Readme file for the CAPTCHA module for Drupal
----------------------------------------------
-
-captcha.module is the basic CAPTCHA module, offering general CAPTCHA
-administration and a simple math challenge.
-
-Submodule image_captcha.module offers an image based challenge.
-
-Installation:
- Installation is like with all normal drupal modules:
- extract the 'captcha' folder from the tar ball to the
- modules directory from your website (typically sites/all/modules).
-
-Dependencies:
- The basic CAPTCHA module has no dependencies, nothing special is required.
-
-Conflicts/known issues:
- CAPTCHA and page caching do not work together currently.
- However, the CAPTCHA module does support the Drupal core page
- caching mechanism: it just disables the caching of the pages
- where it has to put its challenges.
- If you use other caching mechanisms, it is possible that CAPTCHA's
- won't work, and you get error messages like 'CAPTCHA validation
- error: unknown CAPTCHA session ID'.
-
-Configuration:
- The configuration page is at admin/config/people/captcha,
- where you can configure the CAPTCHA module
- and enable challenges for the desired forms.
- You can also tweak the image CAPTCHA to your liking.
diff --git a/sites/all/modules/contrib/captcha/captcha.admin.inc b/sites/all/modules/contrib/captcha/captcha.admin.inc
deleted file mode 100644
index 0d095aed..00000000
--- a/sites/all/modules/contrib/captcha/captcha.admin.inc
+++ /dev/null
@@ -1,516 +0,0 @@
- $type, '@module' => $module));
- }
- }
- }
- return $captcha_types;
-}
-
-/**
- * Form builder function for the general CAPTCHA configuration
- */
-function captcha_admin_settings() {
- module_load_include('inc', 'captcha');
-
- // Use javascript for some added usability on admin form.
- drupal_add_js(drupal_get_path('module', 'captcha') . '/captcha.js');
-
- // Configuration of which forms to protect, with what challenge.
- $form['captcha_form_protection'] = array(
- '#type' => 'fieldset',
- '#title' => t('Form protection'),
- '#description' => t("Select the challenge type you want for each of the listed forms (identified by their so called form_id 's). You can easily add arbitrary forms with the textfield at the bottom of the table or with the help of the option Add CAPTCHA administration links to forms below."),
- );
- $form['captcha_form_protection']['captcha_default_challenge'] = array(
- '#type' => 'select',
- '#title' => t('Default challenge type'),
- '#description' => t('Select the default challenge type for CAPTCHAs. This can be overriden for each form if desired.'),
- '#options' => _captcha_available_challenge_types(FALSE),
- '#default_value' => variable_get('captcha_default_challenge', 'captcha/Math'),
- );
- // List known form_ids.
- $form['captcha_form_protection']['captcha_form_id_overview'] = array(
- '#theme' => 'captcha_admin_settings_captcha_points',
- '#tree' => TRUE,
- );
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'] = array();
- $captcha_type_options = _captcha_available_challenge_types();
- $result = db_select('captcha_points', 'cp')->fields('cp')->orderBy('form_id')->execute();
- foreach ($result as $captcha_point) {
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id] = array();
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['form_id'] = array(
- '#markup' => $captcha_point->form_id,
- );
- // Select widget for CAPTCHA type.
- if (isset($captcha_point->module) && $captcha_point->module) {
- $captcha_type = $captcha_point->module . '/' . $captcha_point->captcha_type;
- }
- elseif (isset($captcha_point->captcha_type) && ($captcha_point->captcha_type == 'default')) {
- $captcha_type = 'default';
- }
- else {
- $captcha_type = 'none';
- }
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['captcha_type'] = array(
- '#type' => 'select',
- '#default_value' => $captcha_type,
- '#options' => $captcha_type_options,
- );
- // Additional operations.
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_captcha_points'][$captcha_point->form_id]['operations'] = array(
- '#markup' => implode(", ", array(
- l(t('delete'), "admin/config/people/captcha/captcha/captcha_point/{$captcha_point->form_id}/delete"),
- ))
- );
- }
-
- // Form items for new form_id.
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point'] = array();
- // Textfield for form_id.
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'] = array(
- '#type' => 'textfield',
- '#size' => 16,
- );
- // Select widget for CAPTCHA type.
- $form['captcha_form_protection']['captcha_form_id_overview']['captcha_new_captcha_point']['captcha_type'] = array(
- '#type' => 'select',
- '#default_value' => 'none',
- '#options' => $captcha_type_options,
- );
-
- // Field for the CAPTCHA administration mode.
- $form['captcha_form_protection']['captcha_administration_mode'] = array(
- '#type' => 'checkbox',
- '#title' => t('Add CAPTCHA administration links to forms'),
- '#default_value' => variable_get('captcha_administration_mode', FALSE),
- '#description' => t('This option makes it easy to manage CAPTCHA settings on forms. When enabled, users with the administer CAPTCHA settings permission will see a fieldset with CAPTCHA administration links on all forms, except on administrative pages.'),
- );
- // Field for the CAPTCHAs on admin pages.
- $form['captcha_form_protection']['captcha_allow_on_admin_pages'] = array(
- '#type' => 'checkbox',
- '#title' => t('Allow CAPTCHAs and CAPTCHA administration links on administrative pages'),
- '#default_value' => variable_get('captcha_allow_on_admin_pages', FALSE),
- '#description' => t("This option makes it possible to add CAPTCHAs to forms on administrative pages. CAPTCHAs are disabled by default on administrative pages (which shouldn't be accessible to untrusted users normally) to avoid the related overhead. In some situations, e.g. in the case of demo sites, it can be usefull to allow CAPTCHAs on administrative pages."),
- );
-
- // Button for clearing the CAPTCHA placement cache.
- // Based on Drupal core's "Clear all caches" (performance settings page).
- $form['captcha_form_protection']['captcha_placement_caching'] = array(
- '#type' => 'item',
- '#title' => t('CAPTCHA placement caching'),
- '#description' => t('For efficiency, the positions of the CAPTCHA elements in each of the configured forms are cached. Most of the time, the structure of a form does not change and it would be a waste to recalculate the positions every time. Occasionally however, the form structure can change (e.g. during site building) and clearing the CAPTCHA placement cache can be required to fix the CAPTCHA placement.'),
- );
- $form['captcha_form_protection']['captcha_placement_caching']['captcha_placement_cache_clear'] = array(
- '#type' => 'submit',
- '#value' => t('Clear the CAPTCHA placement cache'),
- '#submit' => array('captcha_clear_captcha_placement_cache_submit'),
- );
-
- // Configuration option for adding a CAPTCHA description.
- $form['captcha_add_captcha_description'] = array(
- '#type' => 'checkbox',
- '#title' => t('Add a description to the CAPTCHA'),
- '#description' => t('Add a configurable description to explain the purpose of the CAPTCHA to the visitor.'),
- '#default_value' => variable_get('captcha_add_captcha_description', TRUE),
- );
- // Textfield(s) for the CAPTCHA description.
- if (module_exists('locale')) {
- $langs = locale_language_list();
- $form['captcha_descriptions'] = array(
- '#type' => 'fieldset',
- '#title' => t('CAPTCHA description'),
- '#description' => t('Configurable description of the CAPTCHA. An empty entry will reset the description to default.'),
- '#attributes' => array('id' => 'edit-captcha-description-wrapper'),
- );
- foreach ($langs as $lang_code => $lang_name) {
- $form['captcha_descriptions']["captcha_description_$lang_code"] = array(
- '#type' => 'textfield',
- '#title' => t('For language %lang_name (code %lang_code)', array('%lang_name' => $lang_name, '%lang_code' => $lang_code)),
- '#default_value' => _captcha_get_description($lang_code),
- '#maxlength' => 256,
- );
- }
- }
- else {
- $form['captcha_description'] = array(
- '#type' => 'textfield',
- '#title' => t('Challenge description'),
- '#description' => t('Configurable description of the CAPTCHA. An empty entry will reset the description to default.'),
- '#default_value' => _captcha_get_description(),
- '#maxlength' => 256,
- '#attributes' => array('id' => 'edit-captcha-description-wrapper'),
- );
- }
-
- // Option for case sensitive/insensitive validation of the responses.
- $form['captcha_default_validation'] = array(
- '#type' => 'radios',
- '#title' => t('Default CAPTCHA validation'),
- '#description' => t('Define how the response should be processed by default. Note that the modules that provide the actual challenges can override or ignore this.'),
- '#options' => array(
- CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE => t('Case sensitive validation: the response has to exactly match the solution.'),
- CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE => t('Case insensitive validation: lowercase/uppercase errors are ignored.'),
- ),
- '#default_value' => variable_get('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE),
- );
-
- // Field for CAPTCHA persistence.
- // TODO for D7: Rethink/simplify the explanation and UI strings.
- $form['captcha_persistence'] = array(
- '#type' => 'radios',
- '#title' => t('Persistence'),
- '#default_value' => variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE),
- '#options' => array(
- CAPTCHA_PERSISTENCE_SHOW_ALWAYS =>
- t('Always add a challenge.'),
- CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE =>
- t('Omit challenges in a multi-step/preview workflow once the user successfully responds to a challenge.'),
- CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE =>
- t('Omit challenges on a form type once the user successfully responds to a challenge on a form of that type.'),
- CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL =>
- t('Omit challenges on all forms once the user successfully responds to any challenge on the site.'),
- ),
- '#description' => t('Define if challenges should be omitted during the rest of a session once the user successfully responds to a challenge.'),
- );
-
- // Enable wrong response counter.
- $form['captcha_enable_stats'] = array(
- '#type' => 'checkbox',
- '#title' => t('Enable statistics'),
- '#description' => t('Keep CAPTCHA related counters in the status report . Note that this comes with a performance penalty as updating the counters results in clearing the variable cache.', array('!statusreport' => url('admin/reports/status'))),
- '#default_value' => variable_get('captcha_enable_stats', FALSE),
- );
-
- // Option for logging wrong responses.
- $form['captcha_log_wrong_responses'] = array(
- '#type' => 'checkbox',
- '#title' => t('Log wrong responses'),
- '#description' => t('Report information about wrong responses to the log .', array('!dblog' => url('admin/reports/dblog'))),
- '#default_value' => variable_get('captcha_log_wrong_responses', FALSE),
- );
-
- // Submit button.
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save configuration'),
- );
-
- return $form;
-}
-
-/**
- * Custom theme function for a table of (form_id -> CAPTCHA type) settings
- */
-function theme_captcha_admin_settings_captcha_points($variables) {
- $form = $variables['form'];
- $header = array('form_id', t('Challenge type'), t('Operations'));
- $rows = array();
- // Existing CAPTCHA points.
- foreach (element_children($form['captcha_captcha_points']) as $key) {
- $row = array();
- $row[] = drupal_render($form['captcha_captcha_points'][$key]['form_id']);
- $row[] = drupal_render($form['captcha_captcha_points'][$key]['captcha_type']);
- $row[] = drupal_render($form['captcha_captcha_points'][$key]['operations']);
- $rows[] = $row;
- }
- // For new CAPTCHA point.
- $row = array();
- $row[] = drupal_render($form['captcha_new_captcha_point']['form_id']);
- $row[] = drupal_render($form['captcha_new_captcha_point']['captcha_type']);
- $row[] = '';
- $rows[] = $row;
-
- $output = theme('table', array('header' => $header, 'rows' => $rows));
- return $output;
-}
-
-/**
- * Validation handler for captcha_admin_settings form.
- */
-function captcha_admin_settings_validate($form, $form_state) {
- $form_id = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'];
- if (!preg_match('/^[a-z0-9_]*$/', $form_id)) {
- form_set_error('captcha_form_id_overview][captcha_new_captcha_point][form_id', t('Illegal form_id'));
- }
-}
-
-/**
- * Submission function for captcha_admin_settings form.
- */
-function captcha_admin_settings_submit($form, &$form_state) {
-
- variable_set('captcha_administration_mode', $form_state['values']['captcha_administration_mode']);
- variable_set('captcha_allow_on_admin_pages', $form_state['values']['captcha_allow_on_admin_pages']);
-
- variable_set('captcha_default_challenge', $form_state['values']['captcha_default_challenge']);
-
- // Process CAPTCHA points
- if (isset($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'])) {
- foreach ($form_state['values']['captcha_form_id_overview']['captcha_captcha_points'] as $captcha_point_form_id => $data) {
- captcha_set_form_id_setting($captcha_point_form_id, $data['captcha_type']);
- }
- }
-
- // Add new CAPTCHA point?
- $captcha_point_form_id = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['form_id'];
- if (!empty($captcha_point_form_id)) {
- $captcha_type = $form_state['values']['captcha_form_id_overview']['captcha_new_captcha_point']['captcha_type'];
- captcha_set_form_id_setting($captcha_point_form_id, $captcha_type);
- drupal_set_message(t('Added CAPTCHA point.'), 'status');
- }
-
- // CAPTCHA description stuff.
- variable_set('captcha_add_captcha_description', $form_state['values']['captcha_add_captcha_description']);
- // Save (or reset) the CAPTCHA descriptions.
- if (module_exists('locale')) {
- $langs = locale_language_list();
- foreach ($langs as $lang_code => $lang_name) {
- $description = $form_state['values']["captcha_description_$lang_code"];
- if ($description) {
- variable_set("captcha_description_$lang_code", $description);
- }
- else {
- variable_del("captcha_description_$lang_code");
- drupal_set_message(t('Reset of CAPTCHA description for language %language.', array('%language' => $lang_name)), 'status');
- }
- }
- }
- else {
- $description = $form_state['values']['captcha_description'];
- if ($description) {
- variable_set('captcha_description', $description);
- }
- else {
- variable_del('captcha_description');
- drupal_set_message(t('Reset of CAPTCHA description.'), 'status');
- }
- }
-
- variable_set('captcha_default_validation', $form_state['values']['captcha_default_validation']);
- variable_set('captcha_persistence', $form_state['values']['captcha_persistence']);
- variable_set('captcha_enable_stats', $form_state['values']['captcha_enable_stats']);
- variable_set('captcha_log_wrong_responses', $form_state['values']['captcha_log_wrong_responses']);
-
- drupal_set_message(t('The CAPTCHA settings have been saved.'), 'status');
-}
-
-
-
-
-/**
- * Submit callback; clear CAPTCHA placement cache.
- */
-function captcha_clear_captcha_placement_cache_submit($form, &$form_state) {
- variable_del('captcha_placement_map_cache');
- drupal_set_message(t('Cleared the CAPTCHA placement cache.'));
-}
-
-
-/**
- * Central handler for CAPTCHA point administration (adding, disabling, deleting)
- */
-function captcha_point_admin($captcha_point_form_id=NULL, $op=NULL) {
- module_load_include('inc', 'captcha');
-
- // if $captcha_point_form_id and action $op given: do the action
- if ($captcha_point_form_id) {
- switch ($op) {
- case 'disable':
- return drupal_get_form('captcha_point_disable_confirm', $captcha_point_form_id, FALSE);
- case 'delete':
- return drupal_get_form('captcha_point_disable_confirm', $captcha_point_form_id, TRUE);
- }
- // return edit form for CAPTCHA point
- return drupal_get_form('captcha_point_admin_form', $captcha_point_form_id);
- }
- // return add form for CAPTCHA point
- return drupal_get_form('captcha_point_admin_form');
-}
-
-function captcha_point_admin_form($form, $form_state, $captcha_point_form_id=NULL) {
- $form = array();
- $default_captcha_type = 'none';
- if (isset($captcha_point_form_id)) {
- // use given CAPTCHA point form_id
- $form['captcha_point_form_id'] = array(
- '#type' => 'textfield',
- '#title' => t('Form ID'),
- '#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
- '#value' => check_plain($captcha_point_form_id),
- '#disabled' => TRUE,
- );
- $captcha_point = captcha_get_form_id_setting($captcha_point_form_id);
- if ($captcha_point) {
- $default_captcha_type = "{$captcha_point->module}/{$captcha_point->captcha_type}";
- }
- }
- else {
- // textfield for CAPTCHA point form_id
- $form['captcha_point_form_id'] = array(
- '#type' => 'textfield',
- '#title' => t('Form ID'),
- '#description' => t('The Drupal form_id of the form to add the CAPTCHA to.'),
- );
- }
- // select widget for CAPTCHA type
- $form['captcha_type'] = array(
- '#type' => 'select',
- '#title' => t('Challenge type'),
- '#description' => t('The CAPTCHA type to use for this form.'),
- '#default_value' => $default_captcha_type,
- '#options' => _captcha_available_challenge_types(),
- );
- // redirect to general CAPTCHA settings page after submission
- $form['#redirect'] = 'admin/config/people/captcha';
- // submit button
- $form['actions'] = array('#type' => 'actions');
- $form['actions']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- );
- return $form;
-}
-
-
-/**
- * validation function for captcha_point_admin_form
- */
-function captcha_point_admin_form_validate($form, $form_state) {
- if (!preg_match('/^[a-z0-9_]+$/', $form_state['values']['captcha_point_form_id'])) {
- form_set_error('captcha_point_form_id', t('Illegal form_id'));
- }
-}
-
-
-/**
- * Submit function for captcha_point_admin_form.
- */
-function captcha_point_admin_form_submit($form, $form_state) {
- $captcha_point_form_id = $form_state['values']['captcha_point_form_id'];
- $captcha_type = $form_state['values']['captcha_type'];
- captcha_set_form_id_setting($captcha_point_form_id, $captcha_type);
- drupal_set_message(t('Saved CAPTCHA point settings.'), 'status');
-}
-
-/**
- * Confirm dialog for disabling/deleting a CAPTCHA point
- */
-function captcha_point_disable_confirm($form, &$form_state, $captcha_point_form_id, $delete) {
- $form = array();
- $form['captcha_point_form_id'] = array(
- '#type' => 'value',
- '#value' => $captcha_point_form_id,
- );
- $form['captcha_point_delete'] = array(
- '#type' => 'value',
- '#value' => $delete,
- );
- if ($delete) {
- $message = t('Are you sure you want to delete the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
- $yes = t('Delete');
- }
- else {
- $message = t('Are you sure you want to disable the CAPTCHA for form_id %form_id?', array('%form_id' => $captcha_point_form_id));
- $yes = t('Disable');
- }
- return confirm_form($form, $message, 'admin/config/people/captcha/captcha', '', $yes);
-}
-
-/**
- * Submission handler of CAPTCHA point disabling/deleting confirm_form.
- */
-function captcha_point_disable_confirm_submit($form, &$form_state) {
- $captcha_point_form_id = $form_state['values']['captcha_point_form_id'];
- $delete = $form_state['values']['captcha_point_delete'];
- if ($delete) {
- captcha_set_form_id_setting($captcha_point_form_id, NULL);
- drupal_set_message(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
- }
- else {
- captcha_set_form_id_setting($captcha_point_form_id, 'none');
- drupal_set_message(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)));
- }
- $form_state['redirect'] = 'admin/config/people/captcha/captcha';
-}
-
-/**
- * Helper function for generating an example challenge.
- */
-function _captcha_generate_example_challenge($module, $type) {
- return array(
- '#type' => 'captcha',
- '#captcha_type' => $module . '/' . $type,
- '#captcha_admin_mode' => TRUE,
- );
-}
-
-/**
- * Funtion for generating a page with CAPTCHA examples.
- *
- * If the arguments $module and $challenge are not set, generate a list with
- * examples of the available CAPTCHA types.
- * If $module and $challenge are set, generate 10 examples of the concerning
- * CAPTCHA.
- */
-function captcha_examples($form, $form_state, $module, $challenge) {
- module_load_include('inc', 'captcha');
-
- $form = array();
- if ($module && $challenge) {
- // Generate 10 example challenges.
- for ($i=0; $i<10; $i++) {
- $form["challenge_{$i}"] = _captcha_generate_example_challenge($module, $challenge);
- }
- }
- else {
- // generate a list with examples of the available CAPTCHA types
- $form['info'] = array(
- '#markup' => t('This page gives an overview of all available challenge types, generated with their current settings.'),
- );
- foreach (module_implements('captcha') as $mkey => $module) {
- $challenges = call_user_func_array($module . '_captcha', array('list'));
- if ($challenges) {
- foreach ($challenges as $ckey => $challenge) {
- $form["captcha_{$mkey}_{$ckey}"] = array(
- '#type' => 'fieldset',
- '#title' => t('Challenge %challenge by module %module', array('%challenge' => $challenge, '%module' => $module)),
- 'challenge' => _captcha_generate_example_challenge($module, $challenge),
- 'more_examples' => array(
- '#markup' => l(t('10 more examples of this challenge.'), "admin/config/people/captcha/captcha/examples/$module/$challenge"),
- ),
- );
- }
- }
- }
- }
- return $form;
-}
diff --git a/sites/all/modules/contrib/captcha/captcha.inc b/sites/all/modules/contrib/captcha/captcha.inc
deleted file mode 100644
index 6af73a66..00000000
--- a/sites/all/modules/contrib/captcha/captcha.inc
+++ /dev/null
@@ -1,384 +0,0 @@
-module and $captcha_type->captcha_type
- * @return nothing
- */
-function captcha_set_form_id_setting($form_id, $captcha_type) {
- // Handle 'none'.
- if ($captcha_type == 'none') {
- db_merge('captcha_points')
- ->key(array('form_id' => $form_id))
- ->fields(array('module' => NULL, 'captcha_type' => NULL))
- ->execute();
- }
- // Handle 'default'.
- elseif ($captcha_type == 'default') {
- db_merge('captcha_points')
- ->key(array('form_id' => $form_id))
- ->fields(array('module' => NULL, 'captcha_type' => 'default'))
- ->execute();
- }
- // Handle NULL.
- elseif ($captcha_type == NULL) {
- db_delete('captcha_points')->condition('form_id', $form_id)->execute();
- }
- // Handle a captcha_type object.
- elseif (is_object($captcha_type) && isset($captcha_type->module) && isset($captcha_type->captcha_type)) {
- db_merge('captcha_points')
- ->key(array('form_id' => $form_id))
- ->fields(array('module' => $captcha_type->module, 'captcha_type' => $captcha_type->captcha_type))
- ->execute();
- }
- // Handle a captcha_type string.
- elseif (is_string($captcha_type) && substr_count($captcha_type, '/') == 1) {
- list($module, $type) = explode('/', $captcha_type);
- db_merge('captcha_points')
- ->key(array('form_id' => $form_id))
- ->fields(array('module' => $module, 'captcha_type' => $type))
- ->execute();
- }
- else {
- drupal_set_message(t('Failed to set a CAPTCHA type for form %form_id: could not interpret value "@captcha_type"',
- array('%form_id' => $form_id, '@captcha_type' => (string)$captcha_type)), 'warning');
- }
-}
-
-/**
- * Get the CAPTCHA setting for a given form_id.
- *
- * @param $form_id the form_id to query for
- * @param $symbolic flag to return as (symbolic) strings instead of object.
- *
- * @return NULL if no setting is known
- * or a captcha_point object with fields 'module' and 'captcha_type'.
- * If argument $symbolic is true, returns (symbolic) as 'none', 'default'
- * or in the form 'captcha/Math'.
- */
-function captcha_get_form_id_setting($form_id, $symbolic=FALSE) {
- $result = db_query("SELECT module, captcha_type FROM {captcha_points} WHERE form_id = :form_id",
- array(':form_id' => $form_id));
- $captcha_point = $result->fetchObject();
- if (!$captcha_point) {
- $captcha_point = NULL;
- }
- elseif ($captcha_point->captcha_type == 'default') {
- if (!$symbolic) {
- list($module, $type) = explode('/', variable_get('captcha_default_challenge', 'captcha/Math'));
- $captcha_point->module = $module;
- $captcha_point->captcha_type = $type;
- }
- else {
- $captcha_point = 'default';
- }
- }
- elseif ($captcha_point->module == NULL && $captcha_point->captcha_type == NULL && $symbolic) {
- $captcha_point = 'none';
- }
- elseif ($symbolic) {
- $captcha_point = $captcha_point->module . '/' . $captcha_point->captcha_type;
- }
- return $captcha_point;
-}
-
-
-/**
- * Helper function for generating a new CAPTCHA session.
- *
- * @param $form_id the form_id of the form to add a CAPTCHA to.
- * @param $status the initial status of the CAPTHCA session.
- * @return the session ID of the new CAPTCHA session.
- */
-function _captcha_generate_captcha_session($form_id=NULL, $status=CAPTCHA_STATUS_UNSOLVED) {
- global $user;
- // Initialize solution with random data.
- $solution = md5(mt_rand());
- // Insert an entry and thankfully receive the value of the autoincrement field 'csid'.
- $captcha_sid = db_insert('captcha_sessions')
- ->fields(array(
- 'uid' => $user->uid,
- 'sid' => session_id(),
- 'ip_address' => ip_address(),
- 'timestamp' => REQUEST_TIME,
- 'form_id' => $form_id,
- 'solution' => $solution,
- 'status' => $status,
- 'attempts' => 0,
- ))
- ->execute();
- return $captcha_sid;
-}
-
-/**
- * Helper function for updating the solution in the CAPTCHA session table.
- *
- * @param $captcha_sid the CAPTCHA session ID to update.
- * @param $solution the new solution to associate with the given CAPTCHA session.
- */
-function _captcha_update_captcha_session($captcha_sid, $solution) {
- db_update('captcha_sessions')
- ->condition('csid', $captcha_sid)
- ->fields(array(
- 'timestamp' => REQUEST_TIME,
- 'solution' => $solution,
- ))
- ->execute();
-}
-
-/**
- * Helper function for checking if CAPTCHA is required for user,
- * based on the CAPTCHA persistence setting, the CAPTCHA session ID and
- * user session info.
- */
-function _captcha_required_for_user($captcha_sid, $form_id) {
- // Get the CAPTCHA persistence setting.
- $captcha_persistence = variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
-
- // First check: should we always add a CAPTCHA?
- if ($captcha_persistence == CAPTCHA_PERSISTENCE_SHOW_ALWAYS) {
- return TRUE;
- }
-
- // Get the status of the current CAPTCHA session.
- $captcha_session_status = db_query('SELECT status FROM {captcha_sessions} WHERE csid = :csid', array(':csid' => $captcha_sid))->fetchField();
- // Second check: if the current session is already solved: omit further CAPTCHAs.
- if ($captcha_session_status == CAPTCHA_STATUS_SOLVED) {
- return FALSE;
- }
-
- // Third check: look at the persistence level (per form instance, per form or per user).
- if ($captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE) {
- return TRUE;
- }
- else {
- $captcha_success_form_ids = isset($_SESSION['captcha_success_form_ids']) ? (array)($_SESSION['captcha_success_form_ids']) : array();
- switch ($captcha_persistence) {
- case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL:
- return (count($captcha_success_form_ids) == 0);
- case CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE:
- return !isset($captcha_success_form_ids[$form_id]);
- }
- }
-
- // We should never get to this point, but to be sure, we return TRUE.
- return TRUE;
-}
-
-
-/**
- * Get the CAPTCHA description as configured on the general CAPTCHA
- * settings page.
- *
- * If the locale module is enabled, the description will be returned
- * for the current language the page is rendered for. This language
- * can optionally been overriden with the $lang_code argument.
- *
- * @param $lang_code an optional language code to get the descripion for.
- * @return a string with (localized) CAPTCHA description.
- */
-function _captcha_get_description($lang_code=NULL) {
- // If no language code is given: use the language of the current page.
- global $language;
- $lang_code = isset($lang_code) ? $lang_code : $language->language;
- // The hardcoded but localizable default.
- $default = t('This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.', array(), array('langcode' => $lang_code));
- // Look up the configured CAPTCHA description or fall back on the (localized) default.
- if (module_exists('locale')) {
- $description = variable_get("captcha_description_$lang_code", $default);
- }
- else {
- $description = variable_get('captcha_description', $default);
- }
- return filter_xss_admin($description);
-}
-
-/**
- * Parse or interpret the given captcha_type.
- * @param $captcha_type string representation of the CAPTCHA type,
- * e.g. 'default', 'none', 'captcha/Math', 'image_captcha/Image'
- * @return list($captcha_module, $captcha_type)
- */
-function _captcha_parse_captcha_type($captcha_type) {
- if ($captcha_type == 'none') {
- return array(NULL, NULL);
- }
- if ($captcha_type == 'default') {
- $captcha_type = variable_get('captcha_default_challenge', 'captcha/Math');
- }
- return explode('/', $captcha_type);
-}
-
-/**
- * Helper function to get placement information for a given form_id.
- * @param $form_id the form_id to get the placement information for.
- * @param $form if a form corresponding to the given form_id, if there
- * is no placement info for the given form_id, this form is examined to
- * guess the placement.
- * @return placement info array (@see _captcha_insert_captcha_element() for more
- * info about the fields 'path', 'key' and 'weight'.
- */
-function _captcha_get_captcha_placement($form_id, $form) {
- // Get CAPTCHA placement map from cache. Two levels of cache:
- // static variable in this function and storage in the variables table.
- static $placement_map = NULL;
- // Try first level cache.
- if ($placement_map === NULL) {
- // If first level cache missed: try second level cache.
- $placement_map = variable_get('captcha_placement_map_cache', NULL);
-
- if ($placement_map === NULL) {
- // If second level cache missed: initialize the placement map
- // and let other modules hook into this with the hook_captcha_placement_map hook.
- // By default however, probably all Drupal core forms are already correctly
- // handled with the best effort guess based on the 'actions' element (see below).
- $placement_map = module_invoke_all('captcha_placement_map');
- }
- }
-
- // Query the placement map.
- if (array_key_exists($form_id, $placement_map)) {
- $placement = $placement_map[$form_id];
- }
- // If no placement info is available in placement map: make a best effort guess.
- else {
- // If there is an "actions" button group, a good placement is just before that.
- if (isset($form['actions']) && isset($form['actions']['#type']) && $form['actions']['#type'] === 'actions') {
- $placement = array(
- 'path' => array(),
- 'key' => 'actions',
- // #type 'actions' defaults to 100.
- 'weight' => (isset($form['actions']['#weight']) ? $form['actions']['#weight'] - 1 : 99),
- );
- }
- else {
- // Search the form for buttons and guess placement from it.
- $buttons = _captcha_search_buttons($form);
- if (count($buttons)) {
- // Pick first button.
- // TODO: make this more sofisticated? Use cases needed.
- $placement = $buttons[0];
- }
- else {
- // Use NULL when no buttons were found.
- $placement = NULL;
- }
- }
-
- // Store calculated placement in cache.
- $placement_map[$form_id] = $placement;
- variable_set('captcha_placement_map_cache', $placement_map);
- }
-
- return $placement;
-}
-
-/**
- * Helper function for searching the buttons in a form.
- *
- * @param $form the form to search button elements in
- * @return an array of paths to the buttons.
- * A path is an array of keys leading to the button, the last
- * item in the path is the weight of the button element
- * (or NULL if undefined).
- */
-function _captcha_search_buttons($form) {
- $buttons = array();
- foreach (element_children($form) as $key) {
- // Look for submit or button type elements.
- if (isset($form[$key]['#type']) && ($form[$key]['#type'] == 'submit' || $form[$key]['#type'] == 'button')) {
- $weight = isset($form[$key]['#weight']) ? $form[$key]['#weight'] : NULL;
- $buttons[] = array(
- 'path' => array(),
- 'key' => $key,
- 'weight' => $weight,
- );
- }
- // Process children recurively.
- $children_buttons = _captcha_search_buttons($form[$key]);
- foreach ($children_buttons as $b) {
- $b['path'] = array_merge(array($key), $b['path']);
- $buttons[] = $b;
- }
- }
- return $buttons;
-}
-
-/**
- * Helper function to insert a CAPTCHA element in a form before a given form element.
- * @param $form the form to add the CAPTCHA element to.
- * @param $placement information where the CAPTCHA element should be inserted.
- * $placement should be an associative array with fields:
- * - 'path': path (array of path items) of the container in the form where the
- * CAPTCHA element should be inserted.
- * - 'key': the key of the element before which the CAPTCHA element
- * should be inserted. If the field 'key' is undefined or NULL, the CAPTCHA will
- * just be appended in the container.
- * - 'weight': if 'key' is not NULL: should be the weight of the element defined by 'key'.
- * If 'key' is NULL and weight is not NULL: set the weight property of the CAPTCHA element
- * to this value.
- * @param $captcha_element the CAPTCHA element to insert.
- */
-function _captcha_insert_captcha_element(&$form, $placement, $captcha_element) {
- // Get path, target and target weight or use defaults if not available.
- $target_key = isset($placement['key']) ? $placement['key'] : NULL;
- $target_weight = isset($placement['weight']) ? $placement['weight'] : NULL;
- $path = isset($placement['path']) ? $placement['path'] : array();
-
- // Walk through the form along the path.
- $form_stepper = &$form;
- foreach ($path as $step) {
- if (isset($form_stepper[$step])) {
- $form_stepper = & $form_stepper[$step];
- }
- else {
- // Given path is invalid: stop stepping and
- // continue in best effort (append instead of insert).
- $target_key = NULL;
- break;
- }
- }
-
- // If no target is available: just append the CAPTCHA element to the container.
- if ($target_key == NULL || !array_key_exists($target_key, $form_stepper)) {
- // Optionally, set weight of CAPTCHA element.
- if ($target_weight != NULL) {
- $captcha_element['#weight'] = $target_weight;
- }
- $form_stepper['captcha'] = $captcha_element;
- }
- // If there is a target available: make sure the CAPTCHA element comes right before it.
- else {
- // If target has a weight: set weight of CAPTCHA element a bit smaller
- // and just append the CAPTCHA: sorting will fix the ordering anyway.
- if ($target_weight != NULL) {
- $captcha_element['#weight'] = $target_weight - .1;
- $form_stepper['captcha'] = $captcha_element;
- }
- else {
- // If we can't play with weights: insert the CAPTCHA element at the right position.
- // Because PHP lacks a function for this (array_splice() comes close,
- // but it does not preserve the key of the inserted element), we do it by hand:
- // chop of the end, append the CAPTCHA element and put the end back.
- $offset = array_search($target_key, array_keys($form_stepper));
- $end = array_splice($form_stepper, $offset);
- $form_stepper['captcha'] = $captcha_element;
- foreach ($end as $k => $v) {
- $form_stepper[$k] = $v;
- }
- }
- }
-}
-
diff --git a/sites/all/modules/contrib/captcha/captcha.info b/sites/all/modules/contrib/captcha/captcha.info
deleted file mode 100644
index 32c91fca..00000000
--- a/sites/all/modules/contrib/captcha/captcha.info
+++ /dev/null
@@ -1,18 +0,0 @@
-name = CAPTCHA
-description = Base CAPTCHA module for adding challenges to arbitrary forms.
-package = "Spam control"
-core = 7.x
-configure = admin/config/people/captcha
-
-files[] = captcha.module
-files[] = captcha.inc
-files[] = captcha.admin.inc
-files[] = captcha.install
-files[] = captcha.test
-
-; Information added by drupal.org packaging script on 2013-06-25
-version = "7.x-1.0"
-core = "7.x"
-project = "captcha"
-datestamp = "1372203950"
-
diff --git a/sites/all/modules/contrib/captcha/captcha.install b/sites/all/modules/contrib/captcha/captcha.install
deleted file mode 100644
index f53f600a..00000000
--- a/sites/all/modules/contrib/captcha/captcha.install
+++ /dev/null
@@ -1,336 +0,0 @@
- 'This table describes which challenges should be added to which forms.',
- 'fields' => array(
- 'form_id' => array(
- 'description' => 'The form_id of the form to add a CAPTCHA to.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'module' => array(
- 'description' => 'The module that provides the challenge.',
- 'type' => 'varchar',
- 'length' => 64,
- ),
- 'captcha_type' => array(
- 'description' => 'The challenge type to use.',
- 'type' => 'varchar',
- 'length' => 64,
- ),
- ),
- 'primary key' => array('form_id'),
- );
- // Table for the CAPTCHA sessions.
- $schema['captcha_sessions'] = array(
- 'description' => 'Stores the data about CAPTCHA sessions (solution, IP address, timestamp, ...).',
- 'fields' => array(
- 'csid' => array(
- 'description' => 'CAPTCHA session ID.',
- 'type' => 'serial',
- 'not null' => TRUE,
- ),
- 'token' => array(
- 'description' => 'One time CAPTCHA token.',
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => FALSE,
- ),
- 'uid' => array(
- 'description' => "User's {users}.uid.",
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'sid' => array(
- 'description' => "Session ID of the user.",
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'ip_address' => array(
- 'description' => 'IP address of the visitor.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => FALSE,
- ),
- 'timestamp' => array(
- 'description' => 'A Unix timestamp indicating when the challenge was generated.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'form_id' => array(
- 'description' => 'The form_id of the form where the CAPTCHA is added to.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- ),
- 'solution' => array(
- 'description' => 'Solution of the challenge.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'status' => array(
- 'description' => 'Status of the CAPTCHA session (unsolved, solved, ...)',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'attempts' => array(
- 'description' => 'The number of attempts.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- )
- ),
- 'primary key' => array('csid'),
- 'indexes' => array(
- 'csid_ip' => array('csid', 'ip_address'),
- ),
- );
-
- return $schema;
-}
-
-/**
- * Implementation of hook_requirements().
- */
-function captcha_requirements($phase) {
- $requirements = array();
- $t = get_t();
- if ($phase == 'runtime' && variable_get('captcha_enable_stats', FALSE)) {
- // Show the wrong response counter in the status report.
- $requirements['captcha_wrong_response_counter'] = array(
- 'title' => $t('CAPTCHA'),
- 'value' => format_plural(
- variable_get('captcha_wrong_response_counter', 0),
- 'Already 1 blocked form submission',
- 'Already @count blocked form submissions'
- ),
- 'severity' => REQUIREMENT_INFO,
- );
- }
- return $requirements;
-}
-
-/**
- * Implementation of hook_install().
- */
-function captcha_install() {
- $t = get_t();
- // Insert some default CAPTCHA points.
- $form_ids = array(
- 'contact_site_form', 'contact_personal_form',
- 'user_register_form', 'user_pass', 'user_login', 'user_login_block',
- 'forum_node_form'
- );
- // Add form_ids of all currently known node types too.
- foreach (node_type_get_names() as $type => $name) {
- $form_ids[] = 'comment_node_' . $type . '_form';
- }
- foreach ($form_ids as $form_id) {
- db_insert('captcha_points')
- ->fields(array(
- 'form_id' => $form_id,
- 'module' => NULL,
- 'captcha_type' => NULL,
- ))
- ->execute();
- }
-
- // Be friendly to your users: what to do after install?
- drupal_set_message($t('You can now configure the CAPTCHA module for your site.',
- array('!captcha_admin' => url('admin/config/people/captcha'))), 'status');
-
- // Explain to users that page caching may be disabled.
- if (variable_get('cache', 0) != 0) {
- drupal_set_message($t('Note that the CAPTCHA module disables page caching of pages that include a CAPTCHA challenge.',
- array('!performance_admin' => url('admin/config/development/performance'))), 'warning');
- }
-
-}
-
-/**
- * Implementation of hook_uninstall().
- */
-function captcha_uninstall() {
- drupal_uninstall_schema('captcha');
- db_query("DELETE FROM {variable} WHERE name LIKE 'captcha_%'");
- cache_clear_all('variables', 'cache');
-}
-
-/**
- * Implementation of hook_update_N()
- */
-function captcha_update_6200() {
- $items = array();
-
- // Table for the CAPTCHA sessions.
- $schema['captcha_sessions'] = array(
- 'description' => 'Stores the data about CAPTCHA sessions (solution, IP address, timestamp, ...).',
- 'fields' => array(
- 'csid' => array(
- 'description' => 'CAPTCHA session ID.',
- 'type' => 'serial',
- 'not null' => TRUE,
- ),
- 'uid' => array(
- 'description' => "User's {users}.uid.",
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'sid' => array(
- 'description' => "Session ID of the user.",
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'ip_address' => array(
- 'description' => 'IP address of the visitor.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => FALSE,
- ),
- 'timestamp' => array(
- 'description' => 'A Unix timestamp indicating when the challenge was generated.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'form_id' => array(
- 'description' => 'The form_id of the form where the CAPTCHA is added to.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- ),
- 'solution' => array(
- 'description' => 'Solution of the challenge.',
- 'type' => 'varchar',
- 'length' => 128,
- 'not null' => TRUE,
- 'default' => '',
- ),
- 'status' => array(
- 'description' => 'Status of the CAPTCHA session (unsolved, solved, ...)',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- ),
- 'attempts' => array(
- 'description' => 'The number of attempts.',
- 'type' => 'int',
- 'not null' => TRUE,
- 'default' => 0,
- )
- ),
- 'primary key' => array('csid'),
- 'indexes' => array(
- 'csid_ip' => array('csid', 'ip_address'),
- ),
- );
-
- db_create_table($items, 'captcha_sessions', $schema['captcha_sessions']);
-
- return $items;
-}
-
-/**
- * Implementation of hook_update_N()
- * Change the captcha points with the old text CAPTCHA, which was
- * removed from the 6.x-2.x branch, to the simple math CAPTCHA.
- */
-function captcha_update_6201() {
- $items = array();
- $items[] = update_sql("UPDATE {captcha_points} SET module = 'captcha', type = 'Math' WHERE module = 'text_captcha' AND type = 'Text';");
- return $items;
-}
-
-
-/**
- * Implementation of hook_update_N()
- * Add a CAPTCHA token column to captcha_sessions table.
- */
-function captcha_update_6202() {
- $ret = array();
- db_add_column($ret, 'captcha_sessions', 'token', 'varchar(64)');
- return $ret;
-}
-
-
-
-/**
- * Implementation of hook_update_N()
- * Rename the type field to captcha_type in captcha_points.
- */
-function captcha_update_6203() {
- $ret = array();
- db_change_field($ret, 'captcha_points', 'type', 'captcha_type', array('type' => 'varchar', 'length' => 64));
- return $ret;
-}
-
-
-/**
- * Migrate form configuration for changed form ids in Drupal 7.
- */
-function captcha_update_7000() {
- // 'user_register' became 'user_register_form'.
- db_update('captcha_points')
- ->fields(array('form_id' => 'user_register_form'))
- ->condition('form_id', 'user_register')
- ->execute();
- // 'contact_mail_page' became 'contact_site_form'.
- db_update('captcha_points')
- ->fields(array('form_id' => 'contact_site_form'))
- ->condition('form_id', 'contact_mail_page')
- ->execute();
- // 'contact_mail_user' became 'contact_personal_form'.
- db_update('captcha_points')
- ->fields(array('form_id' => 'contact_personal_form'))
- ->condition('form_id', 'contact_mail_user')
- ->execute();
-
- // The D6-style comment_form form_id is split per node type
- // in D7: comment_node_{type}_form, e.g. comment_node_page_form.
- // Get the current settings for 'comment_form'.
- $captcha_point = db_query(
- "SELECT * FROM {captcha_points} WHERE form_id = :comment_form_id",
- array(':comment_form_id' => 'comment_form')
- )->fetchObject();
- if ($captcha_point !== FALSE) {
- // Create entries for D7-style node form IDs.
- $module = $captcha_point->module;
- $captcha_type = $captcha_point->captcha_type;
- foreach (node_type_get_names() as $type => $name) {
- $form_id = 'comment_node_' . $type . '_form';
- db_insert('captcha_points')
- ->fields(array(
- 'form_id' => $form_id,
- 'module' => $module,
- 'captcha_type' => $captcha_type,
- ))
- ->execute();
- }
- // Delete outdated entry.
- db_delete('captcha_points')
- ->condition('form_id', 'comment_form')
- ->execute();
- }
-}
diff --git a/sites/all/modules/contrib/captcha/captcha.js b/sites/all/modules/contrib/captcha/captcha.js
deleted file mode 100644
index 0259736c..00000000
--- a/sites/all/modules/contrib/captcha/captcha.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function ($) {
-
- Drupal.behaviors.captcha = {
- attach: function (context) {
-
- // Turn off autocompletion for the CAPTCHA response field.
- // We do it here with Javascript (instead of directly in the markup)
- // because this autocomplete attribute is not standard and
- // it would break (X)HTML compliance.
- $("#edit-captcha-response").attr("autocomplete", "off");
-
- }
- };
-
- Drupal.behaviors.captchaAdmin = {
- attach: function (context) {
- // Add onclick handler to checkbox for adding a CAPTCHA description
- // so that the textfields for the CAPTCHA description are hidden
- // when no description should be added.
- // @todo: div.form-item-captcha-description depends on theming, maybe
- // it's better to add our own wrapper with id (instead of a class).
- $("#edit-captcha-add-captcha-description").click(function() {
- if ($("#edit-captcha-add-captcha-description").is(":checked")) {
- // Show the CAPTCHA description textfield(s).
- $("div.form-item-captcha-description").show('slow');
- }
- else {
- // Hide the CAPTCHA description textfield(s).
- $("div.form-item-captcha-description").hide('slow');
- }
- });
- // Hide the CAPTCHA description textfields if option is disabled on page load.
- if (!$("#edit-captcha-add-captcha-description").is(":checked")) {
- $("div.form-item-captcha-description").hide();
- }
- }
-
- };
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/captcha/captcha.module b/sites/all/modules/contrib/captcha/captcha.module
deleted file mode 100644
index b2772b6a..00000000
--- a/sites/all/modules/contrib/captcha/captcha.module
+++ /dev/null
@@ -1,743 +0,0 @@
-' . t('"CAPTCHA" is an acronym for "Completely Automated Public Turing test to tell Computers and Humans Apart". It is typically a challenge-response test to determine whether the user is human. The CAPTCHA module is a tool to fight automated submission by malicious users (spamming) of for example comments forms, user registration forms, guestbook forms, etc. You can extend the desired forms with an additional challenge, which should be easy for a human to solve correctly, but hard enough to keep automated scripts and spam bots out.') . '';
- $output .= '' . t('Note that the CAPTCHA module interacts with page caching (see performance settings ). Because the challenge should be unique for each generated form, the caching of the page it appears on is prevented. Make sure that these forms do not appear on too many pages or you will lose much caching efficiency. For example, if you put a CAPTCHA on the user login block, which typically appears on each page for anonymous visitors, caching will practically be disabled. The comment submission forms are another example. In this case you should set the Location of comment submission form to Display on separate page in the comment settings of the relevant content types for better caching efficiency.',
- array(
- '!performancesettings' => url('admin/config/development/performance'),
- '!contenttypes' => url('admin/structure/types'),
- )
- ) . '
';
- $output .= '' . t('CAPTCHA is a trademark of Carnegie Mellon University.') . '
';
- return $output;
- case 'admin/config/people/captcha':
- case 'admin/config/people/captcha/captcha':
- case 'admin/config/people/captcha/captcha/settings':
- $output = '' . t('A CAPTCHA can be added to virtually each Drupal form. Some default forms are already provided in the form list, but arbitrary forms can be easily added and managed when the option Add CAPTCHA administration links to forms is enabled.') . '
';
- $output .= '' . t('Users with the Skip CAPTCHA permission won\'t be offered a challenge. Be sure to grant this permission to the trusted users (e.g. site administrators). If you want to test a protected form, be sure to do it as a user without the Skip CAPTCHA permission (e.g. as anonymous user).', array('@perm' => url('admin/people/permissions'))) . '
';
- return $output;
- }
-}
-
-/**
- * Implementation of hook_menu().
- */
-function captcha_menu() {
- $items = array();
- // main configuration page of the basic CAPTCHA module
- $items['admin/config/people/captcha'] = array(
- 'title' => 'CAPTCHA',
- 'description' => 'Administer how and where CAPTCHAs are used.',
- 'file' => 'captcha.admin.inc',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('captcha_admin_settings'),
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_NORMAL_ITEM,
- );
- // the default local task (needed when other modules want to offer
- // alternative CAPTCHA types and their own configuration page as local task)
- $items['admin/config/people/captcha/captcha'] = array(
- 'title' => 'CAPTCHA',
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -20,
- );
- $items['admin/config/people/captcha/captcha/settings'] = array(
- 'title' => 'General settings',
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => 0,
- );
- $items['admin/config/people/captcha/captcha/examples'] = array(
- 'title' => 'Examples',
- 'description' => 'An overview of the available challenge types with examples.',
- 'file' => 'captcha.admin.inc',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('captcha_examples', 6, 7),
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 5,
- );
- $items['admin/config/people/captcha/captcha/captcha_point'] = array(
- 'title' => 'CAPTCHA point administration',
- 'file' => 'captcha.admin.inc',
- 'page callback' => 'captcha_point_admin',
- 'page arguments' => array(6, 7),
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_CALLBACK,
- );
- return $items;
-}
-
-/**
- * Implementation of hook_permission().
- */
-function captcha_permission() {
- return array(
- 'administer CAPTCHA settings' => array(
- 'title' => t('Administer CAPTCHA settings'),
- ),
- 'skip CAPTCHA' => array(
- 'title' => t('Skip CAPTCHA'),
- 'description' => t('Users with this permission will not be offered a CAPTCHA.'),
- ),
- );
-}
-
-/**
- * Implementation of hook_theme().
- */
-function captcha_theme() {
- return array(
- 'captcha_admin_settings_captcha_points' => array(
- 'render element' => 'form',
- ),
- 'captcha' => array(
- 'render element' => 'element',
- ),
- );
-}
-
-/**
- * Implementation of hook_cron().
- *
- * Remove old entries from captcha_sessions table.
- */
-function captcha_cron() {
- // Remove challenges older than 1 day.
- db_delete('captcha_sessions')
- ->condition('timestamp', REQUEST_TIME - 60*60*24, '<')
- ->execute();
-}
-
-
-/**
- * Implementation of hook_element_info().
- */
-function captcha_element_info() {
- // Define the CAPTCHA form element with default properties.
- $captcha_element = array(
- '#input' => TRUE,
- '#process' => array('captcha_element_process'),
- // The type of challenge: e.g. 'default', 'none', 'captcha/Math', 'image_captcha/Image', ...
- '#captcha_type' => 'default',
- '#default_value' => '',
- // CAPTCHA in admin mode: presolve the CAPTCHA and always show it (despite previous successful responses).
- '#captcha_admin_mode' => FALSE,
- // The default CAPTCHA validation function.
- // TODO: should this be a single string or an array of strings (combined in OR fashion)?
- '#captcha_validate' => 'captcha_validate_strict_equality',
- );
- // Override the default CAPTCHA validation function for case insensitive validation.
- // TODO: shouldn't this be done somewhere else, e.g. in form_alter?
- if (CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE == variable_get('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE)) {
- $captcha_element['#captcha_validate'] = 'captcha_validate_case_insensitive_equality';
- }
- return array('captcha' => $captcha_element);
-}
-
-/**
- * Process callback for CAPTCHA form element.
- */
-function captcha_element_process($element, &$form_state, $complete_form) {
-
- module_load_include('inc', 'captcha');
-
- // Add Javascript for general CAPTCHA functionality.
- drupal_add_js(drupal_get_path('module', 'captcha') . '/captcha.js');
-
- // Prevent caching of the page with CAPTCHA elements.
- // This needs to be done even if the CAPTCHA will be ommitted later:
- // other untrusted users should not get a cached page when
- // the current untrusted user can skip the current CAPTCHA.
- global $conf;
- $conf['cache'] = FALSE;
-
- // Get the form ID of the form we are currently processing (which is not
- // necessary the same form that is submitted (if any).
- $this_form_id = $complete_form['form_id']['#value'];
-
- // Get the CAPTCHA session ID.
- // If there is a submitted form: try to retrieve and reuse the
- // CAPTCHA session ID from the posted data.
- list($posted_form_id, $posted_captcha_sid) = _captcha_get_posted_captcha_info($element, $form_state, $this_form_id);
- if ($this_form_id == $posted_form_id && isset($posted_captcha_sid)) {
- $captcha_sid = $posted_captcha_sid;
- }
- else {
- // Generate a new CAPTCHA session if we could not reuse one from a posted form.
- $captcha_sid = _captcha_generate_captcha_session($this_form_id, CAPTCHA_STATUS_UNSOLVED);
- }
-
- // Store CAPTCHA session ID as hidden field.
- // Strictly speaking, it is not necessary to send the CAPTCHA session id
- // with the form, as the one time CAPTCHA token (see lower) is enough.
- // However, we still send it along, because it can help debugging
- // problems on live sites with only access to the markup.
- $element['captcha_sid'] = array(
- '#type' => 'hidden',
- '#value' => $captcha_sid,
- );
-
- // Additional one time CAPTCHA token: store in database and send with form.
- $captcha_token = md5(mt_rand());
- db_update('captcha_sessions')
- ->fields(array('token' => $captcha_token))
- ->condition('csid', $captcha_sid)
- ->execute();
- $element['captcha_token'] = array(
- '#type' => 'hidden',
- '#value' => $captcha_token,
- );
-
- // Get implementing module and challenge for CAPTCHA.
- list($captcha_type_module, $captcha_type_challenge) = _captcha_parse_captcha_type($element['#captcha_type']);
-
- // Store CAPTCHA information for further processing in
- // - $form_state['captcha_info'], which survives a form rebuild (e.g. node
- // preview), useful in _captcha_get_posted_captcha_info().
- // - $element['#captcha_info'], for post processing functions that do not
- // receive a $form_state argument (e.g. the pre_render callback).
- $form_state['captcha_info'] = array(
- 'this_form_id' => $this_form_id,
- 'posted_form_id' => $posted_form_id,
- 'captcha_sid' => $captcha_sid,
- 'module' => $captcha_type_module,
- 'captcha_type' => $captcha_type_challenge,
- );
- $element['#captcha_info'] = array(
- 'form_id' => $this_form_id,
- 'captcha_sid' => $captcha_sid,
- );
-
-
- if (_captcha_required_for_user($captcha_sid, $this_form_id) || $element['#captcha_admin_mode']) {
- // Generate a CAPTCHA and its solution
- // (note that the CAPTCHA session ID is given as third argument).
- $captcha = module_invoke($captcha_type_module, 'captcha', 'generate', $captcha_type_challenge, $captcha_sid);
- if (!isset($captcha['form']) || !isset($captcha['solution'])) {
- // The selected module did not return what we expected: log about it and quit.
- watchdog('CAPTCHA',
- 'CAPTCHA problem: unexpected result from hook_captcha() of module %module when trying to retrieve challenge type %type for form %form_id.',
- array('%type' => $captcha_type_challenge, '%module' => $captcha_type_module, '%form_id' => $this_form_id),
- WATCHDOG_ERROR);
- return $element;
- }
- // Add form elements from challenge as children to CAPTCHA form element.
- $element['captcha_widgets'] = $captcha['form'];
-
- // Add a validation callback for the CAPTCHA form element (when not in admin mode).
- if (!$element['#captcha_admin_mode']) {
- $element['#element_validate'] = array('captcha_validate');
- }
-
- // Set a custom CAPTCHA validate function if requested.
- if (isset($captcha['captcha_validate'])) {
- $element['#captcha_validate'] = $captcha['captcha_validate'];
- }
-
- // Set the theme function.
- $element['#theme'] = 'captcha';
-
- // Add pre_render callback for additional CAPTCHA processing.
- if (!isset($element['#pre_render'])) {
- $element['#pre_render'] = array();
- }
- $element['#pre_render'][] = 'captcha_pre_render_process';
-
- // Store the solution in the #captcha_info array.
- $element['#captcha_info']['solution'] = $captcha['solution'];
-
- // Make sure we can use a top level form value $form_state['values']['captcha_response'], even if the form has #tree=true.
- $element['#tree'] = FALSE;
-
- }
-
- return $element;
-}
-
-
-/**
- * Theme function for a CAPTCHA element.
- *
- * Render it in a fieldset if a description of the CAPTCHA
- * is available. Render it as is otherwise.
- */
-function theme_captcha($variables) {
- $element = $variables['element'];
- if (!empty($element['#description']) && isset($element['captcha_widgets'])) {
- $fieldset = array(
- '#type' => 'fieldset',
- '#title' => t('CAPTCHA'),
- '#description' => $element['#description'],
- '#children' => drupal_render_children($element),
- '#attributes' => array('class' => array('captcha')),
- );
- return theme('fieldset', array('element' => $fieldset));
- }
- else {
- return '' . drupal_render_children($element) . '
';
- }
-}
-
-
-/**
- * Implementation of hook_form_alter().
- *
- * This function adds a CAPTCHA to forms for untrusted users if needed and adds
- * CAPTCHA administration links for site administrators if this option is enabled.
- */
-function captcha_form_alter(&$form, &$form_state, $form_id) {
-
- if (!user_access('skip CAPTCHA')) {
- // Visitor does not have permission to skip CAPTCHAs.
- module_load_include('inc', 'captcha');
-
- // Get CAPTCHA type and module for given form_id.
- $captcha_point = captcha_get_form_id_setting($form_id);
- if ($captcha_point && $captcha_point->captcha_type) {
- module_load_include('inc', 'captcha');
- // Build CAPTCHA form element.
- $captcha_element = array(
- '#type' => 'captcha',
- '#captcha_type' => $captcha_point->module . '/' . $captcha_point->captcha_type,
- );
- // Add a CAPTCHA description if required.
- if (variable_get('captcha_add_captcha_description', TRUE)) {
- $captcha_element['#description'] = _captcha_get_description();
- }
-
- // Get placement in form and insert in form.
- $captcha_placement = _captcha_get_captcha_placement($form_id, $form);
- _captcha_insert_captcha_element($form, $captcha_placement, $captcha_element);
- }
- }
- else if (
- variable_get('captcha_administration_mode', FALSE)
- && user_access('administer CAPTCHA settings')
- && (arg(0) != 'admin' || variable_get('captcha_allow_on_admin_pages', FALSE))
- ) {
- // Add CAPTCHA administration tools.
- module_load_include('inc', 'captcha');
-
- $captcha_point = captcha_get_form_id_setting($form_id);
- // For administrators: show CAPTCHA info and offer link to configure it
- $captcha_element = array(
- '#type' => 'fieldset',
- '#title' => t('CAPTCHA'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- '#attributes' => array('class' => array('captcha-admin-links')),
- );
- if ($captcha_point !== NULL && $captcha_point->captcha_type) {
- $captcha_element['#title'] = t('CAPTCHA: challenge "@type" enabled', array('@type' => $captcha_point->captcha_type));
- $captcha_element['#description'] = t('Untrusted users will see a CAPTCHA here (general CAPTCHA settings ).',
- array('@settings' => url('admin/config/people/captcha'))
- );
- $captcha_element['challenge'] = array(
- '#type' => 'item',
- '#title' => t('Enabled challenge'),
- '#markup' => t('%type by module %module (change , disable )', array(
- '%type' => $captcha_point->captcha_type,
- '%module' => $captcha_point->module,
- '@change' => url("admin/config/people/captcha/captcha/captcha_point/$form_id", array('query' => drupal_get_destination())),
- '@disable' => url("admin/config/people/captcha/captcha/captcha_point/$form_id/disable", array('query' => drupal_get_destination())),
- )),
- );
- // Add an example challenge with solution.
- // This does not work with the reCAPTCHA and Egglue challenges as
- // discussed in http://drupal.org/node/487032 and
- // http://drupal.org/node/525586. As a temporary workaround, we
- // blacklist the reCAPTCHA and Egglue challenges and do not show
- // an example challenge.
- // TODO: Once the issues mentioned above are fixed, this workaround
- // should be removed.
- if ($captcha_point->module != 'recaptcha' && $captcha_point->module != 'egglue_captcha') {
- $captcha_element['example'] = array(
- '#type' => 'fieldset',
- '#title' => t('Example'),
- '#description' => t('This is a pre-solved, non-blocking example of this challenge.'),
- );
- $captcha_element['example']['example_captcha'] = array(
- '#type' => 'captcha',
- '#captcha_type' => $captcha_point->module . '/' . $captcha_point->captcha_type,
- '#captcha_admin_mode' => TRUE,
- );
- }
- }
- else {
- $captcha_element['#title'] = t('CAPTCHA: no challenge enabled');
- $captcha_element['add_captcha'] = array(
- '#markup' => l(t('Place a CAPTCHA here for untrusted users.'), "admin/config/people/captcha/captcha/captcha_point/$form_id", array('query' => drupal_get_destination()))
- );
-
- }
- // Get placement in form and insert in form.
- $captcha_placement = _captcha_get_captcha_placement($form_id, $form);
- _captcha_insert_captcha_element($form, $captcha_placement, $captcha_element);
-
- }
-
- // Add a warning about caching on the Perfomance settings page.
- if ($form_id == 'system_performance_settings') {
- $icon = theme('image', array('path' => 'misc/watchdog-warning.png', 'width' => 18, 'height' => 18, 'alt' => t('warning'), 'title' => t('warning')));
- $form['caching']['captcha'] = array(
- '#type' => 'item',
- '#title' => t('CAPTCHA'),
- '#markup' => t('!icon The CAPTCHA module will disable the caching of pages that contain a CAPTCHA element.', array(
- '!icon' => '' . $icon . ' ')
- ),
- '#attributes' => array('class' => array('warning')),
- );
- }
-
-}
-
-/**
- * CAPTCHA validation function to tests strict equality.
- * @param $solution the solution of the test.
- * @param $response the response to the test.
- * @return TRUE when strictly equal, FALSE otherwise.
- */
-function captcha_validate_strict_equality($solution, $response) {
- return $solution === $response;
-}
-
-/**
- * CAPTCHA validation function to tests case insensitive equality.
- * @param $solution the solution of the test.
- * @param $response the response to the test.
- * @return TRUE when case insensitive equal, FALSE otherwise.
- */
-function captcha_validate_case_insensitive_equality($solution, $response) {
- return drupal_strtolower($solution) === drupal_strtolower($response);
-}
-
-/**
- * CAPTCHA validation function to tests equality while ignoring spaces.
- * @param $solution the solution of the test.
- * @param $response the response to the test.
- * @return TRUE when equal (ignoring spaces), FALSE otherwise.
- */
-function captcha_validate_ignore_spaces($solution, $response) {
- return preg_replace('/\s/', '', $solution) === preg_replace('/\s/', '', $response);
-}
-
-/**
- * CAPTCHA validation function to tests case insensitive equality while ignoring spaces.
- * @param $solution the solution of the test.
- * @param $response the response to the test.
- * @return TRUE when equal (ignoring spaces), FALSE otherwise.
- */
-function captcha_validate_case_insensitive_ignore_spaces($solution, $response) {
- return preg_replace('/\s/', '', drupal_strtolower($solution)) === preg_replace('/\s/', '', drupal_strtolower($response));
-}
-
-/**
- * Helper function for getting the posted CAPTCHA info (posted form_id and
- * CAPTCHA sessions ID) from a form in case it is posted.
- *
- * This function hides the form processing mess for several use cases an
- * browser bug workarounds.
- * For example: $element['#post'] can typically be used to get the posted
- * form_id and captcha_sid, but in the case of node preview situations
- * (with correct CAPTCHA response) that does not work and we can get them from
- * $form_state['clicked_button']['#post'].
- * However with Internet Explorer 7, the latter does not work either when
- * submitting the forms (with only one text field) with the enter key
- * (see http://drupal.org/node/534168), in which case we also have to check
- * $form_state['buttons']['button']['0']['#post'].
- *
- * @todo for Drupal 7 version: is this IE7 workaround still needed?
- *
- * @param $element the CAPTCHA element.
- * @param $form_state the form state structure to extract the info from.
- * @param $this_form_id the form ID of the form we are currently processing
- * (which is not necessarily the form that was posted).
- *
- * @return an array with $posted_form_id and $post_captcha_sid (with NULL values
- * if the values could not be found, e.g. for a fresh form).
- */
-function _captcha_get_posted_captcha_info($element, $form_state, $this_form_id) {
- if ($form_state['submitted'] && isset($form_state['captcha_info'])) {
- // We are handling (or rebuilding) an already submitted form,
- // so we already determined the posted form ID and CAPTCHA session ID
- // for this form (from before submitting). Reuse this info.
- $posted_form_id = $form_state['captcha_info']['posted_form_id'];
- $posted_captcha_sid = $form_state['captcha_info']['captcha_sid'];
- }
- else {
- // We have to determine the posted form ID and CAPTCHA session ID
- // from the post data.
- // Because we possibly use raw post data here,
- // we should be extra cautious and filter this data.
- $posted_form_id = isset($form_state['input']['form_id']) ?
- preg_replace("/[^a-z0-9_]/", "", (string) $form_state['input']['form_id'])
- : NULL;
- $posted_captcha_sid = isset($form_state['input']['captcha_sid']) ?
- (int) $form_state['input']['captcha_sid']
- : NULL;
- $posted_captcha_token = isset($form_state['input']['captcha_token']) ?
- preg_replace("/[^a-zA-Z0-9]/", "", (string) $form_state['input']['captcha_token'])
- : NULL;
-
- if ($posted_form_id == $this_form_id) {
- // Check if the posted CAPTCHA token is valid for the posted CAPTCHA
- // session ID. Note that we could just check the validity of the CAPTCHA
- // token and extract the CAPTCHA session ID from that (without looking at
- // the actual posted CAPTCHA session ID). However, here we check both
- // the posted CAPTCHA token and session ID: it is a bit more stringent
- // and the database query should also be more efficient (because there is
- // an index on the CAPTCHA session ID).
- if ($posted_captcha_sid != NULL) {
- $expected_captcha_token = db_query(
- "SELECT token FROM {captcha_sessions} WHERE csid = :csid",
- array(':csid' => $posted_captcha_sid)
- )->fetchField();
- if ($expected_captcha_token !== $posted_captcha_token) {
- drupal_set_message(t('CAPTCHA session reuse attack detected.'), 'error');
- // Invalidate the CAPTCHA session.
- $posted_captcha_sid = NULL;
- }
- // Invalidate CAPTCHA token to avoid reuse.
- db_update('captcha_sessions')
- ->fields(array('token' => NULL))
- ->condition('csid', $posted_captcha_sid);
- }
- }
- else {
- // The CAPTCHA session ID is specific to the posted form.
- // Return NULL, so a new session will be generated for this other form.
- $posted_captcha_sid = NULL;
- }
- }
- return array($posted_form_id, $posted_captcha_sid);
-}
-
-/**
- * CAPTCHA validation handler.
- *
- * This function is placed in the main captcha.module file to make sure that
- * it is available (even for cached forms, which don't fire
- * captcha_form_alter(), and subsequently don't include additional include
- * files).
- */
-function captcha_validate($element, &$form_state) {
-
- $captcha_info = $form_state['captcha_info'];
- $form_id = $captcha_info['this_form_id'];
-
- // Get CAPTCHA response.
- $captcha_response = $form_state['values']['captcha_response'];
-
- // Get CAPTCHA session from CAPTCHA info
- // TODO: is this correct in all cases: see comment and code in previous revisions?
- $csid = $captcha_info['captcha_sid'];
-
- $solution = db_query(
- 'SELECT solution FROM {captcha_sessions} WHERE csid = :csid',
- array(':csid' => $csid)
- )
- ->fetchField();
-
- // @todo: what is the result when there is no entry for the captcha_session? in D6 it was FALSE, what in D7?
- if ($solution === FALSE) {
- // Unknown challenge_id.
- // TODO: this probably never happens anymore now that there is detection
- // for CAPTCHA session reuse attacks in _captcha_get_posted_captcha_info().
- form_set_error('captcha', t('CAPTCHA validation error: unknown CAPTCHA session ID. Contact the site administrator if this problem persists.'));
- watchdog('CAPTCHA',
- 'CAPTCHA validation error: unknown CAPTCHA session ID (%csid).',
- array('%csid' => var_export($csid, TRUE)),
- WATCHDOG_ERROR);
- }
- else {
- // Get CAPTCHA validate function or fall back on strict equality.
- $captcha_validate = $element['#captcha_validate'];
- if (!function_exists($captcha_validate)) {
- $captcha_validate = 'captcha_validate_strict_equality';
- }
- // Check the response with the CAPTCHA validation function.
- // Apart from the traditional expected $solution and received $response,
- // we also provide the CAPTCHA $element and $form_state arrays for more advanced use cases.
- if ($captcha_validate($solution, $captcha_response, $element, $form_state)) {
- // Correct answer.
-
- // Store form_id in session (but only if it is useful to do so, avoid setting stuff in session unnecessarily).
- $captcha_persistence = variable_get('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
- if ($captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL || $captcha_persistence == CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE) {
- $_SESSION['captcha_success_form_ids'][$form_id] = $form_id;
- }
-
- // Record success.
- db_update('captcha_sessions')
- ->condition('csid', $csid)
- ->fields(array('status' => CAPTCHA_STATUS_SOLVED))
- ->expression('attempts', 'attempts + 1')
- ->execute();
- }
- else {
- // Wrong answer.
- db_update('captcha_sessions')
- ->condition('csid', $csid)
- ->expression('attempts', 'attempts + 1')
- ->execute();
- // set form error
- form_set_error('captcha_response', t('The answer you entered for the CAPTCHA was not correct.'));
- // update wrong response counter
- if (variable_get('captcha_enable_stats', FALSE)) {
- variable_set('captcha_wrong_response_counter', variable_get('captcha_wrong_response_counter', 0) + 1);
- }
- // log to watchdog if needed
- if (variable_get('captcha_log_wrong_responses', FALSE)) {
- watchdog('CAPTCHA',
- '%form_id post blocked by CAPTCHA module: challenge %challenge (by module %module), user answered "@response", but the solution was "@solution".',
- array('%form_id' => $form_id,
- '@response' => $captcha_response, '@solution' => $solution,
- '%challenge' => $captcha_info['captcha_type'], '%module' => $captcha_info['module'],
- ),
- WATCHDOG_NOTICE);
- }
- }
- }
-}
-
-/**
- * Pre-render callback for additional processing of a CAPTCHA form element.
- *
- * This encompasses tasks that should happen after the general FAPI processing
- * (building, submission and validation) but before rendering (e.g. storing the solution).
- *
- * @param $element the CAPTCHA form element
- * @return the manipulated element
- */
-function captcha_pre_render_process($element) {
- module_load_include('inc', 'captcha');
-
- // Get form and CAPTCHA information.
- $captcha_info = $element['#captcha_info'];
- $form_id = $captcha_info['form_id'];
- $captcha_sid = (int)($captcha_info['captcha_sid']);
- // Check if CAPTCHA is still required.
- // This check is done in a first phase during the element processing
- // (@see captcha_process), but it is also done here for better support
- // of multi-page forms. Take previewing a node submission for example:
- // when the challenge is solved correctely on preview, the form is still
- // not completely submitted, but the CAPTCHA can be skipped.
- if (_captcha_required_for_user($captcha_sid, $form_id) || $element['#captcha_admin_mode']) {
- // Update captcha_sessions table: store the solution of the generated CAPTCHA.
- _captcha_update_captcha_session($captcha_sid, $captcha_info['solution']);
-
- // Handle the response field if it is available and if it is a textfield.
- if (isset($element['captcha_widgets']['captcha_response']['#type']) && $element['captcha_widgets']['captcha_response']['#type'] == 'textfield') {
- // Before rendering: presolve an admin mode challenge or
- // empty the value of the captcha_response form item.
- $value = $element['#captcha_admin_mode'] ? $captcha_info['solution'] : '';
- $element['captcha_widgets']['captcha_response']['#value'] = $value;
- }
- }
- else {
- // Remove CAPTCHA widgets from form.
- unset($element['captcha_widgets']);
- }
-
- return $element;
-}
-
-/**
- * Default implementation of hook_captcha().
- */
-function captcha_captcha($op, $captcha_type = '') {
- switch ($op) {
- case 'list':
- return array('Math');
- break;
-
- case 'generate':
- if ($captcha_type == 'Math') {
- $result = array();
- $answer = mt_rand(1, 20);
- $x = mt_rand(1, $answer);
- $y = $answer - $x;
- $result['solution'] = "$answer";
- // Build challenge widget.
- // Note that we also use t() for the math challenge itself. This makes
- // it possible to 'rephrase' the challenge a bit through localization
- // or string overrides.
- $result['form']['captcha_response'] = array(
- '#type' => 'textfield',
- '#title' => t('Math question'),
- '#description' => t('Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.'),
- '#field_prefix' => t('@x + @y = ', array('@x' => $x, '@y' => $y)),
- '#size' => 4,
- '#maxlength' => 2,
- '#required' => TRUE,
- );
- return $result;
- }
- elseif ($captcha_type == 'Test') {
- // This challenge is not visible through the administrative interface
- // as it is not listed in captcha_captcha('list'),
- // but it is meant for debugging and testing purposes.
- // TODO for Drupal 7 version: This should be done with a mock module,
- // but Drupal 6 does not support this (mock modules can not be hidden).
- $result = array(
- 'solution' => 'Test 123',
- 'form' => array(),
- );
- $result['form']['captcha_response'] = array(
- '#type' => 'textfield',
- '#title' => t('Test one two three'),
- '#required' => TRUE,
- );
- return $result;
- }
- break;
- }
-}
-
-/**
- * Implements hook_modules_enabled.
- */
-function captcha_modules_enabled() {
- // When new modules are enabled: clear the CAPTCHA placement cache, so that
- // new hook_captcha_placement_map hooks can be triggered.
- variable_del('captcha_placement_map_cache');
-}
diff --git a/sites/all/modules/contrib/captcha/captcha.test b/sites/all/modules/contrib/captcha/captcha.test
deleted file mode 100644
index bccefe37..00000000
--- a/sites/all/modules/contrib/captcha/captcha.test
+++ /dev/null
@@ -1,1139 +0,0 @@
-normal_user = $this->drupalCreateUser($permissions);
-
- // Create an admin user.
- $permissions[] = 'administer CAPTCHA settings';
- $permissions[] = 'skip CAPTCHA';
- $permissions[] = 'administer permissions';
- $permissions[] = 'administer content types';
- $this->admin_user = $this->drupalCreateUser($permissions);
-
- // Put comments on page nodes on a separate page (default in D7: below post).
- variable_set('comment_form_location_page', COMMENT_FORM_SEPARATE_PAGE);
-
- }
-
- /**
- * Assert that the response is accepted:
- * no "unknown CSID" message, no "CSID reuse attack detection" message,
- * no "wrong answer" message.
- */
- protected function assertCaptchaResponseAccepted() {
- // There should be no error message about unknown CAPTCHA session ID.
- $this->assertNoText(t(CAPTCHA_UNKNOWN_CSID_ERROR_MESSAGE),
- 'CAPTCHA response should be accepted (known CSID).',
- 'CAPTCHA');
- // There should be no error message about CSID reuse attack.
- $this->assertNoText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE),
- 'CAPTCHA response should be accepted (no CAPTCHA session reuse attack detection).',
- 'CAPTCHA');
- // There should be no error message about wrong response.
- $this->assertNoText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE),
- 'CAPTCHA response should be accepted (correct response).',
- 'CAPTCHA');
- }
-
- /**
- * Assert that there is a CAPTCHA on the form or not.
- * @param bool $presence whether there should be a CAPTCHA or not.
- */
- protected function assertCaptchaPresence($presence) {
- if ($presence) {
- $this->assertText(_captcha_get_description(),
- 'There should be a CAPTCHA on the form.', 'CAPTCHA');
- }
- else {
- $this->assertNoText(_captcha_get_description(),
- 'There should be no CAPTCHA on the form.', 'CAPTCHA');
- }
- }
-
- /**
- * Helper function to create a node with comments enabled.
- *
- * @return
- * Created node object.
- */
- protected function createNodeWithCommentsEnabled($type='page') {
- $node_settings = array(
- 'type' => $type,
- 'comment' => COMMENT_NODE_OPEN,
- );
- $node = $this->drupalCreateNode($node_settings);
- return $node;
- }
-
- /**
- * Helper function to generate a form values array for comment forms
- */
- protected function getCommentFormValues() {
- $edit = array(
- 'subject' => 'comment_subject ' . $this->randomName(32),
- 'comment_body[' . LANGUAGE_NONE . '][0][value]' => 'comment_body ' . $this->randomName(256),
- );
- return $edit;
- }
-
- /**
- * Helper function to generate a form values array for node forms
- */
- protected function getNodeFormValues() {
- $edit = array(
- 'title' => 'node_title ' . $this->randomName(32),
- 'body[' . LANGUAGE_NONE . '][0][value]' => 'node_body ' . $this->randomName(256),
- );
- return $edit;
- }
-
-
- /**
- * Get the CAPTCHA session id from the current form in the browser.
- */
- protected function getCaptchaSidFromForm() {
- $elements = $this->xpath('//input[@name="captcha_sid"]');
- $captcha_sid = (int) $elements[0]['value'];
- return $captcha_sid;
- }
- /**
- * Get the CAPTCHA token from the current form in the browser.
- */
- protected function getCaptchaTokenFromForm() {
- $elements = $this->xpath('//input[@name="captcha_token"]');
- $captcha_token = (int) $elements[0]['value'];
- return $captcha_token;
- }
-
- /**
- * Get the solution of the math CAPTCHA from the current form in the browser.
- */
- protected function getMathCaptchaSolutionFromForm() {
- // Get the math challenge.
- $elements = $this->xpath('//div[@class="form-item form-type-textfield form-item-captcha-response"]/span[@class="field-prefix"]');
- $challenge = (string) $elements[0];
- // Extract terms and operator from challenge.
- $matches = array();
- $ret = preg_match('/\\s*(\\d+)\\s*(-|\\+)\\s*(\\d+)\\s*=\\s*/', $challenge, $matches);
- // Solve the challenge
- $a = (int) $matches[1];
- $b = (int) $matches[3];
- $solution = $matches[2] == '-' ? $a - $b : $a + $b;
- return $solution;
- }
-
- /**
- * Helper function to allow comment posting for anonymous users.
- */
- protected function allowCommentPostingForAnonymousVisitors() {
- // Log in as admin.
- $this->drupalLogin($this->admin_user);
- // Post user permissions form
- $edit = array(
- '1[access comments]' => true,
- '1[post comments]' => true,
- '1[skip comment approval]' => true,
- );
- $this->drupalPost('admin/people/permissions', $edit, 'Save permissions');
- $this->assertText('The changes have been saved.');
- // Log admin out
- $this->drupalLogout();
- }
-
-}
-
-
-
-class CaptchaTestCase extends CaptchaBaseWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => t('General CAPTCHA functionality'),
- 'description' => t('Testing of the basic CAPTCHA functionality.'),
- 'group' => t('CAPTCHA'),
- );
- }
-
- /**
- * Testing the protection of the user log in form.
- */
- function testCaptchaOnLoginForm() {
- // Create user and test log in without CAPTCHA.
- $user = $this->drupalCreateUser();
- $this->drupalLogin($user);
- // Log out again.
- $this->drupalLogout();
-
- // Set a CAPTCHA on login form
- captcha_set_form_id_setting('user_login', 'captcha/Math');
-
- // Check if there is a CAPTCHA on the login form (look for the title).
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
-
- // Try to log in, which should fail.
- $edit = array(
- 'name' => $user->name,
- 'pass' => $user->pass_raw,
- 'captcha_response' => '?',
- );
- $this->drupalPost('user', $edit, t('Log in'));
- // Check for error message.
- $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE),
- 'CAPTCHA should block user login form', 'CAPTCHA');
-
- // And make sure that user is not logged in: check for name and password fields on ?q=user
- $this->drupalGet('user');
- $this->assertField('name', t('Username field found.'), 'CAPTCHA');
- $this->assertField('pass', t('Password field found.'), 'CAPTCHA');
-
- }
-
-
- /**
- * Assert function for testing if comment posting works as it should.
- *
- * Creates node with comment writing enabled, tries to post comment
- * with given CAPTCHA response (caller should enable the desired
- * challenge on page node comment forms) and checks if the result is as expected.
- *
- * @param $captcha_response the response on the CAPTCHA
- * @param $should_pass boolean describing if the posting should pass or should be blocked
- * @param $message message to prefix to nested asserts
- */
- protected function assertCommentPosting($captcha_response, $should_pass, $message) {
- // Make sure comments on pages can be saved directely without preview.
- variable_set('comment_preview_page', DRUPAL_OPTIONAL);
-
- // Create a node with comments enabled.
- $node = $this->createNodeWithCommentsEnabled();
-
- // Post comment on node.
- $edit = $this->getCommentFormValues();
- $comment_subject = $edit['subject'];
- $comment_body = $edit['comment_body[' . LANGUAGE_NONE . '][0][value]'];
- $edit['captcha_response'] = $captcha_response;
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Save'));
-
- if ($should_pass) {
- // There should be no error message.
- $this->assertCaptchaResponseAccepted();
- // Get node page and check that comment shows up.
- $this->drupalGet('node/' . $node->nid);
- $this->assertText($comment_subject, $message .' Comment should show up on node page.', 'CAPTCHA');
- $this->assertText($comment_body, $message . ' Comment should show up on node page.', 'CAPTCHA');
- }
- else {
- // Check for error message.
- $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), $message .' Comment submission should be blocked.', 'CAPTCHA');
- // Get node page and check that comment is not present.
- $this->drupalGet('node/' . $node->nid);
- $this->assertNoText($comment_subject, $message .' Comment should not show up on node page.', 'CAPTCHA');
- $this->assertNoText($comment_body, $message . ' Comment should not show up on node page.', 'CAPTCHA');
- }
- }
-
- /*
- * Testing the case sensistive/insensitive validation.
- */
- function testCaseInsensitiveValidation() {
- // Set Test CAPTCHA on comment form
- captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');
-
- // Log in as normal user.
- $this->drupalLogin($this->normal_user);
-
- // Test case sensitive posting.
- variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE);
- $this->assertCommentPosting('Test 123', TRUE, 'Case sensitive validation of right casing.');
- $this->assertCommentPosting('test 123', FALSE, 'Case sensitive validation of wrong casing.');
- $this->assertCommentPosting('TEST 123', FALSE, 'Case sensitive validation of wrong casing.');
-
- // Test case insensitive posting (the default)
- variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE);
- $this->assertCommentPosting('Test 123', TRUE, 'Case insensitive validation of right casing.');
- $this->assertCommentPosting('test 123', TRUE, 'Case insensitive validation of wrong casing.');
- $this->assertCommentPosting('TEST 123', TRUE, 'Case insensitive validation of wrong casing.');
-
- }
-
- /**
- * Test if the CAPTCHA description is only shown if there are challenge widgets to show.
- * For example, when a comment is previewed with correct CAPTCHA answer,
- * a challenge is generated and added to the form but removed in the pre_render phase.
- * The CAPTCHA description should not show up either.
- *
- * \see testCaptchaSessionReuseOnNodeForms()
- */
- function testCaptchaDescriptionAfterCommentPreview() {
- // Set Test CAPTCHA on comment form.
- captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');
-
- // Log in as normal user.
- $this->drupalLogin($this->normal_user);
-
- // Create a node with comments enabled.
- $node = $this->createNodeWithCommentsEnabled();
-
- // Preview comment with correct CAPTCHA answer.
- $edit = $this->getCommentFormValues();
- $edit['captcha_response'] = 'Test 123';
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
-
- // Check that there is no CAPTCHA after preview.
- $this->assertCaptchaPresence(FALSE);
- }
-
- /**
- * Test if the CAPTCHA session ID is reused when previewing nodes:
- * node preview after correct response should not show CAPTCHA anymore.
- * The preview functionality of comments and nodes works slightly different under the hood.
- * CAPTCHA module should be able to handle both.
- *
- * \see testCaptchaDescriptionAfterCommentPreview()
- */
- function testCaptchaSessionReuseOnNodeForms() {
- // Set Test CAPTCHA on page form.
- captcha_set_form_id_setting('page_node_form', 'captcha/Test');
-
- // Log in as normal user.
- $this->drupalLogin($this->normal_user);
-
- // Page settings to post, with correct CAPTCHA answer.
- $edit = $this->getNodeFormValues();
- $edit['captcha_response'] = 'Test 123';
- // Preview the node
- $this->drupalPost('node/add/page', $edit, t('Preview'));
-
- // Check that there is no CAPTCHA after preview.
- $this->assertCaptchaPresence(FALSE);
- }
-
-
- /**
- * CAPTCHA should also be put on admin pages even if visitor
- * has no access
- */
- function testCaptchaOnLoginBlockOnAdminPagesIssue893810() {
- // Set a CAPTCHA on login block form
- captcha_set_form_id_setting('user_login_block', 'captcha/Math');
-
- // Check if there is a CAPTCHA on home page.
- $this->drupalGet('node');
- $this->assertCaptchaPresence(TRUE);
-
- // Check there is a CAPTCHA on "forbidden" admin pages
- $this->drupalGet('admin');
- $this->assertCaptchaPresence(TRUE);
- }
-
-}
-
-
-class CaptchaAdminTestCase extends CaptchaBaseWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => t('CAPTCHA administration functionality'),
- 'description' => t('Testing of the CAPTCHA administration interface and functionality.'),
- 'group' => t('CAPTCHA'),
- );
- }
-
- /**
- * Test access to the admin pages.
- */
- function testAdminAccess() {
- $this->drupalLogin($this->normal_user);
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH);
- file_put_contents('tmp.simpletest.html', $this->drupalGetContent());
- $this->assertText(t('Access denied'), 'Normal users should not be able to access the CAPTCHA admin pages', 'CAPTCHA');
-
- $this->drupalLogin($this->admin_user);
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH);
- $this->assertNoText(t('Access denied'), 'Admin users should be able to access the CAPTCHA admin pages', 'CAPTCHA');
- }
-
- /**
- * Test the CAPTCHA point setting getter/setter.
- */
- function testCaptchaPointSettingGetterAndSetter() {
- $comment_form_id = self::COMMENT_FORM_ID;
- // Set to 'none'.
- captcha_set_form_id_setting($comment_form_id, 'none');
- $result = captcha_get_form_id_setting($comment_form_id);
- $this->assertNotNull($result, 'Setting and getting CAPTCHA point: none', 'CAPTCHA');
- $this->assertNull($result->module, 'Setting and getting CAPTCHA point: none', 'CAPTCHA');
- $this->assertNull($result->captcha_type, 'Setting and getting CAPTCHA point: none', 'CAPTCHA');
- $result = captcha_get_form_id_setting($comment_form_id, TRUE);
- $this->assertEqual($result, 'none', 'Setting and symbolic getting CAPTCHA point: "none"', 'CAPTCHA');
- // Set to 'default'
- captcha_set_form_id_setting($comment_form_id, 'default');
- variable_set('captcha_default_challenge', 'foo/bar');
- $result = captcha_get_form_id_setting($comment_form_id);
- $this->assertNotNull($result, 'Setting and getting CAPTCHA point: default', 'CAPTCHA');
- $this->assertEqual($result->module, 'foo', 'Setting and getting CAPTCHA point: default', 'CAPTCHA');
- $this->assertEqual($result->captcha_type, 'bar', 'Setting and getting CAPTCHA point: default', 'CAPTCHA');
- $result = captcha_get_form_id_setting($comment_form_id, TRUE);
- $this->assertEqual($result, 'default', 'Setting and symbolic getting CAPTCHA point: "default"', 'CAPTCHA');
- // Set to 'baz/boo'.
- captcha_set_form_id_setting($comment_form_id, 'baz/boo');
- $result = captcha_get_form_id_setting($comment_form_id);
- $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA');
- $this->assertEqual($result->module, 'baz', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA');
- $this->assertEqual($result->captcha_type, 'boo', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA');
- $result = captcha_get_form_id_setting($comment_form_id, TRUE);
- $this->assertEqual($result, 'baz/boo', 'Setting and symbolic getting CAPTCHA point: "baz/boo"', 'CAPTCHA');
- // Set to NULL (which should delete the CAPTCHA point setting entry).
- captcha_set_form_id_setting($comment_form_id, NULL);
- $result = captcha_get_form_id_setting($comment_form_id);
- $this->assertNull($result, 'Setting and getting CAPTCHA point: NULL', 'CAPTCHA');
- $result = captcha_get_form_id_setting($comment_form_id, TRUE);
- $this->assertNull($result, 'Setting and symbolic getting CAPTCHA point: NULL', 'CAPTCHA');
- // Set with object.
- $captcha_type = new stdClass;
- $captcha_type->module = 'baba';
- $captcha_type->captcha_type = 'fofo';
- captcha_set_form_id_setting($comment_form_id, $captcha_type);
- $result = captcha_get_form_id_setting($comment_form_id);
- $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA');
- $this->assertEqual($result->module, 'baba', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA');
- $this->assertEqual($result->captcha_type, 'fofo', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA');
- $result = captcha_get_form_id_setting($comment_form_id, TRUE);
- $this->assertEqual($result, 'baba/fofo', 'Setting and symbolic getting CAPTCHA point: "baba/fofo"', 'CAPTCHA');
-
- }
-
-
- /**
- * Helper function for checking CAPTCHA setting of a form.
- *
- * @param $form_id the form_id of the form to investigate.
- * @param $challenge_type what the challenge type should be:
- * NULL, 'none', 'default' or something like 'captcha/Math'
- */
- protected function assertCaptchaSetting($form_id, $challenge_type) {
- $result = captcha_get_form_id_setting(self::COMMENT_FORM_ID, TRUE);
- $this->assertEqual($result, $challenge_type,
- t('Check CAPTCHA setting for form: expected: @expected, received: @received.',
- array('@expected' => var_export($challenge_type, TRUE), '@received' => var_export($result, TRUE))),
- 'CAPTCHA');
- }
-
- /**
- * Testing of the CAPTCHA administration links.
- */
- function testCaptchAdminLinks() {
- // Log in as admin
- $this->drupalLogin($this->admin_user);
-
- // Enable CAPTCHA administration links.
- $edit = array(
- 'captcha_administration_mode' => TRUE,
- );
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration');
-
- // Create a node with comments enabled.
- $node = $this->createNodeWithCommentsEnabled();
-
- // Go to node page
- $this->drupalGet('node/' . $node->nid);
-
- // Click the add new comment link
- $this->clickLink(t('Add new comment'));
- $add_comment_url = $this->getUrl();
- // Remove fragment part from comment URL to avoid problems with later asserts
- $add_comment_url = strtok($add_comment_url, "#");
-
- ////////////////////////////////////////////////////////////
- // Click the CAPTCHA admin link to enable a challenge.
- $this->clickLink(t('Place a CAPTCHA here for untrusted users.'));
- // Enable Math CAPTCHA.
- $edit = array('captcha_type' => 'captcha/Math');
- $this->drupalPost($this->getUrl(), $edit, t('Save'));
-
- // Check if returned to original comment form.
- $this->assertUrl($add_comment_url, array(),
- 'After setting CAPTCHA with CAPTCHA admin links: should return to original form.', 'CAPTCHA');
- // Check if CAPTCHA was successfully enabled (on CAPTCHA admin links fieldset).
- $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')),
- 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA');
- // Check if CAPTCHA was successfully enabled (through API).
- $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'captcha/Math');
-
- //////////////////////////////////////////////////////
- // Edit challenge type through CAPTCHA admin links.
- $this->clickLink(t('change'));
- // Enable Math CAPTCHA.
- $edit = array('captcha_type' => 'default');
- $this->drupalPost($this->getUrl(), $edit, t('Save'));
-
- // Check if returned to original comment form.
- $this->assertEqual($add_comment_url, $this->getUrl(),
- 'After editing challenge type CAPTCHA admin links: should return to original form.', 'CAPTCHA');
- // Check if CAPTCHA was successfully changed (on CAPTCHA admin links fieldset).
- // This is actually the same as the previous setting because the captcha/Math is the
- // default for the default challenge. TODO Make sure the edit is a real change.
- $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')),
- 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA');
- // Check if CAPTCHA was successfully edited (through API).
- $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'default');
-
-
-
- //////////////////////////////////////////////////////
- // Disable challenge through CAPTCHA admin links.
- $this->clickLink(t('disable'));
- // And confirm.
- $this->drupalPost($this->getUrl(), array(), 'Disable');
-
- // Check if returned to original comment form.
- $this->assertEqual($add_comment_url, $this->getUrl(),
- 'After disablin challenge with CAPTCHA admin links: should return to original form.', 'CAPTCHA');
- // Check if CAPTCHA was successfully disabled (on CAPTCHA admin links fieldset).
- $this->assertText(t('CAPTCHA: no challenge enabled'),
- 'Disable challenge through the CAPTCHA admin links', 'CAPTCHA');
- // Check if CAPTCHA was successfully disabled (through API).
- $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'none');
-
- }
-
-
- function testUntrustedUserPosting() {
- // Set CAPTCHA on comment form.
- captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math');
-
- // Create a node with comments enabled.
- $node = $this->createNodeWithCommentsEnabled();
-
- // Log in as normal (untrusted) user.
- $this->drupalLogin($this->normal_user);
-
- // Go to node page and click the "add comment" link.
- $this->drupalGet('node/' . $node->nid);
- $this->clickLink(t('Add new comment'));
- $add_comment_url = $this->getUrl();
-
- // Check if CAPTCHA is visible on form.
- $this->assertCaptchaPresence(TRUE);
- // Try to post a comment with wrong answer.
- $edit = $this->getCommentFormValues();
- $edit['captcha_response'] = 'xx';
- $this->drupalPost($add_comment_url, $edit, t('Preview'));
- $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE),
- 'wrong CAPTCHA should block form submission.', 'CAPTCHA');
-
- //TODO: more testing for untrusted posts.
- }
-
-
-
- /**
- * Test XSS vulnerability on CAPTCHA description.
- */
- function testXssOnCaptchaDescription() {
- // Set CAPTCHA on user register form.
- captcha_set_form_id_setting('user_register', 'captcha/Math');
-
- // Put Javascript snippet in CAPTCHA description.
- $this->drupalLogin($this->admin_user);
- $xss = '';
- $edit = array('captcha_description' => $xss);
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration');
-
- // Visit user register form and check if Javascript snippet is there.
- $this->drupalLogout();
- $this->drupalGet('user/register');
- $this->assertNoRaw($xss, 'Javascript should not be allowed in CAPTCHA description.', 'CAPTCHA');
-
- }
-
- /**
- * Test the CAPTCHA placement clearing.
- */
- function testCaptchaPlacementCacheClearing() {
- // Set CAPTCHA on user register form.
- captcha_set_form_id_setting('user_register_form', 'captcha/Math');
- // Visit user register form to fill the CAPTCHA placement cache.
- $this->drupalGet('user/register');
- // Check if there is CAPTCHA placement cache.
- $placement_map = variable_get('captcha_placement_map_cache', NULL);
- $this->assertNotNull($placement_map, 'CAPTCHA placement cache should be set.');
- // Clear the cache
- $this->drupalLogin($this->admin_user);
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH, array(), t('Clear the CAPTCHA placement cache'));
- // Check that the placement cache is unset
- $placement_map = variable_get('captcha_placement_map_cache', NULL);
- $this->assertNull($placement_map, 'CAPTCHA placement cache should be unset after cache clear.');
- }
-
- /**
- * Helper function to get the CAPTCHA point setting straight from the database.
- * @param string $form_id
- * @return stdClass object
- */
- private function getCaptchaPointSettingFromDatabase($form_id) {
- $result = db_query(
- "SELECT * FROM {captcha_points} WHERE form_id = :form_id",
- array(':form_id' => $form_id)
- )->fetchObject();
- return $result;
- }
-
- /**
- * Method for testing the CAPTCHA point administration
- */
- function testCaptchaPointAdministration() {
- // Generate CAPTCHA point data:
- // Drupal form ID should consist of lowercase alphanumerics and underscore)
- $captcha_point_form_id = 'form_' . strtolower($this->randomName(32));
- // the Math CAPTCHA by the CAPTCHA module is always available, so let's use it
- $captcha_point_module = 'captcha';
- $captcha_point_type = 'Math';
-
- // Log in as admin
- $this->drupalLogin($this->admin_user);
-
- // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point
- $form_values = array(
- 'captcha_point_form_id' => $captcha_point_form_id,
- 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type,
- );
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point', $form_values, t('Save'));
- $this->assertText(t('Saved CAPTCHA point settings.'),
- 'Saving of CAPTCHA point settings');
-
- // Check in database
- $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id);
- $this->assertEqual($result->module, $captcha_point_module,
- 'Enabled CAPTCHA point should have module set');
- $this->assertEqual($result->captcha_type, $captcha_point_type,
- 'Enabled CAPTCHA point should have type set');
-
- // Disable CAPTCHA point again
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable', array(), t('Disable'));
- $this->assertRaw(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), 'Disabling of CAPTCHA point');
-
- // Check in database
- $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id);
- $this->assertNull($result->module,
- 'Disabled CAPTCHA point should have NULL as module');
- $this->assertNull($result->captcha_type,
- 'Disabled CAPTCHA point should have NULL as type');
-
- // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id
- $form_values = array(
- 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type,
- );
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id, $form_values, t('Save'));
- $this->assertText(t('Saved CAPTCHA point settings.'),
- 'Saving of CAPTCHA point settings');
-
- // Check in database
- $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id);
- $this->assertEqual($result->module, $captcha_point_module,
- 'Enabled CAPTCHA point should have module set');
- $this->assertEqual($result->captcha_type, $captcha_point_type,
- 'Enabled CAPTCHA point should have type set');
-
- // Delete CAPTCHA point
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete'));
- $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)),
- 'Deleting of CAPTCHA point');
-
- // Check in database
- $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id);
- $this->assertFalse($result, 'Deleted CAPTCHA point should be in database');
- }
-
- /**
- * Method for testing the CAPTCHA point administration
- */
- function testCaptchaPointAdministrationByNonAdmin() {
- // First add a CAPTCHA point (as admin)
- $this->drupalLogin($this->admin_user);
- $captcha_point_form_id = 'form_' . strtolower($this->randomName(32));
- $captcha_point_module = 'captcha';
- $captcha_point_type = 'Math';
- $form_values = array(
- 'captcha_point_form_id' => $captcha_point_form_id,
- 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type,
- );
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/', $form_values, t('Save'));
- $this->assertText(t('Saved CAPTCHA point settings.'),
- 'Saving of CAPTCHA point settings');
-
- // Switch from admin to nonadmin
- $this->drupalGet(url('logout', array('absolute' => TRUE)));
- $this->drupalLogin($this->normal_user);
-
-
- // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point');
- $this->assertText(t('You are not authorized to access this page.'),
- 'Non admin should not be able to set a CAPTCHA point');
-
- // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/' . 'form_' . strtolower($this->randomName(32)));
- $this->assertText(t('You are not authorized to access this page.'),
- 'Non admin should not be able to set a CAPTCHA point');
-
- // Try to disable the CAPTCHA point
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable');
- $this->assertText(t('You are not authorized to access this page.'),
- 'Non admin should not be able to disable a CAPTCHA point');
-
- // Try to delete the CAPTCHA point
- $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete');
- $this->assertText(t('You are not authorized to access this page.'),
- 'Non admin should not be able to delete a CAPTCHA point');
-
- // Switch from nonadmin to admin again
- $this->drupalGet(url('logout', array('absolute' => TRUE)));
- $this->drupalLogin($this->admin_user);
-
- // Check if original CAPTCHA point still exists in database
- $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id);
- $this->assertEqual($result->module, $captcha_point_module,
- 'Enabled CAPTCHA point should still have module set');
- $this->assertEqual($result->captcha_type, $captcha_point_type,
- 'Enabled CAPTCHA point should still have type set');
-
- // Delete CAPTCHA point
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete'));
- $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)),
- 'Deleting of CAPTCHA point');
- }
-
-
-
-}
-
-
-
-class CaptchaPersistenceTestCase extends CaptchaBaseWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => t('CAPTCHA persistence functionality'),
- 'description' => t('Testing of the CAPTCHA persistence functionality.'),
- 'group' => t('CAPTCHA'),
- );
- }
-
- /**
- * Set up the persistence and CAPTCHA settings.
- * @param int $persistence the persistence value.
- */
- private function setUpPersistence($persistence) {
- // Log in as admin
- $this->drupalLogin($this->admin_user);
- // Set persistence.
- $edit = array('captcha_persistence' => $persistence);
- $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration');
- // Log admin out.
- $this->drupalLogout();
-
- // Set the Test123 CAPTCHA on user register and comment form.
- // We have to do this with the function captcha_set_form_id_setting()
- // (because the CATCHA admin form does not show the Test123 option).
- // We also have to do this after all usage of the CAPTCHA admin form
- // (because posting the CAPTCHA admin form would set the CAPTCHA to 'none').
- captcha_set_form_id_setting('user_login', 'captcha/Test');
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- captcha_set_form_id_setting('user_register_form', 'captcha/Test');
- $this->drupalGet('user/register');
- $this->assertCaptchaPresence(TRUE);
- }
-
- protected function assertPreservedCsid($captcha_sid_initial) {
- $captcha_sid = $this->getCaptchaSidFromForm();
- $this->assertEqual($captcha_sid_initial, $captcha_sid,
- "CAPTCHA session ID should be preserved (expected: $captcha_sid_initial, found: $captcha_sid).");
- }
-
- protected function assertDifferentCsid($captcha_sid_initial) {
- $captcha_sid = $this->getCaptchaSidFromForm();
- $this->assertNotEqual($captcha_sid_initial, $captcha_sid,
- "CAPTCHA session ID should be different.");
- }
-
- function testPersistenceAlways(){
- // Set up of persistence and CAPTCHAs.
- $this->setUpPersistence(CAPTCHA_PERSISTENCE_SHOW_ALWAYS);
-
- // Go to login form and check if there is a CAPTCHA on the login form (look for the title).
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- $captcha_sid_initial = $this->getCaptchaSidFromForm();
-
- // Try to with wrong user name and password, but correct CAPTCHA.
- $edit = array(
- 'name' => 'foobar',
- 'pass' => 'bazlaz',
- 'captcha_response' => 'Test 123',
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check that there was no error message for the CAPTCHA.
- $this->assertCaptchaResponseAccepted();
-
- // Name and password were wrong, we should get an updated form with a fresh CAPTCHA.
- $this->assertCaptchaPresence(TRUE);
- $this->assertPreservedCsid($captcha_sid_initial);
-
- // Post from again.
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check that there was no error message for the CAPTCHA.
- $this->assertCaptchaResponseAccepted();
- $this->assertPreservedCsid($captcha_sid_initial);
-
- }
-
- function testPersistencePerFormInstance(){
- // Set up of persistence and CAPTCHAs.
- $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
-
- // Go to login form and check if there is a CAPTCHA on the login form.
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- $captcha_sid_initial = $this->getCaptchaSidFromForm();
-
- // Try to with wrong user name and password, but correct CAPTCHA.
- $edit = array(
- 'name' => 'foobar',
- 'pass' => 'bazlaz',
- 'captcha_response' => 'Test 123',
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check that there was no error message for the CAPTCHA.
- $this->assertCaptchaResponseAccepted();
- // There shouldn't be a CAPTCHA on the new form.
- $this->assertCaptchaPresence(FALSE);
- $this->assertPreservedCsid($captcha_sid_initial);
-
- // Start a new form instance/session
- $this->drupalGet('node');
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- $this->assertDifferentCsid($captcha_sid_initial);
-
- // Check another form
- $this->drupalGet('user/register');
- $this->assertCaptchaPresence(TRUE);
- $this->assertDifferentCsid($captcha_sid_initial);
-
- }
-
- function testPersistencePerFormType(){
- // Set up of persistence and CAPTCHAs.
- $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE);
-
- // Go to login form and check if there is a CAPTCHA on the login form.
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- $captcha_sid_initial = $this->getCaptchaSidFromForm();
-
- // Try to with wrong user name and password, but correct CAPTCHA.
- $edit = array(
- 'name' => 'foobar',
- 'pass' => 'bazlaz',
- 'captcha_response' => 'Test 123',
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check that there was no error message for the CAPTCHA.
- $this->assertCaptchaResponseAccepted();
- // There shouldn't be a CAPTCHA on the new form.
- $this->assertCaptchaPresence(FALSE);
- $this->assertPreservedCsid($captcha_sid_initial);
-
- // Start a new form instance/session
- $this->drupalGet('node');
- $this->drupalGet('user');
- $this->assertCaptchaPresence(FALSE);
- $this->assertDifferentCsid($captcha_sid_initial);
-
- // Check another form
- $this->drupalGet('user/register');
- $this->assertCaptchaPresence(TRUE);
- $this->assertDifferentCsid($captcha_sid_initial);
- }
-
- function testPersistenceOnlyOnce(){
- // Set up of persistence and CAPTCHAs.
- $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL);
-
- // Go to login form and check if there is a CAPTCHA on the login form.
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
- $captcha_sid_initial = $this->getCaptchaSidFromForm();
-
- // Try to with wrong user name and password, but correct CAPTCHA.
- $edit = array(
- 'name' => 'foobar',
- 'pass' => 'bazlaz',
- 'captcha_response' => 'Test 123',
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- // Check that there was no error message for the CAPTCHA.
- $this->assertCaptchaResponseAccepted();
- // There shouldn't be a CAPTCHA on the new form.
- $this->assertCaptchaPresence(FALSE);
- $this->assertPreservedCsid($captcha_sid_initial);
-
- // Start a new form instance/session
- $this->drupalGet('node');
- $this->drupalGet('user');
- $this->assertCaptchaPresence(FALSE);
- $this->assertDifferentCsid($captcha_sid_initial);
-
- // Check another form
- $this->drupalGet('user/register');
- $this->assertCaptchaPresence(FALSE);
- $this->assertDifferentCsid($captcha_sid_initial);
- }
-
-}
-
-
-class CaptchaSessionReuseAttackTestCase extends CaptchaBaseWebTestCase {
-
- public static function getInfo() {
- return array(
- 'name' => t('CAPTCHA session reuse attack tests'),
- 'description' => t('Testing of the protection against CAPTCHA session reuse attacks.'),
- 'group' => t('CAPTCHA'),
- );
- }
-
- /**
- * Assert that the CAPTCHA session ID reuse attack was detected.
- */
- protected function assertCaptchaSessionIdReuseAttackDetection() {
- $this->assertText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE),
- 'CAPTCHA session ID reuse attack should be detected.',
- 'CAPTCHA');
- // There should be an error message about wrong response.
- $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE),
- 'CAPTCHA response should flagged as wrong.',
- 'CAPTCHA');
- }
-
- function testCaptchaSessionReuseAttackDetectionOnCommentPreview() {
- // Create commentable node
- $node = $this->createNodeWithCommentsEnabled();
- // Set Test CAPTCHA on comment form.
- captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math');
- variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
-
- // Log in as normal user.
- $this->drupalLogin($this->normal_user);
-
- // Go to comment form of commentable node.
- $this->drupalGet('comment/reply/' . $node->nid);
- $this->assertCaptchaPresence(TRUE);
-
- // Get CAPTCHA session ID and solution of the challenge.
- $captcha_sid = $this->getCaptchaSidFromForm();
- $captcha_token = $this->getCaptchaTokenFromForm();
- $solution = $this->getMathCaptchaSolutionFromForm();
-
- // Post the form with the solution.
- $edit = $this->getCommentFormValues();
- $edit['captcha_response'] = $solution;
- $this->drupalPost(NULL, $edit, t('Preview'));
- // Answer should be accepted and further CAPTCHA ommitted.
- $this->assertCaptchaResponseAccepted();
- $this->assertCaptchaPresence(FALSE);
-
- // Post a new comment, reusing the previous CAPTCHA session.
- $edit = $this->getCommentFormValues();
- $edit['captcha_sid'] = $captcha_sid;
- $edit['captcha_token'] = $captcha_token;
- $edit['captcha_response'] = $solution;
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
- // CAPTCHA session reuse attack should be detected.
- $this->assertCaptchaSessionIdReuseAttackDetection();
- // There should be a CAPTCHA.
- $this->assertCaptchaPresence(TRUE);
-
- }
-
- function testCaptchaSessionReuseAttackDetectionOnNodeForm() {
- // Set CAPTCHA on page form.
- captcha_set_form_id_setting('page_node_form', 'captcha/Math');
- variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
-
- // Log in as normal user.
- $this->drupalLogin($this->normal_user);
-
- // Go to node add form.
- $this->drupalGet('node/add/page');
- $this->assertCaptchaPresence(TRUE);
-
- // Get CAPTCHA session ID and solution of the challenge.
- $captcha_sid = $this->getCaptchaSidFromForm();
- $captcha_token = $this->getCaptchaTokenFromForm();
- $solution = $this->getMathCaptchaSolutionFromForm();
-
- // Page settings to post, with correct CAPTCHA answer.
- $edit = $this->getNodeFormValues();
- $edit['captcha_response'] = $solution;
- // Preview the node
- $this->drupalPost(NULL, $edit, t('Preview'));
- // Answer should be accepted.
- $this->assertCaptchaResponseAccepted();
- // Check that there is no CAPTCHA after preview.
- $this->assertCaptchaPresence(FALSE);
-
- // Post a new comment, reusing the previous CAPTCHA session.
- $edit = $this->getNodeFormValues();
- $edit['captcha_sid'] = $captcha_sid;
- $edit['captcha_token'] = $captcha_token;
- $edit['captcha_response'] = $solution;
- $this->drupalPost('node/add/page', $edit, t('Preview'));
- // CAPTCHA session reuse attack should be detected.
- $this->assertCaptchaSessionIdReuseAttackDetection();
- // There should be a CAPTCHA.
- $this->assertCaptchaPresence(TRUE);
-
- }
-
- function testCaptchaSessionReuseAttackDetectionOnLoginForm() {
- // Set CAPTCHA on login form.
- captcha_set_form_id_setting('user_login', 'captcha/Math');
- variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE);
-
- // Go to log in form.
- $this->drupalGet('user');
- $this->assertCaptchaPresence(TRUE);
-
- // Get CAPTCHA session ID and solution of the challenge.
- $captcha_sid = $this->getCaptchaSidFromForm();
- $captcha_token = $this->getCaptchaTokenFromForm();
- $solution = $this->getMathCaptchaSolutionFromForm();
-
- // Log in through form.
- $edit = array(
- 'name' => $this->normal_user->name,
- 'pass' => $this->normal_user->pass_raw,
- 'captcha_response' => $solution,
- );
- $this->drupalPost(NULL, $edit, t('Log in'));
- $this->assertCaptchaResponseAccepted();
- $this->assertCaptchaPresence(FALSE);
- // If a "log out" link appears on the page, it is almost certainly because
- // the login was successful.
- $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $this->normal_user->name)), t('User login'));
-
- // Log out again.
- $this->drupalLogout();
-
- // Try to log in again, reusing the previous CAPTCHA session.
- $edit += array(
- 'captcha_sid' => $captcha_sid,
- 'captcha_token' => $captcha_token,
- );
- $this->drupalPost('user', $edit, t('Log in'));
- // CAPTCHA session reuse attack should be detected.
- $this->assertCaptchaSessionIdReuseAttackDetection();
- // There should be a CAPTCHA.
- $this->assertCaptchaPresence(TRUE);
- }
-
-
- public function testMultipleCaptchaProtectedFormsOnOnePage()
- {
- // Set Test CAPTCHA on comment form and login block
- captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');
- captcha_set_form_id_setting('user_login_block', 'captcha/Math');
- $this->allowCommentPostingForAnonymousVisitors();
-
- // Create a node with comments enabled.
- $node = $this->createNodeWithCommentsEnabled();
-
- // Preview comment with correct CAPTCHA answer.
- $edit = $this->getCommentFormValues();
- $comment_subject = $edit['subject'];
- $edit['captcha_response'] = 'Test 123';
- $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
- // Post should be accepted: no warnings,
- // no CAPTCHA reuse detection (which could be used by user log in block).
- $this->assertCaptchaResponseAccepted();
- $this->assertText($comment_subject);
-
- }
-
-}
-
-
-// Some tricks to debug:
-// drupal_debug($data) // from devel module
-// file_put_contents('tmp.simpletest.html', $this->drupalGetContent());
diff --git a/sites/all/modules/contrib/captcha/captcha_api.txt b/sites/all/modules/contrib/captcha/captcha_api.txt
deleted file mode 100644
index dc343fcc..00000000
--- a/sites/all/modules/contrib/captcha/captcha_api.txt
+++ /dev/null
@@ -1,219 +0,0 @@
-
-This documentation is for developers that want to implement their own
-challenge type and integrate it with the base CAPTCHA module.
-
-
-=== Required: hook_captcha($op, $captcha_type='') ===
-
-The hook_captcha() hook is the only required function if you want to integrate
-with the base CAPTCHA module.
-Functionality depends on the first argument $op:
- * 'list': you should return an array of possible challenge types
- that your module implements.
- * 'generate': generate a challenge.
- You should return an array that offers form elements and the solution
- of your challenge, defined by the second argument $captcha_type.
- The returned array $captcha should have the following items:
- $captcha['solution']: this is the solution of your challenge
- $captcha['form']: an array of the form elements you want to add to the form.
- There should be a key 'captcha_response' in this array, which points to
- the form element where the user enters his answer.
- An optional additional argument $captcha_sid with the captcha session ID is
- available for more advanced challenges (e.g. the image CAPTCHA uses this
- argument, see image_captcha_captcha()).
-
-Let's give a simple example to make this more clear.
-We create the challenge 'Foo CAPTCHA', which requires the user to
-enter "foo" in a textfield.
-
-"""
-/**
- * Implementation of hook_captcha().
- */
-function foo_captcha_captcha($op, $captcha_type='') {
- switch ($op) {
- case 'list':
- return array('Foo CAPTCHA');
- case 'generate':
- if ($captcha_type == 'Foo CAPTCHA') {
- $captcha = array();
- $captcha['solution'] = 'foo';
- $captcha['form']['captcha_response'] = array(
- '#type' => 'textfield',
- '#title' => t('Enter "foo"'),
- '#required' => TRUE,
- );
- return $captcha;
- }
- break;
- }
-}
-"""
-
-Validation of the answer against the solution and other stuff is done by the
-base CAPTCHA module.
-
-
-
-
-=== Required: the .info file ===
-
-You should specify that your module depends on the base CAPTCHA module.
-Optionally you could put your module in the "Spam control" package.
-
-For our simple foo CAPTCHA module this would mean the following lines in the
-file foo_captcha.info:
-
-"""
-name = "Foo CAPTCHA"
-description = "The foo CAPTCHA requires the user to enter the word 'foo'."
-package = "Spam control"
-dependencies[] = captcha
-core = 6.x
-"""
-
-
-
-
-=== Recommended: hook_menu($may_cache) ===
-
-More advanced CAPTCHA modules probably want some configuration page.
-To integrate nicely with the base CAPTCHA module you should offer your
-configuration page as a MENU_LOCAL_TASK menu entry under 'admin/config/people/captcha/'.
-
-For our simple foo CAPTCHA module this would mean:
-
-"""
-/**
- * Implementation of hook_menu().
- */
-function foo_captcha_menu($may_cache) {
- $items = array();
- if ($may_cache) {
- $items['admin/config/people/captcha/foo_captcha'] = array(
- 'title' => t('Foo CAPTCHA'),
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('foo_captcha_settings_form'),
- 'type' => MENU_LOCAL_TASK,
- );
- }
- return $items;
-}
-"""
-
-You should of course implement a function foo_captcha_settings_form() which
-returns the form of your configuration page.
-
-
-
-
-=== Optional: hook_help($section) ===
-To offer a description/explanation of your challenge, you can use the
-normal hook_help() system.
-
-For our simple foo CAPTCHA module this would mean:
-
-"""
-/**
- * Implementation of hook_help().
- */
-function foo_captcha_help($path, $arg) {
- switch ($path) {
- case 'admin/config/people/captcha/foo_captcha':
- return ''. t('This is a very simple challenge, which requires users to enter "foo" in a textfield.') .'
';
- }
-}
-"""
-
-
-
-=== Optional: custom response validation ===
-The CAPTCHA module provides an option for case sensitive and case insensitve
-validation of the responses. If this is not sufficient, you can provide
-your own validation function with the 'captcha_validate' field, illustrated
-by the following example:
-
-"""
-/**
- * Implementation of hook_captcha().
- */
-function foo_captcha_captcha($op, $captcha_type='') {
- switch ($op) {
- ...
- case 'generate':
- if ($captcha_type == 'Foo CAPTCHA') {
- $captcha = array();
- $captcha['solution'] = ...
- $captcha['form'] = ...
- $captcha['captcha_validate'] = 'foo_captcha_custom_validation';
- return $captcha;
- }
- break;
- }
-}
-
-/**
- * Custom CAPTCHA validation function.
- *
- * @param solution the solution for the challenge as reported by hook_captcha('generate', ...).
- * @param response the answer given by the user.
- * @return TRUE on succes and FALSE on failure.
- */
-function foo_captcha_custom_validation($solution, $response) {
- return $response == "foo" || $response == "bar";
-}
-"""
-
-Previous example shows the basic usage for custom validation with only a $solution
-and $response argument, which should be sufficient for most CAPTCHA modules.
-More advanced CAPTCHA modules can also use extra provided arguments $element
-and $form_state:
-"""
-function foo_captcha_custom_validation($solution, $response, $element, $form_state) {
- return $form_state['foo']['#bar'] = 'baz';
-}
-"""
-These extra arguments are the $element and $form_state arguments of the validation function
-of the #captcha element. See captcha_validate() in captcha.module for more info about this.
-
-
-
-=== Hook into CAPTCHA placement ===
-The CAPTCHA module attempts to place the CAPTCHA element in an appropriate spot
-at the bottom of the targeted form, but this automatic detection may be insufficient
-for complex forms.
-The hook_captcha_placement_map hook allows to define the placement of the CAPTCHA element
-as desired. The hook should return an array, mapping form IDs to placement arrays, which are
-associative arrays with the following fields:
- - 'path': path (array of path items) of the form's container element in which the
- CAPTCHA element should be inserted.
- - 'key': the key of the element before which the CAPTCHA element
- should be inserted. If the field 'key' is undefined or NULL, the CAPTCHA will
- just be appended in the container.
- - 'weight': if 'key' is not NULL: should be the weight of the element defined by 'key'.
- If 'key' is NULL and weight is not NULL/unset: set the weight property of the CAPTCHA element
- to this value.
-
-For example:
-"""
-/**
- * Implementation of hook_captcha_placement_map
- */
-function hook_captcha_placement_map() {
- return array(
- 'my_fancy_form' => array(
- 'path' => array('items', 'buttons'),
- 'key' => 'savebutton',
- ),
- 'another_form' => array(
- 'path' => array(),
- 'weight' => 34,
- ),
- );
-}
-"""
-This will place the CAPTCHA element
- - in the 'my_fancy_form' form inside the container $form['items']['buttons'],
- just before the element $form['items']['buttons']['sacebutton'].
- - in the 'another_form' form at the toplevel of the form, with a weight 34.
-
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/README.txt b/sites/all/modules/contrib/captcha/image_captcha/fonts/README.txt
deleted file mode 100644
index 452586d7..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/fonts/README.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-It possible to put your own fonts for the Image CAPTCHA in this folder.
-However, this is not the recommended way, as they can get lost easily during
-a module update. The recommended way to provide your own fonts is putting them
-in the files directory of your Drupal setup or, just like with contributed
-modules and themes, in the "libraries" folders sites/all/libraries/fonts
-or sites//libraries/fonts.
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox.ttf b/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox.ttf
deleted file mode 100644
index 31f91d34..00000000
Binary files a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox.ttf and /dev/null differ
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox_readme.txt b/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox_readme.txt
deleted file mode 100644
index b7470143..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tesox/tesox_readme.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-
-The Tesox typeface
-==================
-
-The Tesox typeface is created by Stefaan Lippens (also known as soxofaan on
-drupal.org, http://drupal.org/user/41478).
-It is based on hand drawn characters, converted to a TrueType font with the
-FontCapture web service (http://www.fontcapture.com).
-
-Background
-----------
-The Tesox typeface is created specifically for the image CAPTCHA module
-for Drupal (http://drupal.org/project/captcha). For a better out-of-the-box
-experience it was desired to include one or more typefaces with the CAPTCHA
-module package by default. However, this redistribution raised licensing issues.
-For example, according the code hosting policy of drupal.org, only GPL licensed
-code and resources are allowed in the drupal.org code repository (CVS).
-To avoid licensing and redistribution issues, it was decided to create a
-dedicated typeface for the image CAPTCHA module from scratch.
-
-Licencing
----------
-The Tesox typeface is GPLv2 licenced to be compatible with the drupal.org code
-hosting and packaging policies, as explained above.
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/README.txt b/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/README.txt
deleted file mode 100644
index 205343fb..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/README.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-
-This directory contains a subset (Regular and Bold) of the Tuffy typeface
-created by Thatcher Ulrich (http://tulrich.com/fonts) and released in the
-public domain.
-
-Original licensing statement of the creator
--------------------------------------------
-Here are my dabblings in font design. I have placed them in the Public Domain.
-This is all 100% my own work. Usage is totally unrestricted.
-If you want to make derivative works for any purpose, please go ahead.
-
-I welcome comments & constructive criticism.
-
-Put another way, a la PD-self (http://en.wikipedia.org/wiki/Template:PD-self):
- I, the copyright holder of this work, hereby release it into the public
- domain. This applies worldwide.
-
- In case this is not legally possible,
-
- I grant any entity the right to use this work for any purpose,
- without any conditions, unless such conditions are required by law.
-
--Thatcher Ulrich http://tulrich.com
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy.ttf b/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy.ttf
deleted file mode 100755
index 8ea64709..00000000
Binary files a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy.ttf and /dev/null differ
diff --git a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy_Bold.ttf b/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy_Bold.ttf
deleted file mode 100755
index 9574aab6..00000000
Binary files a/sites/all/modules/contrib/captcha/image_captcha/fonts/Tuffy/Tuffy_Bold.ttf and /dev/null differ
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.admin.inc b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.admin.inc
deleted file mode 100644
index 5bf39fcd..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.admin.inc
+++ /dev/null
@@ -1,442 +0,0 @@
-GD library with JPEG support).',
- array('!gdlib' => 'http://php.net/manual/en/book.image.php')
- ), 'error');
- // It is no use to continue building the rest of the settings form.
- return $form;
- }
-
- $form['image_captcha_example'] = array(
- '#type' => 'fieldset',
- '#title' => t('Example'),
- '#description' => t('Presolved image CAPTCHA example, generated with the current settings.'),
- );
- $form['image_captcha_example']['image'] = array(
- '#type' => 'captcha',
- '#captcha_type' => 'image_captcha/Image',
- '#captcha_admin_mode' => TRUE,
- );
-
- // General code settings.
- $form['image_captcha_code_settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Code settings'),
- );
- $form['image_captcha_code_settings']['image_captcha_image_allowed_chars'] = array(
- '#type' => 'textfield',
- '#title' => t('Characters to use in the code'),
- '#default_value' => variable_get('image_captcha_image_allowed_chars', IMAGE_CAPTCHA_ALLOWED_CHARACTERS),
- );
- $form['image_captcha_code_settings']['image_captcha_code_length'] = array(
- '#type' => 'select',
- '#title' => t('Code length'),
- '#options' => array(2 => 2, 3, 4, 5, 6, 7, 8, 9, 10),
- '#default_value' => (int) variable_get('image_captcha_code_length', 5),
- '#description' => t('The code length influences the size of the image. Note that larger values make the image generation more CPU intensive.'),
- );
- // RTL support option (only show this option when there are RTL languages).
- $languages = language_list('direction');
- if (isset($languages[LANGUAGE_RTL])) {
- $form['image_captcha_code_settings']['image_captcha_rtl_support'] = array(
- '#type' => 'checkbox',
- '#title' => t('RTL support'),
- '#default_value' => variable_get('image_captcha_rtl_support', 0),
- '#description' => t('Enable this option to render the code from right to left for right to left languages.'),
- );
- }
-
-
- // Font related stuff.
- $form['image_captcha_font_settings'] = _image_captcha_settings_form_font_section();
-
- // Color and file format settings.
- $form['image_captcha_color_settings'] = array(
- '#type' => 'fieldset',
- '#title' => t('Color and image settings'),
- '#description' => t('Configuration of the background, text colors and file format of the image CAPTCHA.'),
- );
- $form['image_captcha_color_settings']['image_captcha_background_color'] = array(
- '#type' => 'textfield',
- '#title' => t('Background color'),
- '#description' => t('Enter the hexadecimal code for the background color (e.g. #FFF or #FFCE90). When using the PNG file format with transparent background, it is recommended to set this close to the underlying background color.'),
- '#default_value' => variable_get('image_captcha_background_color', '#ffffff'),
- '#maxlength' => 7,
- '#size' => 8,
- );
- $form['image_captcha_color_settings']['image_captcha_foreground_color'] = array(
- '#type' => 'textfield',
- '#title' => t('Text color'),
- '#description' => t('Enter the hexadecimal code for the text color (e.g. #000 or #004283).'),
- '#default_value' => variable_get('image_captcha_foreground_color', '#000000'),
- '#maxlength' => 7,
- '#size' => 8,
- );
- $form['image_captcha_color_settings']['image_captcha_foreground_color_randomness'] = array(
- '#type' => 'select',
- '#title' => t('Additional variation of text color'),
- '#options' => array(
- 0 => t('No variation'),
- 50 => t('Little variation'),
- 100 => t('Medium variation'),
- 150 => t('High variation'),
- 200 => t('Very high variation'),
- ),
- '#default_value' => (int) variable_get('image_captcha_foreground_color_randomness', 100),
- '#description' => t('The different characters will have randomized colors in the specified range around the text color.'),
- );
- $form['image_captcha_color_settings']['image_captcha_file_format'] = array(
- '#type' => 'select',
- '#title' => t('File format'),
- '#description' => t('Select the file format for the image. JPEG usually results in smaller files, PNG allows tranparency.'),
- '#default_value' => variable_get('image_captcha_file_format', IMAGE_CAPTCHA_FILE_FORMAT_JPG),
- '#options' => array(
- IMAGE_CAPTCHA_FILE_FORMAT_JPG => t('JPEG'),
- IMAGE_CAPTCHA_FILE_FORMAT_PNG => t('PNG'),
- IMAGE_CAPTCHA_FILE_FORMAT_TRANSPARENT_PNG => t('PNG with transparent background'),
- ),
- );
-
- // distortion and noise settings
- $form['image_captcha_distortion_and_noise'] = array(
- '#type' => 'fieldset',
- '#title' => t('Distortion and noise'),
- '#description' => t('With these settings you can control the degree of obfuscation by distortion and added noise. Do not exaggerate the obfuscation and assure that the code in the image is reasonably readable. For example, do not combine high levels of distortion and noise.'),
- );
- // distortion
- $form['image_captcha_distortion_and_noise']['image_captcha_distortion_amplitude'] = array(
- '#type' => 'select',
- '#title' => t('Distortion level'),
- '#options' => array(
- 0 => t('@level - no distortion', array('@level' => '0')),
- 1 => t('@level - low', array('@level' => '1')),
- 2 => '2',
- 3 => '3',
- 4 => '4',
- 5 => t('@level - medium', array('@level' => '5')),
- 6 => '6',
- 7 => '7',
- 8 => '8',
- 9 => '9',
- 10 => t('@level - high', array('@level' => '10')),
- ),
- '#default_value' => (int) variable_get('image_captcha_distortion_amplitude', 0),
- '#description' => t('Set the degree of wave distortion in the image.'),
- );
- $form['image_captcha_distortion_and_noise']['image_captcha_bilinear_interpolation'] = array(
- '#type' => 'checkbox',
- '#title' => t('Smooth distortion'),
- '#default_value' => variable_get('image_captcha_bilinear_interpolation', FALSE),
- '#description' => t('This option enables bilinear interpolation of the distortion which makes the image look smoother, but it is more CPU intensive.'),
- );
- // noise
- $form['image_captcha_distortion_and_noise']['image_captcha_dot_noise'] = array(
- '#type' => 'checkbox',
- '#title' => t('Add salt and pepper noise'),
- '#default_value' => variable_get('image_captcha_dot_noise', 0),
- '#description' => t('This option adds randomly colored point noise.'),
- );
- $form['image_captcha_distortion_and_noise']['image_captcha_line_noise'] = array(
- '#type' => 'checkbox',
- '#title' => t('Add line noise'),
- '#default_value' => variable_get('image_captcha_line_noise', 0),
- '#description' => t('This option enables lines randomly drawn on top of the text code.'),
- );
- $form['image_captcha_distortion_and_noise']['image_captcha_noise_level'] = array(
- '#type' => 'select',
- '#title' => t('Noise level'),
- '#options' => array(
- 1 => '1 - ' . t('low'),
- 2 => '2',
- 3 => '3 - ' . t('medium'),
- 4 => '4',
- 5 => '5 - ' . t('high'),
- 7 => '7',
- 10 => '10 - ' . t('severe'),
- ),
- '#default_value' => (int) variable_get('image_captcha_noise_level', 5),
- );
-
- // Add a validation handler.
- $form['#validate'] = array('image_captcha_settings_form_validate');
-
- // Make it a settings form.
- $form = system_settings_form($form);
- // But also do some custom submission handling.
- $form['#submit'][] = 'image_captcha_settings_form_submit';
-
- return $form;
-}
-
-
-/**
- * Form elements for the font specific setting.
- *
- * This is refactored to a separate function to avoid poluting the
- * general form function image_captcha_settings_form with some
- * specific logic.
- *
- * @return $form, the font settings specific form elements.
- */
-function _image_captcha_settings_form_font_section() {
- // Put it all in a fieldset.
- $form = array(
- '#type' => 'fieldset',
- '#title' => t('Font settings'),
- );
-
- // First check if there is TrueType support.
- $setup_status = _image_captcha_check_setup(FALSE);
- if ($setup_status & IMAGE_CAPTCHA_ERROR_NO_TTF_SUPPORT) {
- // Show a warning that there is no TrueType support
- $form['no_ttf_support'] = array(
- '#type' => 'item',
- '#title' => t('No TrueType support'),
- '#markup' => t('The Image CAPTCHA module can not use TrueType fonts because your PHP setup does not support it. You can only use a PHP built-in bitmap font of fixed size.'),
- );
-
- }
- else {
-
- // Build a list of all available fonts.
- $available_fonts = array();
-
- // List of folders to search through for TrueType fonts.
- $fonts = _image_captcha_get_available_fonts_from_directories();
- // Cache the list of previewable fonts. All the previews are done
- // in separate requests, and we don't want to rescan the filesystem
- // every time, so we cache the result.
- variable_set('image_captcha_fonts_preview_map_cache', $fonts);
- // Put these fonts with preview image in the list
- foreach ($fonts as $token => $font) {
- $img_src = check_url(url('admin/config/people/captcha/image_captcha/font_preview/' . $token));
- $title = t('Font preview of @font (@file)', array('@font' => $font->name, '@file' => $font->uri));
- $available_fonts[$font->uri] = ' ';
- }
-
- // Append the PHP built-in font at the end.
- $img_src = check_url(url('admin/config/people/captcha/image_captcha/font_preview/BUILTIN'));
- $title = t('Preview of built-in font');
- $available_fonts['BUILTIN'] = t('PHP built-in font: !font_preview',
- array('!font_preview' => ' ')
- );
-
- $default_fonts = _image_captcha_get_enabled_fonts();
- $form['image_captcha_fonts'] = array(
- '#type' => 'checkboxes',
- '#title' => t('Fonts'),
- '#default_value' => $default_fonts,
- '#description' => t('Select the fonts to use for the text in the image CAPTCHA. Apart from the provided defaults, you can also use your own TrueType fonts (filename extension .ttf) by putting them in %fonts_library_general or %fonts_library_specific.',
- array(
- '%fonts_library_general' => 'sites/all/libraries/fonts',
- '%fonts_library_specific' => conf_path() . '/libraries/fonts',
- )
- ),
- '#options' => $available_fonts,
- '#attributes' => array('class' => array('image_captcha_admin_fonts_selection')),
- '#process' => array('form_process_checkboxes'),
- );
-
-
- // Font size.
- $form['image_captcha_font_size'] = array(
- '#type' => 'select',
- '#title' => t('Font size'),
- '#options' => array(
- 9 => '9 pt - ' . t('tiny'),
- 12 => '12 pt - ' . t('small'),
- 18 => '18 pt',
- 24 => '24 pt - ' . t('normal'),
- 30 => '30 pt',
- 36 => '36 pt - ' . t('large'),
- 48 => '48 pt',
- 64 => '64 pt - ' . t('extra large'),
- ),
- '#default_value' => (int) variable_get('image_captcha_font_size', 30),
- '#description' => t('The font size influences the size of the image. Note that larger values make the image generation more CPU intensive.'),
- );
-
- }
-
- // Character spacing (available for both the TrueType fonts and the builtin font.
- $form['image_captcha_font_settings']['image_captcha_character_spacing'] = array(
- '#type' => 'select',
- '#title' => t('Character spacing'),
- '#description' => t('Define the average spacing between characters. Note that larger values make the image generation more CPU intensive.'),
- '#default_value' => variable_get('image_captcha_character_spacing', '1.2'),
- '#options' => array(
- '0.75' => t('tight'),
- '1' => t('normal'),
- '1.2' => t('wide'),
- '1.5' => t('extra wide'),
- ),
- );
-
- return $form;
-}
-
-/**
- * Helper function to get fonts from the given directories.
- *
- * @param $directories (optional) an array of directories
- * to recursively search through, if not given, the default
- * directories will be used.
- *
- * @return an array of fonts file objects (with fields 'name',
- * 'basename' and 'filename'), keyed on the md5 hash of the font
- * path (to have an easy token that can be used in an url
- * without en/decoding issues).
- */
-function _image_captcha_get_available_fonts_from_directories($directories=NULL) {
- // If no fonts directories are given: use the default.
- if ($directories === NULL) {
- $directories = array(
- drupal_get_path('module', 'image_captcha') . '/fonts',
- 'sites/all/libraries/fonts',
- conf_path() . '/libraries/fonts',
- );
- }
- // Collect the font information.
- $fonts = array();
- foreach ($directories as $directory) {
- foreach (file_scan_directory($directory, '/\.[tT][tT][fF]$/') as $filename => $font) {
- $fonts[md5($filename)] = $font;
- }
- }
-
- return $fonts;
-}
-
-
-/**
- * Validation function for image_captcha configuration form
- */
-function image_captcha_settings_form_validate($form, &$form_state) {
- // Check image_captcha_image_allowed_chars for spaces.
- if (preg_match('/\s/', $form_state['values']['image_captcha_image_allowed_chars'])) {
- form_set_error('image_captcha_image_allowed_chars', t('The list of characters to use should not contain spaces.'));
- }
-
- if (!isset($form['image_captcha_font_settings']['no_ttf_support'])) {
- // Check the selected fonts.
- // Filter the image_captcha fonts array to pick out the selected ones.
- $fonts = array_filter($form_state['values']['image_captcha_fonts']);
- if (count($fonts) < 1) {
- form_set_error('image_captcha_fonts', t('You need to select at least one font.'));
- }
- if ($form_state['values']['image_captcha_fonts']['BUILTIN']) {
- // With the built in font, only latin2 characters should be used.
- if (preg_match('/[^a-zA-Z0-9]/', $form_state['values']['image_captcha_image_allowed_chars'])) {
- form_set_error('image_captcha_image_allowed_chars', t('The built-in font only supports Latin2 characters. Only use "a" to "z" and numbers.'));
- }
- }
- list($readable_fonts, $problem_fonts) = _image_captcha_check_fonts($fonts);
- if (count($problem_fonts) > 0) {
- form_set_error('image_captcha_fonts', t('The following fonts are not readable: %fonts.', array('%fonts' => implode(', ', $problem_fonts))));
- }
- }
-
- // check color settings
- if (!preg_match('/^#([0-9a-fA-F]{3}){1,2}$/', $form_state['values']['image_captcha_background_color'])) {
- form_set_error('image_captcha_background_color', t('Background color is not a valid hexadecimal color value.'));
- }
- if (!preg_match('/^#([0-9a-fA-F]{3}){1,2}$/', $form_state['values']['image_captcha_foreground_color'])) {
- form_set_error('image_captcha_foreground_color', t('Text color is not a valid hexadecimal color value.'));
- }
-}
-
-/**
- * Submit function for image_captcha configuration form.
- */
-function image_captcha_settings_form_submit($form, &$form_state) {
- if (!isset($form['image_captcha_font_settings']['no_ttf_support'])) {
- // Filter the image_captcha fonts array to pick out the selected ones.
- $fonts = array_filter($form_state['values']['image_captcha_fonts']);
- variable_set('image_captcha_fonts', $fonts);
- }
-}
-
-/**
- * Menu handler for font preview request.
- *
- */
-function image_captcha_font_preview($font_token) {
-
- // Get the font from the given font token.
- if ($font_token == 'BUILTIN') {
- $font = 'BUILTIN';
- }
- else {
- // Get the mapping of font tokens to font file objects.
- $fonts = variable_get('image_captcha_fonts_preview_map_cache', array());
- if (!isset($fonts[$font_token])) {
- echo('bad token');
- exit();
- }
- // Get the font path.
- $font = $fonts[$font_token]->uri;
- // Some sanity checks if the given font is valid.
- if (!is_file($font) || !is_readable($font)) {
- echo('bad font');
- exit();
- }
- }
-
- // Settings of the font preview.
- $width = 120;
- $text = 'AaBbCc123';
- $font_size = 14;
- $height = 2 * $font_size;
-
- // Allocate image resource.
- $image = imagecreatetruecolor($width, $height);
- if (!$image) {
- exit();
- }
- // White background and black foreground.
- $background_color = imagecolorallocate($image, 255, 255, 255);
- $color = imagecolorallocate($image, 0, 0, 0);
- imagefilledrectangle($image, 0, 0, $width, $height, $background_color);
-
- // Draw preview text
- if ($font == 'BUILTIN') {
- imagestring($image, 5, 1, .5*$height-10, $text, $color);
- }
- else {
- imagettftext($image, $font_size, 0, 1, 1.5*$font_size, $color, realpath($font), $text);
- }
-
- // Set content type.
- drupal_add_http_header('Content-Type', 'image/png');
- // Dump image data to client.
- imagepng($image);
- // Release image memory.
- imagedestroy($image);
-
- // Close connection.
- exit();
-}
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.css b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.css
deleted file mode 100644
index d6e2f760..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.css
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Styling of the font selection list (with previews)
- * on the Image CAPTCHA settings page.
- */
-
-/**
- * Float the fonts with preview (with a fixed width)
- * to create a multi-column layout.
- */
-.image_captcha_admin_fonts_selection .form-item {
- float: left;
- width: 160px;
-}
-
-/**
- * Stop floating with the item for the built in font.
- */
-.image_captcha_admin_fonts_selection .form-item-image-captcha-fonts-BUILTIN {
- clear: both;
- float: none;
- width: 100%;
-}
-
-/**
- * Center the font previews vertically to the text.
- */
-.image_captcha_admin_fonts_selection img {
- vertical-align: middle;
-}
-
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.info b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.info
deleted file mode 100644
index 1c0e9b16..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.info
+++ /dev/null
@@ -1,18 +0,0 @@
-name = "Image CAPTCHA"
-description = "Provides an image based CAPTCHA."
-package = "Spam control"
-dependencies[] = captcha
-core = 7.x
-configure = admin/config/people/captcha/image_captcha
-
-files[] = image_captcha.install
-files[] = image_captcha.module
-files[] = image_captcha.admin.inc
-files[] = image_captcha.user.inc
-
-; Information added by drupal.org packaging script on 2013-06-25
-version = "7.x-1.0"
-core = "7.x"
-project = "captcha"
-datestamp = "1372203950"
-
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.install b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.install
deleted file mode 100644
index 1f6385c6..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.install
+++ /dev/null
@@ -1,40 +0,0 @@
- $t('Image CAPTCHA requires GD library'),
- 'description' =>
- $t('The Image CAPTCHA module can not be installed because your PHP setup does not provide the GD library , which is required to generate images.',
- array('!gddoc' => 'http://www.php.net/manual/en/book.image.php',)
- ),
- 'severity' => REQUIREMENT_ERROR,
- );
- }
- }
- return $requirements;
-}
-
-/**
- * On uninstall: remove module variables and clear variable cache
- */
-function image_captcha_uninstall() {
- db_delete('variable')
- ->condition('name', db_like('image_captcha_') . '%', 'LIKE')
- ->execute();
- cache_clear_all('variables', 'cache');
-}
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.js b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.js
deleted file mode 100644
index b20facc7..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.js
+++ /dev/null
@@ -1,40 +0,0 @@
-(function($) {
-
- Drupal.behaviors.captchaAdmin = {
- attach : function(context) {
-
- // Helper function to show/hide noise level widget.
- var noise_level_shower = function(speed) {
- speed = (typeof speed == 'undefined') ? 'slow' : speed;
- if ($("#edit-image-captcha-dot-noise").is(":checked")
- || $("#edit-image-captcha-line-noise").is(":checked")) {
- $(".form-item-image-captcha-noise-level").show(speed);
- } else {
- $(".form-item-image-captcha-noise-level").hide(speed);
- }
- }
- // Add onclick handler to the dot and line noise check boxes.
- $("#edit-image-captcha-dot-noise").click(noise_level_shower);
- $("#edit-image-captcha-line-noise").click(noise_level_shower);
- // Show or hide appropriately on page load.
- noise_level_shower(0);
-
- // Helper function to show/hide smooth distortion widget.
- var smooth_distortion_shower = function(speed) {
- speed = (typeof speed == 'undefined') ? 'slow' : speed;
- if ($("#edit-image-captcha-distortion-amplitude").val() > 0) {
- $(".form-item-image-captcha-bilinear-interpolation").show(speed);
- } else {
- $(".form-item-image-captcha-bilinear-interpolation").hide(speed);
- }
- }
- // Add onchange handler to the distortion level select widget.
- $("#edit-image-captcha-distortion-amplitude").change(
- smooth_distortion_shower);
- // Show or hide appropriately on page load.
- smooth_distortion_shower(0)
-
- }
- };
-
-})(jQuery);
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.module b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.module
deleted file mode 100644
index fc1e850a..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.module
+++ /dev/null
@@ -1,272 +0,0 @@
-' . t('The image CAPTCHA is a popular challenge where a random textual code is obfuscated in an image. The image is generated on the fly for each request, which is rather CPU intensive for the server. Be careful with the size and computation related settings.') . '';
- return $output;
- }
-}
-
-/**
- * Implements hook_menu().
- */
-function image_captcha_menu() {
- $items = array();
- // add an administration tab for image_captcha
- $items['admin/config/people/captcha/image_captcha'] = array(
- 'title' => 'Image CAPTCHA',
- 'file' => 'image_captcha.admin.inc',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('image_captcha_settings_form'),
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_LOCAL_TASK,
- );
- // Menu path for generating font example.
- $items['admin/config/people/captcha/image_captcha/font_preview'] = array(
- 'title' => 'Font example',
- 'file' => 'image_captcha.admin.inc',
- 'page callback' => 'image_captcha_font_preview',
- 'access arguments' => array('administer CAPTCHA settings'),
- 'type' => MENU_CALLBACK,
- );
- // callback for generating an image
- $items['image_captcha'] = array(
- 'file' => 'image_captcha.user.inc',
- 'page callback' => 'image_captcha_image',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- );
- return $items;
-}
-
-/**
- * Helper function for getting the fonts to use in the image CAPTCHA.
- *
- * @return a list of font paths.
- */
-function _image_captcha_get_enabled_fonts() {
- if (IMAGE_CAPTCHA_ERROR_NO_TTF_SUPPORT & _image_captcha_check_setup(FALSE)) {
- return array('BUILTIN');
- }
- else {
- $default = array(
- drupal_get_path('module', 'image_captcha') . '/fonts/Tesox/tesox.ttf',
- drupal_get_path('module', 'image_captcha') . '/fonts/Tuffy/Tuffy.ttf',
- );
- return variable_get('image_captcha_fonts', $default);
- }
-}
-
-/**
- * Helper function for checking if the specified fonts are available.
- *
- * @param $fonts paths of fonts to check.
- * @return list($readable_fonts, $problem_fonts)
- */
-function _image_captcha_check_fonts($fonts) {
- $readable_fonts = array();
- $problem_fonts = array();
- foreach ($fonts as $font) {
- if ($font != 'BUILTIN' && (!is_file($font) || !is_readable($font))) {
- $problem_fonts[] = $font;
- }
- else {
- $readable_fonts[] = $font;
- }
- }
- return array($readable_fonts, $problem_fonts);
-}
-
-/**
- * Helper function for splitting an utf8 string correctly in characters.
- * Assumes the given utf8 string is well formed.
- * See http://en.wikipedia.org/wiki/Utf8 for more info
- */
-function _image_captcha_utf8_split($str) {
- $characters = array();
- $len = strlen($str);
- for ($i=0; $i < $len; ) {
- $chr = ord($str[$i]);
- if (($chr & 0x80) == 0x00) { // one byte character (0zzzzzzz)
- $width = 1;
- }
- else {
- if (($chr & 0xE0) == 0xC0) { // two byte character (first byte: 110yyyyy)
- $width = 2;
- }
- elseif (($chr & 0xF0) == 0xE0) { // three byte character (first byte: 1110xxxx)
- $width = 3;
- }
- elseif (($chr & 0xF8) == 0xF0) { // four byte character (first byte: 11110www)
- $width = 4;
- }
- else {
- watchdog('CAPTCHA', 'Encountered an illegal byte while splitting an utf8 string in characters.', array(), WATCHDOG_ERROR);
- return $characters;
- }
- }
- $characters[] = substr($str, $i, $width);
- $i += $width;
- }
- return $characters;
-}
-
-/**
- * Helper function for checking the setup of the Image CAPTCHA.
- *
- * The image CAPTCHA requires at least the GD PHP library.
- * Support for TTF is recommended and the enabled
- * font files should be readable.
- * This functions checks these things.
- *
- * @param $check_fonts whether or not the enabled fonts should be checked.
- *
- * @return status code: bitwise 'OR' of status flags like
- * IMAGE_CAPTCHA_ERROR_NO_GDLIB, IMAGE_CAPTCHA_ERROR_NO_TTF_SUPPORT,
- * IMAGE_CAPTCHA_ERROR_TTF_FILE_READ_PROBLEM.
- */
-function _image_captcha_check_setup($check_fonts=TRUE) {
- // Start clean.
- $status = 0;
- // Check if we can use the GD library.
- // We need at least the imagepng function (for font previews on the settings page).
- // Note that the imagejpg function is optionally also used, but not required.
- if (!function_exists('imagepng')) {
- $status = $status | IMAGE_CAPTCHA_ERROR_NO_GDLIB;
- }
- if (!function_exists('imagettftext')) {
- $status = $status | IMAGE_CAPTCHA_ERROR_NO_TTF_SUPPORT;
- }
- if ($check_fonts) {
- // Check availability of enabled fonts.
- $fonts = _image_captcha_get_enabled_fonts();
- list($readable_fonts, $problem_fonts) = _image_captcha_check_fonts($fonts);
- if (count($problem_fonts) != 0) {
- $status = $status | IMAGE_CAPTCHA_ERROR_TTF_FILE_READ_PROBLEM;
- }
- }
- return $status;
-}
-
-/**
- * Helper function for calculating image height and width
- * based on given code and current font/spacing settings.
- *
- * @return array($width, $heigh)
- */
-function _image_captcha_image_size($code) {
- // Get settings
- $font_size = (int) variable_get('image_captcha_font_size', 30);
- $character_spacing = (float) variable_get('image_captcha_character_spacing', '1.2');
- $characters = _image_captcha_utf8_split($code);
- $character_quantity = count($characters);
-
- // Calculate height and width
- $width = $character_spacing * $font_size * $character_quantity;
- $height = 2 * $font_size;
-
- return array($width, $height);
-}
-
-
-/**
- * Implements hook_captcha().
- */
-function image_captcha_captcha($op, $captcha_type='', $captcha_sid=NULL) {
- switch ($op) {
- case 'list':
- // Only offer the image CAPTCHA if it is possible to generate an image on this setup.
- if (!(_image_captcha_check_setup() & IMAGE_CAPTCHA_ERROR_NO_GDLIB)) {
- return array('Image');
- }
- else {
- return array();
- }
- break;
-
- case 'generate':
- if ($captcha_type == 'Image') {
- // In maintenance mode, the image CAPTCHA does not work because the request
- // for the image itself won't succeed (only ?q=user is permitted for
- // unauthenticated users). We fall back to the Math CAPTCHA in that case.
- global $user;
- if (variable_get('maintenance_mode', 0) && $user->uid == 0) {
- return captcha_captcha('generate', 'Math');
- }
- // generate a CAPTCHA code
- $allowed_chars = _image_captcha_utf8_split(variable_get('image_captcha_image_allowed_chars', IMAGE_CAPTCHA_ALLOWED_CHARACTERS));
- $code_length = (int)variable_get('image_captcha_code_length', 5);
- $code = '';
- for ($i = 0; $i < $code_length; $i++) {
- $code .= $allowed_chars[array_rand($allowed_chars)];
- }
-
- // build the result to return
- $result = array();
-
- $result['solution'] = $code;
- // Generate image source URL (add timestamp to avoid problems with
- // client side caching: subsequent images of the same CAPTCHA session
- // have the same URL, but should display a different code).
- $options = array(
- 'query' => array(
- 'sid' => $captcha_sid,
- 'ts' => REQUEST_TIME,
- ),
- );
- $img_src = check_url(url("image_captcha", $options));
- list($width, $height) = _image_captcha_image_size($code);
- // TODO: start using a theming funtion for generating the image markup?
- $result['form']['captcha_image'] = array(
- '#type' => 'markup',
- '#markup' => ' ',
- '#weight' => -2,
- );
- $result['form']['captcha_response'] = array(
- '#type' => 'textfield',
- '#title' => t('What code is in the image?'),
- '#description' => t('Enter the characters shown in the image.'),
- '#weight' => 0,
- '#required' => TRUE,
- '#size' => 15,
- );
-
- // Handle the case insensitive validation option combined with ignoring spaces.
- switch (variable_get('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE)) {
- case CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE:
- $result['captcha_validate'] = 'captcha_validate_ignore_spaces';
- break;
- case CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE:
- $result['captcha_validate'] = 'captcha_validate_case_insensitive_ignore_spaces';
- break;
- }
-
- return $result;
- }
- break;
-
- }
-}
diff --git a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.user.inc b/sites/all/modules/contrib/captcha/image_captcha/image_captcha.user.inc
deleted file mode 100644
index 07aeb84d..00000000
--- a/sites/all/modules/contrib/captcha/image_captcha/image_captcha.user.inc
+++ /dev/null
@@ -1,343 +0,0 @@
- $captcha_sid)
- )->fetchField();
-
- // Only generate captcha if code exists in the session.
- if ($code !== FALSE) {
- // generate the image
- $image = @_image_captcha_generate_image($code);
- // check of generation was successful
- if (!$image) {
- watchdog('CAPTCHA', 'Generation of image CAPTCHA failed. Check your image CAPTCHA configuration and especially the used font.', array(), WATCHDOG_ERROR);
- exit();
- }
- // Send the image resource as an image file to the client.
- $file_format = variable_get('image_captcha_file_format', IMAGE_CAPTCHA_FILE_FORMAT_JPG);
- if ($file_format == IMAGE_CAPTCHA_FILE_FORMAT_JPG) {
- drupal_add_http_header('Content-Type', 'image/jpeg');
- imagejpeg($image);
- }
- else {
- drupal_add_http_header('Content-Type', 'image/png');
- imagepng($image);
- }
- // Clean up the image resource.
- imagedestroy($image);
- }
- exit();
-}
-
-
-/**
- * Small helper function for parsing a hexadecimal color to a RGB tuple.
- */
-function _image_captcha_hex_to_rgb($hex) {
- // handle #RGB format
- if (strlen($hex) == 4) {
- $hex = $hex[1] . $hex[1] . $hex[2] . $hex[2] . $hex[3] . $hex[3];
- }
- $c = hexdec($hex);
- $rgb = array();
- for ($i = 16; $i >= 0; $i -= 8) {
- $rgb[] = ($c >> $i) & 0xFF;
- }
- return $rgb;
-}
-
-
-/**
- * Base function for generating a image CAPTCHA.
- */
-function _image_captcha_generate_image($code) {
- // Get font.
- $fonts = _image_captcha_get_enabled_fonts();
-
- // get other settings
- $font_size = (int) variable_get('image_captcha_font_size', 30);
- list($width, $height) = _image_captcha_image_size($code);
-
- // create image resource
- $image = imagecreatetruecolor($width, $height);
- if (!$image) {
- return FALSE;
- }
-
- // Get the background color and paint the background.
- $background_rgb = _image_captcha_hex_to_rgb(variable_get('image_captcha_background_color', '#ffffff'));
- $background_color = imagecolorallocate($image, $background_rgb[0], $background_rgb[1], $background_rgb[2]);
- // Set transparency if needed.
- $file_format = variable_get('image_captcha_file_format', IMAGE_CAPTCHA_FILE_FORMAT_JPG);
- if ($file_format == IMAGE_CAPTCHA_FILE_FORMAT_TRANSPARENT_PNG) {
- imagecolortransparent($image, $background_color);
- }
- imagefilledrectangle($image, 0, 0, $width, $height, $background_color);
-
- // Do we need to draw in RTL mode?
- global $language;
- $rtl = $language->direction && ((bool) variable_get('image_captcha_rtl_support', 0));
-
- // draw text
- $result = _image_captcha_image_generator_print_string($image, $width, $height, $fonts, $font_size, $code, $rtl);
- if (!$result) {
- return FALSE;
- }
-
- // add noise
- $noise_colors = array();
- for ($i = 0; $i < 20; $i++) {
- $noise_colors[] = imagecolorallocate($image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
- }
- // Add additional noise.
- if (variable_get('image_captcha_dot_noise', 0)) {
- _image_captcha_image_generator_add_dots($image, $width, $height, $noise_colors);
- }
- if (variable_get('image_captcha_line_noise', 0)) {
- _image_captcha_image_generator_add_lines($image, $width, $height, $noise_colors);
- }
-
- // Distort the image.
- $distortion_amplitude = .25 * $font_size * variable_get('image_captcha_distortion_amplitude', 0) / 10.0;
- if ($distortion_amplitude > 1) {
- // distortion parameters
- $wavelength_xr = (2+3*lcg_value())*$font_size;
- $wavelength_yr = (2+3*lcg_value())*$font_size;
- $freq_xr = 2 * 3.141592 / $wavelength_xr;
- $freq_yr = 2 * 3.141592 / $wavelength_yr;
- $wavelength_xt = (2+3*lcg_value())*$font_size;
- $wavelength_yt = (2+3*lcg_value())*$font_size;
- $freq_xt = 2 * 3.141592 / $wavelength_xt;
- $freq_yt = 2 * 3.141592 / $wavelength_yt;
-
- $distorted_image = imagecreatetruecolor($width, $height);
- if ($file_format == IMAGE_CAPTCHA_FILE_FORMAT_TRANSPARENT_PNG) {
- imagecolortransparent($distorted_image, $background_color);
- }
- if (!$distorted_image) {
- return FALSE;
- }
-
- if (variable_get('image_captcha_bilinear_interpolation', FALSE)) {
- // distortion with bilinear interpolation
- for ($x = 0; $x < $width; $x++) {
- for ($y = 0; $y < $height; $y++) {
- // get distorted sample point in source image
- $r = $distortion_amplitude * sin($x * $freq_xr + $y * $freq_yr);
- $theta = $x * $freq_xt + $y * $freq_yt;
- $sx = $x + $r * cos($theta);
- $sy = $y + $r * sin($theta);
- $sxf = (int)floor($sx);
- $syf = (int)floor($sy);
- if ($sxf < 0 || $syf < 0 || $sxf >= $width - 1 || $syf >= $height - 1) {
- $color = $background_color;
- }
- else {
- // bilinear interpolation: sample at four corners
- $color_00 = imagecolorat($image, $sxf , $syf );
- $color_00_r = ($color_00 >> 16) & 0xFF;
- $color_00_g = ($color_00 >> 8) & 0xFF;
- $color_00_b = $color_00 & 0xFF;
- $color_10 = imagecolorat($image, $sxf+1, $syf );
- $color_10_r = ($color_10 >> 16) & 0xFF;
- $color_10_g = ($color_10 >> 8) & 0xFF;
- $color_10_b = $color_10 & 0xFF;
- $color_01 = imagecolorat($image, $sxf , $syf+1);
- $color_01_r = ($color_01 >> 16) & 0xFF;
- $color_01_g = ($color_01 >> 8) & 0xFF;
- $color_01_b = $color_01 & 0xFF;
- $color_11 = imagecolorat($image, $sxf+1, $syf+1);
- $color_11_r = ($color_11 >> 16) & 0xFF;
- $color_11_g = ($color_11 >> 8) & 0xFF;
- $color_11_b = $color_11 & 0xFF;
- // interpolation factors
- $u = $sx - $sxf;
- $v = $sy - $syf;
- // interpolate
- $r = (int)((1-$v)*((1-$u)*$color_00_r + $u*$color_10_r) + $v*((1-$u)*$color_01_r + $u*$color_11_r));
- $g = (int)((1-$v)*((1-$u)*$color_00_g + $u*$color_10_g) + $v*((1-$u)*$color_01_g + $u*$color_11_g));
- $b = (int)((1-$v)*((1-$u)*$color_00_b + $u*$color_10_b) + $v*((1-$u)*$color_01_b + $u*$color_11_b));
- // build color
- $color = ($r<<16) + ($g<<8) + $b;
- }
- imagesetpixel($distorted_image, $x, $y, $color);
- }
- }
- }
- else {
- // distortion with nearest neighbor interpolation
- for ($x = 0; $x < $width; $x++) {
- for ($y = 0; $y < $height; $y++) {
- // get distorted sample point in source image
- $r = $distortion_amplitude * sin($x * $freq_xr + $y * $freq_yr);
- $theta = $x * $freq_xt + $y * $freq_yt;
- $sx = $x + $r * cos($theta);
- $sy = $y + $r * sin($theta);
- $sxf = (int)floor($sx);
- $syf = (int)floor($sy);
- if ($sxf < 0 || $syf < 0 || $sxf >= $width - 1 || $syf >= $height - 1) {
- $color = $background_color;
- }
- else {
- $color = imagecolorat($image, $sxf, $syf);
- }
- imagesetpixel($distorted_image, $x, $y, $color);
- }
- }
- }
- // release undistorted image
- imagedestroy($image);
- // return distorted image
- return $distorted_image;
- }
- else {
- return $image;
- }
-}
-
-function _image_captcha_image_generator_add_lines(&$image, $width, $height, $colors) {
- $line_quantity = $width * $height/200.0 * ((int) variable_get('image_captcha_noise_level', 5)) / 10.0;
- for ($i = 0; $i < $line_quantity; $i++) {
- imageline($image, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $colors[array_rand($colors)]);
- }
-}
-
-function _image_captcha_image_generator_add_dots(&$image, $width, $height, $colors) {
- $noise_quantity = $width * $height * ((int) variable_get('image_captcha_noise_level', 5)) / 10.0;
- for ($i = 0; $i < $noise_quantity; $i++ ) {
- imagesetpixel($image, mt_rand(0, $width), mt_rand(0, $height), $colors[array_rand($colors)]);
- }
-}
-
-/**
- * Helper function for drawing text on the image.
- */
-function _image_captcha_image_generator_print_string(&$image, $width, $height, $fonts, $font_size, $text, $rtl=FALSE) {
- // get characters
- $characters = _image_captcha_utf8_split($text);
- $character_quantity = count($characters);
-
- // get colors
- $background_rgb = _image_captcha_hex_to_rgb(variable_get('image_captcha_background_color', '#ffffff'));
- $foreground_rgb = _image_captcha_hex_to_rgb(variable_get('image_captcha_foreground_color', '#000000'));
- $background_color = imagecolorallocate($image, $background_rgb[0], $background_rgb[1], $background_rgb[2]);
- $foreground_color = imagecolorallocate($image, $foreground_rgb[0], $foreground_rgb[1], $foreground_rgb[2]);
- // precalculate the value ranges for color randomness
- $foreground_randomness = (int)(variable_get('image_captcha_foreground_color_randomness', 100));
- if ($foreground_randomness) {
- $foreground_color_range = array();
- for ($i=0; $i<3; $i++) {
- $foreground_color_range[$i] = array(max(0, $foreground_rgb[$i] - $foreground_randomness), min(255, $foreground_rgb[$i] + $foreground_randomness));
- }
- }
-
- // set default text color
- $color = $foreground_color;
-
- // the image is seperated in different character cages, one for each character
- // each character will be somewhere inside that cage
- $ccage_width = $width / $character_quantity;
- $ccage_height = $height;
-
- foreach ($characters as $c => $character) {
- // initial position of character: in the center of its cage
- $center_x = ($c + 0.5) * $ccage_width;
- if ($rtl) {
- $center_x = $width - $center_x;
- }
- $center_y = 0.5 * $height;
-
- // Pick a random font from the list.
- $font = $fonts[array_rand($fonts)];
-
- // Get character dimensions for TrueType fonts.
- if ($font != 'BUILTIN') {
- $bbox = imagettfbbox($font_size, 0, drupal_realpath($font), $character);
- // In very rare cases with some versions of the GD library, the x-value
- // of the left side of the bounding box as returned by the first call of
- // imagettfbbox is corrupt (value -2147483648 = 0x80000000).
- // The weird thing is that calling the function a second time
- // can be used as workaround.
- // This issue is discussed at http://drupal.org/node/349218.
- if ($bbox[2] < 0) {
- $bbox = imagettfbbox($font_size, 0, drupal_realpath($font), $character);
- }
- }
- else {
- $character_width = imagefontwidth(5);
- $character_height = imagefontheight(5);
- $bbox = array(0, $character_height, $character_width, $character_height, $character_width, 0, 0, 0);
- }
-
- // Random (but small) rotation of the character.
- // TODO: add a setting for this?
- $angle = mt_rand(-10, 10);
-
- // Determine print position: at what coordinate should the character be
- // printed so that the bounding box would be nicely centered in the cage?
- $bb_center_x = .5 * ($bbox[0] + $bbox[2]);
- $bb_center_y = .5 * ($bbox[1] + $bbox[7]);
- $angle_cos = cos($angle*3.1415/180);
- $angle_sin = sin($angle*3.1415/180);
- $pos_x = $center_x - ($angle_cos * $bb_center_x + $angle_sin * $bb_center_y);
- $pos_y = $center_y - (-$angle_sin * $bb_center_x + $angle_cos * $bb_center_y);
-
- // Calculate available room to jitter: how much can the character be moved
- // so that it stays inside its cage?
- $bb_width = $bbox[2] - $bbox[0];
- $bb_height = $bbox[1] - $bbox[7];
- $dev_x = .5 * max(0, $ccage_width - abs($angle_cos) * $bb_width - abs($angle_sin) * $bb_height);
- $dev_y = .5 * max(0, $ccage_height - abs($angle_cos) * $bb_height - abs($angle_sin) * $bb_width);
-
- // add jitter to position
- $pos_x = $pos_x + mt_rand(-$dev_x, $dev_x);
- $pos_y = $pos_y + mt_rand(-$dev_y, $dev_y);
-
- // calculate text color in case of randomness
- if ($foreground_randomness) {
- $color = imagecolorallocate($image,
- mt_rand($foreground_color_range[0][0], $foreground_color_range[0][1]),
- mt_rand($foreground_color_range[1][0], $foreground_color_range[1][1]),
- mt_rand($foreground_color_range[2][0], $foreground_color_range[2][1])
- );
- }
-
- // draw character
- if ($font == 'BUILTIN') {
- imagestring($image, 5, $pos_x, $pos_y, $character, $color);
- }
- else {
- imagettftext($image, $font_size, $angle, $pos_x, $pos_y, $color, drupal_realpath($font), $character);
- }
-
- // For debugging purposes: draw character bounding box (only valid when rotation is disabled).
- // imagerectangle($image, $pos_x + $bbox[0], $pos_y + $bbox[1], $pos_x + $bbox[2], $pos_y + $bbox[7], $color);
-
- }
-
- // return a sign of success
- return TRUE;
-}
diff --git a/sites/all/modules/contrib/ckeditor/CHANGELOG.txt b/sites/all/modules/contrib/ckeditor/CHANGELOG.txt
deleted file mode 100644
index d47e6ea4..00000000
--- a/sites/all/modules/contrib/ckeditor/CHANGELOG.txt
+++ /dev/null
@@ -1,465 +0,0 @@
-2013-04-12
-New stable release 7.x-1.13
-
-Bug fixes:
-
-[#1063482] by nod_, wwalc, roderik, helior, hadsie: Use Libraries API for CKEditor
-[#1898294] by kscheirer: Fatal error if Libraries module is enabled after CKEditor
-[#1961596] by jcisio: Added 'feature_source()' option so that ckeditor_profile() component is visible in drush.
-[#1356026] by Volx, hctom: Fixed Profile loses text formats when exported into a feature using Drush.
-[#1895278] by wwalc WYSIWYG editor should allow Drupal to trigger 'formUpdated' event
-[#1957066] by rudiedirkx: Use field_extra_fields to be able to position the "Rich text editor settings" fieldset
-[#1959754] by wwalc: CKFinder is not installed correctly - improve information in the status report
-[#1810910] by mokaspar, jcisio, DeFr: Fixed Comments gets filtered out by ckeditor_filter_xss().
-[#1909318] by Simon Georges: Useless file inclusion in ckeditor.info.
-[#1603014] by anou, SebCorbin: Corrected strings used in Security section.
-[#1889010] by michal_cksource: Problem with CKFinder files upload when private download method is used
-[#1885950] by michal_cksource: Fix HTML validation for iframe in profile configuration
-[#1885938] by michal_cksource: Disable div based editor on default
-[#1872064] by dczepierga: Undefined index: loadPlugins in ckeditor_modules_disabled() and ckeditor_modules_uninstalled()
-
-2012-12-22
-New stable release 7.x-1.12
-
-Bug fixes:
-[#1871918] by matulis: Bug in checking if a file "contents.css" exists
-[#1870270] by dczepierga: Disable plugins which not exists and are stored in ckeditor profiles
-[#1864760] by dczepierga: Wrong path to plugins stored in database
-[#1868416] by dczepierga: Move skin selection option to CKEditor Global Profile
-[#1866654] by dczepierga: Remove "Skin" and "Toolbar state on startup" options from user profile
-[#1865086] by dczepierga: Set default theme if selected not exists
-
-2012-12-12
-New stable release 7.x-1.11
-
-New features:
-[#1858840] by dczepierga: Add option to enable/disable aggregate ckeditor.js script
-[#1847662] by dczepierga: Add support for CKEditor v4
-[#1577518] by dczepierga: Remove unused/unsupported hook_user from code
-[#1559700] by dczepierga: Disable HTML Entities conversion by default
-[#1692666] by dczepierga: Unset Ckeditor-Plugin upon module disabling/uninstalling
-
-Bug fixes:
-[#1760506] by ceng: CKEditor features are not reverted or applied from the command line
-[#1857910] by dczepierga: Using extraPlugins config option in Custom JavaScript (Advanced options) not working
-[#1850626] by dczepierga: Wrong path to external plugins loaded by hook
-[#1844390] by dczepierga: Undefined index: loadPlugins in ckeditor_modules_enabled()
-[#1790082] by dczepierga: Order of filters calling in ckeditor filter XSS function
-[#1728318] by dczepierga: Text format filters are not properly given $format; cannot look up their per-format settings
-[#1698600] by azovsky: Undefined index: format in ckeditor_pre_render_text_format()
-[#1651130] by lmeurs: Wrong variable substitution using t()
-[#1637416] by michal_cksource: Fix description to "Custom JavaScript configuration" option
-[#1595606] by kmcnamee: Wrong instructions for configuring CKFinder
-[#1350998] by MegaChriz: CKEditor settings appear on all user profile edit pages
-[#1567022] by dczepierga: Overlays of administration toolbar appears in CKEditor maximized mode
-[#1557526] by dczepierga: CKEditor gets inserted multiple times on text format selection
-[#1554840] by dczepierga: Missing argument - WYSIWYG Filter, HTML Purifier & HTMLawed
-
-2012-04-18
-New stable release 7.x-1.9
-
-New features:
-[#1489358] by dczepierga: Add support for the Stylesheet Parser plugin
-[#1483402] by dczepierga: Change security filters policy
-[#1489074] by acbramley: Change CKEditor XSS URL to be passed through url()
-[#1473010] by michal_cksource: Set spellchecker to use the interface language
-
-Bug fixes:
-[#1537824] by dczepierga: External plugins do not work when the ckeditor_basic.js loading method is used
-[#1507852] by dczepierga: 'drush ckeditor-download' fails if SVN is not installed
-[#1432068] by kruser: Fix path to the sites/all/libraries/ckeditor/ckeditor.styles.js file
-[#1504398] by ndeschildre: Importing CKEditor profile features fails, manual revert is needed
-[#1508342] by dczepierga: WSOD on saving content from CKEditor using Ajax when the node edit form is embedded in the display of another node
-[#1491210] by michal_cksource: CKEditor gets disabled/enabled on all AJAX calls
-[#1512196] by dczepierga: Refactor code with titles and descriptions now available for translation
-[#1496164] by michal_cksource: Buttons are too high when using the drag & drop feature in Firefox
-[#1492344] by dczepierga: Portuguese language missing
-
-2012-03-15
-New stable release 7.x-1.8
-
-Bug fixes:
-[#1371660] by dczepierga: CKFinder requirement check needs fixing
-
-2012-03-14
-New stable release 7.x-1.7
-
-New features:
-[#1338044] by dczepierga: Add an option to disable the toolbar wizard
-[#1349330] by dczepierga: Add a configuration option to set the CKFinder library path
-
-Bug fixes:
-[#1345738] by michal_cksource: Included JavaScript files for the toolbar drag & drop wizard should be minified
-[#1361846] by mrsimonelliott: CKEditor does not load on a 'Long Text' CCK field
-[#1371660] by dczepierga: CKFinder requirement check needs fixing
-[#1043230] by KoCo: D7 administration toolbar overlays CKEditor in maximized mode
-[#1357794] by dczepierga: Invalid attribute "disc-type" in ckeditor.css
-[#1324990] by michal_cksource: Problems with access to private files (download)
-[#1343310] by michal_cksource: Change settings for private download
-[#1351470] by dczepierga: CKEditor plugins added with the "hook_ckeditor_plugin" button do not appear in the toolbar
-[#1329980] by jherencia: Problem with CKEditor module update
-[#1347682] by jherencia: D6 to D7 - error in update #7003 when running update.php
-[#1350382] by michal_cksource: Improve regex pattern to find plugins for CKEditor
-[#1349304] by michal_cksource: Change descriptions in CKEditor help page
-[#1343310] by michal_cksource: Change settings for private download
-[#1348196] by michal_cksource: Change of the default path for CKFinder settings
-[#1346818] by michal_cksource: Change of Full toolbar buttons
-[#1345658] by michal_cksource: Enable the Drupal Breaks plugin by default
-
-2011-11-10
-New stable relase 7.x-1.6
-
-Bug fixes:
-[#1337064] by michal_cksource: Fix Fatal error: Call to undefined function db_fetch_object()
-
-2011-11-09
-New stable relase 7.x-1.5
-
-Bug fixes:
-[#1334140] by michal_cksource: CKEditor is cut off in comments form
-[#1331728] by michal_cksource: Remove unnecessary Drupal Page Break button if there is no module to support this feature
-[#1331720] by michal_cksource: Fix broken link to Global Profile in CKEditor configuration main page
-[#1331716] by michal_cksource: Fix missing version number in report status
-[#1324554] by dczepierga: Fix adding custom plugin - change in ckeditor.api.php
-[#1283918] by michal_cksource: Fix UTF-8 issues
-[#1327540] by michal_cksource: Fix hook_file_download allows downloading of private files created by another module
-[#1325412] by michal_cksource: Fix problem with list-style-type in ckeditor.css
-
-
-2011-10-26
-New stable release 7.x-1.4
-
--- 2011-10-24
-- [#1319658] by michal_cksource: Correct language list in the CKEditor profile configuration
-
--- 2011-10-20
-- [#1259510] by michal_cksource: Fix for setting a private files folder breaks CKEditor file uploads
-
--- 2011-10-17
-- [#1310280] by dczepierga: Improve icons detection from CKEditor plugins (part 2)
-- [#1298972] by michal_cksource: Correct messages and add language fixes
-- [#1311928] by dczepierga: Add jquery_ui support to the Drag & Drop toolbar configuration
-
--- 2011-10-14
-- [#1310280] by dczepierga: Improve icons detection from CKEditor plugins
-- [#1295176] by dczepierga: Fix Notice: Undefined index: default in ckeditor_admin_profile_form() - when editing CKEditor profile
-- [#1310198] by duozersk: Add plugin to count symbols and words inside CKEditor
-
--- 2011-10-04
-- [#1298972] by michal_cksource: Correct messages and add language fixes
-
--- 2011-09-26
-- [#1154264] by dczepierga: Fix for deleting profle - after deleting the Advanced profile, Full HTML profile doesn't load
-
--- 2011-09-23
-- [#1288084] by dczepierga: Disable Media and IMCE module selection if these modules are not installed
-
--- 2011-09-20
-- [#1283788] by dczepierga: Fix Notice: Undefined index: buttons in ckeditor_toolbar_buttons_all()
-
--- 2011-09-19
-- [#1219348] by dczepierga: Fix for WYSIWYG filter - add missing argument
-
--- 2011-09-15
-- [#1280298] by dczepierga: Add configuration option to disable text format filters in filter/xss request
-- [#1270792] by dczepierga: Further improvements to the Drag & Drop toolbar configuration
-
--- 2011-09-13
-- [#1173294] by dczepierga: Fix for incorrect file path for uploaded Images
-
--- 2011-09-12
-- [#1270792] by michal_cksource: Improved Drag & Drop toolbar configuration - fixed css styles
-- [#1270792] by michal_cksource: Improved Drag & Drop toolbar configuration - fixed errors (dragged item was to low in Firefox and validation failed when 'group' button was first in buttons row)
-
--- 2011-09-06
-- [#1270792] by dczepierga: Add Drag & Drop toolbar configuration
-
--- 2011-08-31
-- [#1264884] by dczepierga: Fix warning: is_dir(): open_basedir restriction in effect
-
------------------------------
- 2011-08-29
- Released CKEditor 7.x-1.3
------------------------------
-
--- 2011-08-29
-- [#1260892] by dczepierga: Add regex to work with new CKEditor toolbar format (toolbar groups compatible with WAI-ARIA)
-- [#1258326] by dczepierga: Add configuration option for setting CKEditor plugins directory
-
--- 2011-08-25
-- [#1257308] by dczepierga: Add loading sample toolbar to profile configuration
-- [#1192622] by dczepierga: Replace static paths to plugins in the database with dynamic paths
-
--- 2011-08-16
-- [#1250496] by dczepierga: 'CKEDITOR' is not defined - problem with ckeditor.styles.js
-
--- 2011-08-11
-- [#1231130] by dczepierga: The "Use theme style" setting now always uses the "seven" theme (admin menu theme)
-
--- 2011-08-10
-- [#1245306] by dczepierga: "Custom JavaScript configuration" field description is wrong
-
--- 2011-08-08
-- [#1231338] by dczepierga: Features module support for Drupal 7 (exporting profiles)
-
--- 2011-08-02
-- [#1235142] by madmanmax: README.TXT - Installing CKFinder - wrong permission name
-
--- 2011-07-12
-- [#1216104] by dczepierga: Bug in custom JavaScript configuration - semicolon problem
-- [#1215032] by dczepierga: Bad location of the configuration file in the description of CKEditor profile
-
--- 2011-07-04
-- [#1190278] by dczepierga: CKEditor does not work with the Insert module
-
--- 2011-06-28
-- [#1198068] by michal_cksource: Confusing behavior with IMCE button implementation
-
--- 2011-06-27
-- [#1201180] by dczepierga: SCAYT spelling language does not match node language
-
--- 2011-06-22
-- [#1196166] by dczepierga: Bug in custom JavaScript configuration - editor not showing in some cases
-
--- 2011-06-17
-- [#1032120] by dczepierga: Formatting is lost when editing a node
-
--- 2011-06-14
-- [#1187808] by RolandK: Not formatting text between code tags
-
--- 2011-06-13
-- [#1186880] by dczepierga: Handling arrays in the "Custom JavaScript configuration"
-
--- 2011-06-09
-- [#1183218] by neclimdul: Fix broken teasers for long paragraphs
-
--- 2011-06-06
-- [#1179880] by dczepierga: Add hook to register a plugin
-- [#1063646] by dczepierga: Fix calling Undefined index: "loadPlugins" in ckeditor_admin_values_to_settings()
-
--- 2011-06-02
-- [#1176212] by dczepierga: Remove not supported linktomenu and linktonode plugins
-- [#1176208] by dczepierga: Add plugins management in profile settings
-
------------------------------
- 2011-05-30
- Released CKEditor 7.x-1.2
------------------------------
-
--- 2011-05-27
-- [#1170612] by dczepierga: Add support for autogrow and tableresize plugin
-
--- 2011-05-26
-- [#1169402] by dczepierga: Fix duplicated path in the error message displayed when CKEditor is not installed correctly
-
--- 2011-05-23
-- [#1165864] by dczepierga: Improve manual selection of the user interface color
-- [#1093038] by marhak: CKEDITOR is not defined when using ckeditor_basic.js - Editor is not loading
-- [#1039810] by cwc: Fix to predefined styles path errors (fix typo)
-- [#1164270] by TommyChris: Fix to work with ckeditor_link module (http://drupal.org/project/ckeditor_link)
-
--- 2011-05-16
-- [#1158898] by dczepierga: Add Google PageSpeed and Drupal JS/CSS aggregation support
-
--- 2011-05-09
-- [#1134252] by dczepierga: Add HTML Entities configurable option in each profile
-
--- 2011-05-04
-- [#1022986] by dczepierga: Add integration with Media Module
-
--- 2011-05-02
-- [#1142600] by taite11: Readme file edit - there is no core upload module in Drupal 7
-
--- 2011-04-28
-- [#1022986] by dczepierga: Add integration with Media Module (http://drupal.org/project/media)
-
--- 2011-04-11
-- [#1116516] by weboide: Fix to CKEditor and Profile2 - remove call to undefined function ckeditor_user_customize_form_validate() on uid=1
-
--- 2011-04-07
-- [#1093028] by marhak: Text written in rich text editor (WYSIWYG) mode disappears when switching to plain text editor mode
-- [#1102824] by dczepierga: CKEditor loses all text when uploading an image or file via field API
-
--- 2011-03-31
-- [#1093038] by marhak: CKEDITOR is not defined when using ckeditor_basic.js - Editor is not loading
-
--- 2011-03-30
-- [#1109366] by dczepierga: #1052604 Fix remove call to undefined function ckeditor_user_customize_form_validate
-
--- 2011-03-29
-- [#1107882] by dczepierga: Add a warning message when the wysiwyg module is enabled in Drupal 7
-
--- 2011-03-28
-- [#1107882] by dczepierga: Add a warning message when the wysiwyg module is enabled in Drupal 7
-
--- 2011-03-23
-- [#1039810] by cwc: Fix to predefined styles path errors
-
--- 2011-03-17
-- [#1095954] by dczepierga: Fix to prevent calling "Toggle rich text link" multiple times
-
------------------------------
- 2011-03-10
- Released CKEditor 7.x-1.1
------------------------------
-
--- 2011-02-22
-- [#960576] by dczepierga: Add loading ckeditor.css from theme.
-- [#1069012] by dczepierga: CKEditor version could not be determined
-
--- 2011-02-21
-- [#1068186] by dczepierga: Added support for CKEditor SWF (http://drupal.org/project/ckeditor_swf) and CKEditor Link (http://drupal.org/project/ckeditor_link) modules
-
--- 2011-02-17
-- [#1064422] by dczepierga: All changes to the text are lost when input format is changed
-
--- 2011-02-14
-- [#1053222] by dczepierga: Two editors appeared when JavaScript Aggregation was enabled
-- [#1037390] by dczepierga: Cannot use CKEditor module to create header/footer in Views
-- [#1052604] by dczepierga: Call to undefined function ckeditor_user_customize_form_validate
-
--- 2011-02-11
-- [#1056068] by dczepierga: Fix Warning: file_get_contents(/drupal7/sites/all/libraries/ckeditor/ckeditor.js)
-
--- 2011-02-08
-- [#1054414] by dczepierga: Added support for elFinder (http://drupal.org/project/elfinder) file manager
-- [#1054606] by dczepierga: No detach method in Drupal.behaviors.ckeditor
-
--- 2011-02-07
-- [#1037390] by dczepierga: Cannot use CKEditor module to create header/footer in Views
-- [#1053358] by dczepierga: Removed option to "Use CKEditor in a popup window" in "My account" settings
-
--- 2011-02-04
-- [#1050034] by dczepierga: Disabled editor gets enabled again after ajax calls
-
--- 2011-02-03
-- [#1037390] by dczepierga: Cannot use CKEditor module to create header/footer in Views
-
--- 2011-02-01
-- [#1037390] by dczepierga: Cannot use CKEditor module to create header/footer in Views
-
--- 2011-01-24
-- [#1035544] by dczepierga: Remove double http:// in ckeditor.drush.inc
-
--- 2011-01-20
-- [#1006770] by OnkelTem: Fix Notice: Undefined index: filtered_html in ckeditor_profile_load()
-
------------------------------
- 2011-01-13
- Released CKEditor 7.x-1.0
------------------------------
-
--- 2011-01-13
-- Added Upgrade.txt
-- Fixed filters description (HTML should be allowed there)
-- Link to CKEditor Global Profile was not displayed properly.
-- [#1025472] by dczepierga: Starting slash in editor path result in Warnings
-- [#1022562] by dczepierga: In IE8 break button icon doesn't appear
-- [#1023546] by dczepierga: Useless ajax call when no security filters are checked
-
--- 2011-01-11
-- [#1022666] by dczepierga: Teaser break doesn't work with filtered html input format.
-- [#1022494] by dczepierga: CKEditor module - Compatibility with Drupal's coding standards
-
--- 2011-01-10
-- [#1011112] by Oren_Held: Support RTL also when CSS is not in theme mode (self/none)
-- [#1020612] by amateescu: Extra table borders added by the Seven theme
-- [#1003462] by dczepierga: CKfinder path customization won't work
-- [#1020820] by dczepierga: CKEditor does not work after enabling javascript aggregation
-- [#1006230] by amateescu: Editor not loading for Full HTML
-
--- 2011-01-05
-- [#1006770] by dczepierga: Notice: Undefined index: filtered_html in ckeditor_profile_load()
-
--- 2010-12-29
-- [#1009816] by dczepierga: Access denied: ckeditor/xss
-- [#1004822] by dczepierga: Switching text format to filtered html deletes all "p" tags
-
--- 2010-12-28
-- [#1006124] by dczepierga: Registered user gets "Undefined index: popup" message
-- [#1000330] by dczepierga: No Insert File button in IMCE
-
--- 2010-12-20
-- [#1000838] by dczepierga: The Teaser button is absolutely necessary - important functionality has been deleted
-
------------------------------
- 2010-12-15
- Released CKEditor 7.x-1.0 RC
------------------------------
-
--- 2010-12-15
-- [#991380] by dczepierga: Language files (D7)
-- Removed a link to delete the global profile
-- [#999292] by dczepierga: Remove filter_html as default option in Full HTML text format (D7)
-- Fixed a typo
-- Updated comments, minor corrections
-
--- 2010-12-14
-- [#997136] by dczepierga: CKFinder - thumbnails not available
-- [#997124] by dczepierga: Invalid error message when CKFinder is enabled but not configured properly.
-- [#997116] by dczepierga: D7 Custom formatting options not used
-- [#997090] by dczepierga: XSS protection not working as expected
-- [#997098] by dczepierga: Error when CKEditor (the editor) is not present in the ckeditor folder
-
--- 2010-12-13
-- [#997074] by dczepierga: Corect the default order of Bidi buttons
-
--- 2010-12-10
-- [#994372] by dczepierga: Update README.TXT (D7)
-
--- 2010-12-09
-- [#993436] by dczepierga: Disable option of using CKEditor in a popup window (D7)
-- [#993362] by dczepierga: CKEditor not work in popup window (D7)
-- [#993330] by dczepierga: Change editor theme in profile edit form (D7)
-- [#993272] by dczepierga: User Interface color change enabled only for Kama skin
-
--- 2010-12-07
-- [#991380] by dczepierga: Language files (D7)
-- [#984986] by dczepierga: Code syntax after Coder module validation
-- [#984978] by dczepierga: Security filters not works (D7) - Security mode fix
-- [#984968] by dczepierga: Make sure that the help information is correct (D7)
-
--- 2010-12-06
-- [#990368] by dczepierga: Cleanup code - modules not ported to Drupal 7
-- [#985006] by dczepierga: Review README.txt (D7)
-
--- 2010-12-04
-- [#984978] by dczepierga: Security filters not works (D7)
-
--- 2010-12-03
-- [#984976] by dczepierga: User Interface color not saved in D7
-- [#985002] by dczepierga: Remove DrupalPageBreak button from toolbar
-
--- 2010-11-30
-- [#984986] by dczepierga: Code syntax after Coder module validation
-- Removed extra information that should be added by the packaging script
-
--- 2010-11-29
-- [#984202] by dczepierga: Detecting of summary field in form
-- [#966490] by dczepierga: Comment form after ckeditor install.
-- [#966492] by dczepierga: CKEditor in edit summary/teaser mode
-- [#984096] by dczepierga: Compatibility of DrupalBreaks Plugin
-- [#984000] by dczepierga: CKeditor not works in node edit
-
--- 2010-11-25
-- [#981624] by dczepierga: Compatibility with drupal 7.0-beta3
-- [#966488] by dczepierga: CKEditor should respect input format changes
-
--- 2010-11-23
-- [#976968] by dczepierga: Toolbar config validation in profile
-
--- 2010-11-19
-- [#901502] by dczepierga: Multi toolbar configuration, and different settings for each
-- [#975360] by dczepierga: Remove Minimum rows
-- [#975456] by dczepierga: Remove visibility settings in Global profile in D7
-- [#975458] by dczepierga: Selecting UI Color not working
-
--- 2010-11-09
-- [#966598] by dczepierga: CKFinder compatibility
-
--- 2010-11-08
-- [#965280] by dczepierga: Profiles after save lose all input formats
-- [#965258] by dczepierga: Compatibility with drupal 7.0-beta2
-
--- 2010-10-26
-- Created initial dev version of the CKEditor module for Drupal 7.x
diff --git a/sites/all/modules/contrib/ckeditor/LICENSE.txt b/sites/all/modules/contrib/ckeditor/LICENSE.txt
deleted file mode 100644
index d159169d..00000000
--- a/sites/all/modules/contrib/ckeditor/LICENSE.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/sites/all/modules/contrib/ckeditor/README.txt b/sites/all/modules/contrib/ckeditor/README.txt
deleted file mode 100644
index 5ab2b7b2..00000000
--- a/sites/all/modules/contrib/ckeditor/README.txt
+++ /dev/null
@@ -1,359 +0,0 @@
-TABLE OF CONTENTS
------------------
- * Overview
- * More Information and License
- * Requirements
- * Installation Paths
- * Installation / Configuration
- * Installation Troubleshooting
- * Uploading Images and Files
- * Installing CKFinder
- * Managing Plugins
- * Installing Additional Plugins
- * Integrating a Plugin with the CKEditor Module (for Plugin Developers)
- * Setting up Security Filters
- * HTML Filters and Inline Styling
- * Integrating a Custom Security Filter with the CKEditor Module (for Developers)
- * Upgrading Instructions
- * Help & Contribution
- * Credits
-
-Overview
---------
-This module allows Drupal to replace textarea fields with CKEditor.
-CKEditor is an online rich text editor that can be embedded inside web pages.
-It is a WYSIWYG (What You See Is What You Get) editor which means that the
-text edited in it looks as similar as possible to the results end users will
-see after the document gets published. It brings to the Web popular editing
-features found in desktop word processors such as Microsoft Word and
-OpenOffice.org Writer. CKEditor is truly lightweight and does not require any
-kind of installation on the client computer.
-
-More Information and License
-----------------------------
-CKEditor - The text editor for the Internet
-Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
-
-Licensed under the terms of the GNU Lesser General Public License:
- http://www.opensource.org/licenses/lgpl-license.php
-
-For further information visit:
- http://ckeditor.com/
-
-Requirements
-------------
- - Drupal 7.x,
- - PHP 5.2 or greater,
- - CKEditor 3.4 or greater.
- You will need to download CKEditor from the official download site: http://ckeditor.com/download.
- It is recommended to always use the latest CKEditor version available.
-
-Installation Paths
-------------------
-It is recommended to install the CKEditor for Drupal module in the "sites/all/modules" directory.
-
-When adding the files for standalone CKEditor and CKFinder, you can use one of the following directories:
-- "sites/all/modules/ckeditor/"
-- "sites/all/libraries/"
-and create a "ckeditor" or "ckfinder" directory inside.
-
-The CKEditor module will automatically recognize the proper path to the editor and the file browser.
-
-All installation and configuration instructions in this README file assume that you use the first option and place the CKEditor and CKFinder files in the "sites/all/modules/ckeditor/" directory. If you want to use the "sites/all/libraries/" directory, you will need to adjust the paths given in the instructions accordingly.
-
-Installation / Configuration
-----------------------------
-Note: these instructions assume that you install the CKEditor for Drupal module in the
- "sites/all/modules" directory (recommended).
-
- 1. Unzip the module files to the "sites/all/modules" directory. It should now
- contain a "ckeditor" directory.
- 2. Download standalone CKEditor from http://ckeditor.com/download. Unzip the
- contents of the "ckeditor" directory from the installation package to the
- "sites/all/modules/ckeditor/ckeditor" (or "sites/all/libraries/ckeditor") directory.
- Note: you can skip uploading the "_samples" and "_source" folders.
- 3. Enable the module in the "Administration panel > Modules > User Interface" section.
- 4. Grant permissions for using CKEditor in the
- "Administration panel > People > Permissions" section.
- Note: In order to enable the file browser, refer to the
- "Installing CKFinder" section.
- 5. Adjust CKEditor profiles in the
- "Administration panel > Configuration > Content Authoring > CKEditor" section.
- Profiles determine which options are available to users based on the input format system.
- 6. For the Rich Text Editing to work you also need to configure your filters
- for the users that may access Rich Text Editing.
- Either grant those users Full HTML access or use the following tags:
-