diff --git a/modules/poll/poll.module b/modules/poll/poll.module index f118b08e249..68c4627bde3 100644 --- a/modules/poll/poll.module +++ b/modules/poll/poll.module @@ -478,17 +478,17 @@ function poll_load($nodes) { $poll->allowvotes = FALSE; if (user_access('vote on polls') && $poll->active) { if ($user->uid) { - $result = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetchObject(); + $poll->vote = db_query('SELECT chid FROM {poll_vote} WHERE nid = :nid AND uid = :uid', array(':nid' => $node->nid, ':uid' => $user->uid))->fetchField(); + if (empty($poll->vote)) { + $poll->vote = -1; + $poll->allowvotes = TRUE; + } + } + elseif (!empty($_SESSION['poll_vote'][$node->nid])) { + $poll->vote = $_SESSION['poll_vote'][$node->nid]; } else { - $result = db_query("SELECT chid FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetchObject(); - } - if ($result) { - $poll->vote = $result->chid; - } - else { - $poll->vote = -1; - $poll->allowvotes = TRUE; + $poll->allowvotes = !db_query("SELECT 1 FROM {poll_vote} WHERE nid = :nid AND hostname = :hostname", array(':nid' => $node->nid, ':hostname' => ip_address()))->fetchField(); } } foreach ($poll as $key => $value) { @@ -730,6 +730,16 @@ function poll_vote($form, &$form_state) { ->execute(); cache_clear_all(); + + if (!$user->uid) { + // The vote is recorded so the user gets the result view instead of the + // voting form when viewing the poll. Saving a value in $_SESSION has the + // convenient side effect of preventing the user from hitting the page + // cache. When anonymous voting is allowed, the page cache should only + // contain the voting form, not the results. + $_SESSION['poll_vote'][$node->nid] = $choice; + } + drupal_set_message(t('Your vote was recorded.')); // Return the user to whatever page they voted from. @@ -911,6 +921,8 @@ function poll_cancel($form, &$form_state) { ->condition('chid', $node->vote) ->execute(); + unset($_SESSION['poll_vote'][$node->nid]); + drupal_set_message(t('Your vote was cancelled.')); } diff --git a/modules/poll/poll.test b/modules/poll/poll.test index 35d5ed49e6c..365a1861d96 100644 --- a/modules/poll/poll.test +++ b/modules/poll/poll.test @@ -370,8 +370,13 @@ class PollVoteCheckHostname extends PollTestCase { user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array( 'access content' => TRUE, 'vote on polls' => TRUE, + 'cancel own vote' => TRUE, )); + // Enable page cache to verify that the result page is not saved in the + // cache when anonymous voting is allowed. + variable_set('cache', CACHE_NORMAL); + // Create poll. $title = $this->randomName(); $choices = $this->_generateChoices(3); @@ -380,7 +385,7 @@ class PollVoteCheckHostname extends PollTestCase { $this->drupalLogout(); // Create web users. - $this->web_user1 = $this->drupalCreateUser(array('access content', 'vote on polls')); + $this->web_user1 = $this->drupalCreateUser(array('access content', 'vote on polls', 'cancel own vote')); $this->web_user2 = $this->drupalCreateUser(array('access content', 'vote on polls')); } @@ -405,19 +410,32 @@ class PollVoteCheckHostname extends PollTestCase { $this->drupalGet('node/' . $this->poll_nid); $elements = $this->xpath('//input[@value="Vote"]'); $this->assertTrue(empty($elements), t("%user is not able to vote again.", array('%user' => $this->web_user1->name))); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); // Logout User1. $this->drupalLogout(); + // Fill the page cache by requesting the poll. + $this->drupalGet('node/' . $this->poll_nid); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); + $this->drupalGet('node/' . $this->poll_nid); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'HIT', t('Page was cached.')); + // Anonymous user vote on Poll. - $this->drupalPost('node/' . $this->poll_nid, $edit, t('Vote')); + $this->drupalPost(NULL, $edit, t('Vote')); $this->assertText(t('Your vote was recorded.'), t('Anonymous vote was recorded.')); $this->assertText(t('Total votes: @votes', array('@votes' => 2)), t('Vote count updated correctly.')); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); // Check to make sure Anonymous user cannot vote again. $this->drupalGet('node/' . $this->poll_nid); + $this->assertFalse($this->drupalGetHeader('x-drupal-cache'), t('Page was not cacheable.')); $elements = $this->xpath('//input[@value="Vote"]'); $this->assertTrue(empty($elements), t("Anonymous is not able to vote again.")); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); // Login User2. $this->drupalLogin($this->web_user2); @@ -426,6 +444,8 @@ class PollVoteCheckHostname extends PollTestCase { $this->drupalPost('node/' . $this->poll_nid, $edit, t('Vote')); $this->assertText(t('Your vote was recorded.'), t('%user vote was recorded.', array('%user' => $this->web_user2->name))); $this->assertText(t('Total votes: @votes', array('@votes' => 3)), 'Vote count updated correctly.'); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(empty($elements), t("'Cancel your vote' button does not appear.")); // Logout User2. $this->drupalLogout(); @@ -433,20 +453,30 @@ class PollVoteCheckHostname extends PollTestCase { // Change host name for anonymous users. db_update('poll_vote') ->fields(array( - 'hostname' => '123.456.789.20', + 'hostname' => '123.456.789.1', )) - ->condition('hostname', '', '!=') + ->condition('hostname', '', '<>') ->execute(); - // Check to make sure Anonymous user can vote again after hostname change. - $this->drupalPost('node/' . $this->poll_nid, $edit, t('Vote')); + // Check to make sure Anonymous user can vote again with a new session after + // a hostname change. + $this->drupalGet('node/' . $this->poll_nid); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); + $this->drupalPost(NULL, $edit, t('Vote')); $this->assertText(t('Your vote was recorded.'), t('%user vote was recorded.', array('%user' => $this->web_user2->name))); $this->assertText(t('Total votes: @votes', array('@votes' => 4)), 'Vote count updated correctly.'); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); - // Check to make sure Anonymous user cannot vote again. + // Check to make sure Anonymous user cannot vote again with a new session, + // and that the vote from the previous session cannot be cancelledd. + $this->curlClose(); $this->drupalGet('node/' . $this->poll_nid); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); $elements = $this->xpath('//input[@value="Vote"]'); - $this->assertTrue(empty($elements), t("Anonymous is not able to vote again.")); + $this->assertTrue(empty($elements), t('Anonymous is not able to vote again.')); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(empty($elements), t("'Cancel your vote' button does not appear.")); // Login User1. $this->drupalLogin($this->web_user1); @@ -455,6 +485,8 @@ class PollVoteCheckHostname extends PollTestCase { $this->drupalGet('node/' . $this->poll_nid); $elements = $this->xpath('//input[@value="Vote"]'); $this->assertTrue(empty($elements), t("%user is not able to vote again.", array('%user' => $this->web_user1->name))); + $elements = $this->xpath('//input[@value="Cancel your vote"]'); + $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); } }