It would be great if one logged in user can vote multiple times for the same node, not only one time. May be with a voting delay (one week in my case).
After searching I do not found, ever in votingapi, where the limitation of one vote per node is implemented.

I would use this to allow buyers to vote for products they bought in ubercart.
I get a view with product bought last week, I use userpoints to control users votes. Each order = 1 point = 1 vote. So I will sell food and buyer can buy the same product multiple times. The only thing to get it working is multiple voting on the same node.

Comments

ledom’s picture

Finaly found a workaround by hacking votingapi.module and removing test on criteria an window:

Before:
311 if (!empty($criteria['vote_source']) && $anon_window >= 0) {
312 $criteria['timestamp'] = time() - $anon_window;
313 }

After:
311// if (!empty($criteria['vote_source']) && $anon_window >= 0) {
312 $criteria['timestamp'] = time() - $anon_window;
313// }

jcisio’s picture

Project: Vote Up/Down » Voting API
Version: 6.x-2.0-beta2 » 6.x-2.x-dev
Component: vud_node » Code

I move this issue from vote_up_down to VotingAPI if you don't mind.

marvil07’s picture

Not exactly what you asked for, but related: #813534: +N/-N votes on widgets

jjchinquist’s picture

Hello,

I too am intersted in changing the behaviour (adding a setting in the API admin/settings/votingapi form). It appears straight forward.

I would add a new setting option to admin/settings/votingapi to add a time interval of a non-anonymous user vote. That would then record it to the DB votingapi.module >> votingapi_set_votes

Can anyone answer this question though, if non-anonymous votes are sent and recorded multiple times (1x / day / content_id / uid or 1x / week / content_id / uid, etc.) to votingapi and then to the database, will this mess up any other modules (like advpoll) where it assumes each logged in user votes only 1x / content_id / uid?

Thanks!

jjchinquist’s picture

Status: Active » Needs review

It will take me a bit of time to get the patch created due to technical reasons. However, here is the changes in code I did locally, which worked. Maybe someone can patch on the newest dev version and test.

votingapi.module addition to administration form

  $form['votingapi_registered_user_window'] = array(
    '#type' => 'select',
    '#title' => t('Registered user vote rollover'),
    '#description' => t('The amount of time that must pass before two registered user votes from the same user ID are considered unique. Setting this to \'never\' will eliminate most double-voting, but will make it impossible for multiple anonymous on the same computer (like internet cafe customers) from casting votes.'),
    '#default_value' => variable_get('votingapi_registered_user_window', 86400),
    '#options' => $period
  );

votingapi.module change to votingapi_select_votes

function votingapi_select_votes($criteria = array(), $limit = 0) {
  
  if (!empty($criteria['vote_source']) && $anon_window > 0) {
    $criteria['timestamp'] = time() -  variable_get('votingapi_anonymous_window', 3600);
  }
  if (!empty($criteria['uid']) && (int) $criteria['uid'] > 0 && $user_window > 0){
    $criteria['timestamp'] = time() - variable_get('votingapi_registered_user_window', 3600);
  }
  $votes = array();
  $result = _votingapi_select('vote', $criteria, $limit);
  while ($vote = db_fetch_array($result)) {
    $votes[] = $vote;
  }
  return $votes;
}

votingapi.install change for removing variables on uninstall

function votingapi_uninstall() {
  variable_del('votingapi_anonymous_window');
  variable_del('votingapi_registered_user_window');
  variable_del('votingapi_calculation_schedule');
  
  drupal_uninstall_schema('votingapi');
}
NathanM’s picture

Subscribing & will test out this patch later.

jjchinquist’s picture

Hello NathanM, there is one problem with the following section. If the VotingAPI Admin form is set to "Immediate" then the old votes are overwritten exactly the same as if "Never" were selected.

Old Patch

function votingapi_select_votes($criteria = array(), $limit = 0) {
  
  if (!empty($criteria['vote_source']) && $anon_window > 0) {
    $criteria['timestamp'] = time() -  variable_get('votingapi_anonymous_window', 3600);
  }
  if (!empty($criteria['uid']) && (int) $criteria['uid'] > 0 && $user_window > 0){
    $criteria['timestamp'] = time() - variable_get('votingapi_registered_user_window', 3600);
  }
  $votes = array();
  $result = _votingapi_select('vote', $criteria, $limit);
  while ($vote = db_fetch_array($result)) {
    $votes[] = $vote;
  }
  return $votes;
}

New patch

function votingapi_select_votes($criteria = array(), $limit = 0) {
  $anon_window = variable_get('votingapi_anonymous_window', 3600);
  $user_window = variable_get('votingapi_registered_user_window', 3600);
  
  if (!empty($criteria['vote_source'])) {
    switch($anon_window){
      case 0:
        $criteria['timestamp'] = time();
        break;
      case -1:
        //do nothing, all votes will be deleted
        break;
      default:
        $criteria['timestamp'] = time() - $anon_window;
        break;
    }
  }
  //happens even if the above was also called
  if (!empty($criteria['uid']) && $criteria['uid'] > 0) {
    switch($user_window){
      case 0:
        $criteria['timestamp'] = time();
        break;
      case -1:
        //do nothing, all votes will be deleted
        unset($criteria['timestamp']);
        break;
      default:
        $criteria['timestamp'] = time() - $user_window;
        break;
    }
  }
  $votes = array();
  $result = _votingapi_select('vote', $criteria, $limit);
  while ($vote = db_fetch_array($result)) {
    $votes[] = $vote;
  }
  return $votes;
}
Megha Shah’s picture

Is this patch tested? I'am interested in the same functionality.

emergencyofstate’s picture

Need this same function desperately for D7 version.

havran’s picture

With Rate module you can use this solution (this code is part of my custom module - in my case it's name is regions_vote):

define('REGIONS_VOTE_LIMIT', 60); // 60 seconds for demonstration

/**
 * Implements hook_rate_vote_alter()
 *
 * @param type $votes
 * @param type $context
 */
function regions_vote_rate_vote_alter(&$votes, &$context) {
  // We want save all votes
  $context['criteria'] = FALSE;

  // User vote allowed only if current time is higher than user
  // latest vote time + limit vote time
  $latest_vote = regions_vote_check_vote_allowed($votes);
  if ($latest_vote['status'] === FALSE) {
    $context['save'] = FALSE;
    $_SESSION['regions_vote'] = $latest_vote;
  }
}

/**
 * Implements hook_rate_widget()
 *
 * @param type $op
 * @param type $widget
 * @param type $values
 */
function regions_vote_rate_widget($op, &$widget, $values = NULL) {
  if ($op == 'view') {
    $_SESSION['regions_vote'] = regions_vote_check_vote_allowed(array(
      'content_type' => $values['content_type'],
      'content_id' => $values['content_id'],
      'tag' => REGIONS_VOTE_RATE_TAG,
    ));
  }
}

/**
 * Preprocess function for the regions_vote template.
 */
function regions_vote_preprocess_regions_vote_template_regions_vote(&$variables) {
  extract($variables);

  $variables['button'] = theme('rate_button', $links[0]['text'], $links[0]['href'], 'rate-regions-vote');

  $info = array();
  if ($mode == RATE_CLOSED) {
    $info[] = 'Closed.';
  }
  if ($mode != RATE_COMPACT && $mode != RATE_COMPACT_DISABLED) {
    if (isset($results['user_vote']) && $mode != RATE_CLOSED) {
      if ($just_voted) {
        $info[] = 'Thanks for your vote. You can add new vote after '. $_SESSION['regions_vote']['new_vote_allowed_rendered'];
      }
      else {
        if ($_SESSION['regions_vote']['status'] === FALSE) {
          $info[] = 'Thanks for your vote. You can add new vote after '. $_SESSION['regions_vote']['new_vote_allowed_rendered'];
        }
        else {
          $info[] = 'Thanks for your vote. You could have added new vote for '. $_SESSION['regions_vote']['new_vote_allowed_rendered'];
        }
      }
    }
    else {
      $info[] = $results['count'] .' votes.';
    }
  }
  $variables['info'] = implode(' ', $info);

  if ($just_voted === FALSE) {
    unset($_SESSION['regions_vote']);
  }
}

/**
 * Check if user can vote now.
 *
 * @global type $user
 * @param type $votes
 * @return type
 */
function regions_vote_check_vote_allowed($votes) {
  global $user;

  // Current time.
  $current_time = time();
  // Only one vote per limit per user.
  $limit_vote_time = REGIONS_VOTE_LIMIT;

  // Get latest vote time for this content for current logged user.
  $latest_vote_time = db_result(db_query(
    "SELECT
       timestamp
     FROM {votingapi_vote}
     WHERE
       content_type = '%s' AND
       content_id = %d AND
       tag = '%s' AND
       uid = %d
     ORDER BY timestamp DESC
     LIMIT 1",
    $votes['content_type'],
    $votes['content_id'],
    $votes['tag'],
    $user->uid
  ));

  // User vote allowed only if current time is higher than user
  // latest vote time + limit vote time
  $new_vote_allowed = $latest_vote_time + $limit_vote_time;
  $new_vote_allowed_in_seconds = $new_vote_allowed - $current_time;

  // User can not vote new_vote_allowed_in_seconds seconds...
  if ($current_time < $new_vote_allowed) {
    return array(
      'status' => FALSE,
      'current_time' => $current_time,
      'new_vote_allowed' => $new_vote_allowed,
      'new_vote_allowed_in_seconds' => $new_vote_allowed_in_seconds,
      'new_vote_allowed_rendered' => format_interval($new_vote_allowed_in_seconds),
    );
  }

  // User can vote now...
  return array(
    'status' => TRUE,
    'current_time' => $current_time,
    'new_vote_allowed_in_seconds' => abs($new_vote_allowed_in_seconds),
    'new_vote_allowed_rendered' => format_interval(abs($new_vote_allowed_in_seconds)),
  );
}
frichman’s picture

+1

It would be great if we could get an official patch for this for the D7 version.

balsama’s picture

StatusFileSize
new2.81 KB

Patch incorporating #5 and #7 for Drupal 6 dev branch attached.

balsama’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev
StatusFileSize
new2.9 KB

Drupal 7 patch attached.

This needs to be tested. It looks like the votingapi_select_results() function was slightly modified in the D7 version. I copied @jjchinquist's version from comment #7 above verbatim, which I think was written for the D6 version.

balsama’s picture

StatusFileSize
new2.88 KB

After looking at @jjchinquist's code again, I noticed that it included a db_fetch_array, which obviously won't work in D7. I changed that to a foreach loop in the attached patch.

This patch is still untested though.

istryker’s picture

Status: Needs review » Needs work

Ok I think I found 2 problems

  1. function _votingapi_select() doesn't exist.
    +  $result = _votingapi_select('vote', $criteria, $limit); 
    
  2. I think the default should be 'never'. I could be wrong, but after someone updates (after this gets committed and rolled out to a new version), this will cause unexpected results for most. Users will be able to vote once a day, while before they couldn't.
  3. Minor: there is an extra white-space in patch
    registered_user_rollover-860886-14.patch:45: trailing whitespace.
    

believe #2 applied to 6.x patch too.

istryker’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new2.8 KB
new2.71 KB

Another problem is at the end of patch #14. Something tells me from between May 26th, 2011 and now, the method of selecting the votes from the database has changed. Some one can double-check if they like.
D7

-  $function = variable_get('votingapi_storage_module', 'votingapi') . '_votingapi_storage_select_votes';
-  return $function($criteria, $limit);
+  $votes = array();
+  $result = _votingapi_select('vote', $criteria, $limit);
+  foreach ($result as $vote) {
+    $votes[] = $vote;
+  }
+  return $votes;

Other than that it works.

Attached is my D7 patch, with the changes from this comment and #15.
Attached is @balsama D6 patch, with 3 changes:

  • removed extra white-space
  • change admin default to -1 (-1 = Never)
  • change default 3600 seconds to 0 in votingapi_select_votes()
balsama’s picture

Thanks @iStryker.

Using fivestar, D7 and the votingapi-registered_user_rollover_D7-860886-16.patch patch, I can confirm that both anon and auth voter rollovers are working as I would expect them.

Juan C’s picture

Thanks for the patch. It works.
It would be nicer if the patch allows permission to certain roles only, not all authenticated users, to have the permission for multiple votes.

Cheers,

franzkewd’s picture

Using Advanced Poll, Drupal 7.20, Patch #17. It just works as expected.

Agreed with #19 if we can have the permissions for certain roles only for multiple votes.

torotil’s picture

Status: Reviewed & tested by the community » Fixed

Commited a slightly modified version of this patch to 7.x-2.x. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.