/[drupal]/contributions/modules/project_issue_voting/project_issue_voting.module
ViewVC logotype

Contents of /contributions/modules/project_issue_voting/project_issue_voting.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.29 - (show annotations) (download) (as text)
Fri Oct 31 21:59:31 2008 UTC (12 months, 3 weeks ago) by dww
Branch: MAIN
CVS Tags: HEAD
Changes since 1.28: +56 -70 lines
File MIME type: text/x-php
#328648 by sun, the coder_format script, and dww: Fixed some code
style problems and other minor code cleanup.
1 <?php
2 // $Id: project_issue_voting.module,v 1.28 2008/10/09 22:06:33 thehunmonkgroup Exp $
3
4
5 /**
6 * @file
7 * This module adds a widget for voting on project issue nodes.
8 * It depends on the Project issue tracking module and Voting API.
9 */
10
11 /**
12 * Implementation of hook_help().
13 */
14 function project_issue_voting_help($section) {
15 switch ($section) {
16 case 'admin/help#project_issue_voting':
17 return '<p>'. t('This module is used to add a simple voting widget to Project issue node types.') .'</p>';
18
19 case 'user/'. arg(1) .'/project-issue-votes':
20 return '<p>'. t('This page shows a summary of voting for project issues. Total votes used is listed at the top, then the table shows how many votes were used for each issue. A user can reclaim all votes from an issue (to be used for voting on other issues) by clicking the <em>Reclaim votes</em> link.') .'</p>';
21 }
22 }
23
24 /**
25 * Implementation of hook_perm().
26 */
27 function project_issue_voting_perm() {
28 return array('vote on issues', 'view issue votes', 'administer issue voting');
29 }
30
31 /**
32 * Form builder for the administrative settings form.
33 */
34 function project_issue_voting_admin_settings() {
35 $form['project_issue_voting_allowed_user_votes'] = array(
36 '#type' => 'textfield',
37 '#title' => t('Total votes per user'),
38 '#size' => 5,
39 '#maxlength' => 5,
40 '#required' => TRUE,
41 '#default_value' => variable_get('project_issue_voting_allowed_user_votes', 20),
42 '#description' => t('The total number of votes that a user is allowed to place across all project issues.'),
43 '#validate' => array('project_issue_voting_validate_numeric' => array()),
44 );
45
46 $form['vote_node_types'] = array(
47 '#type' => 'fieldset',
48 '#title' => t('Types'),
49 '#description' => t('Set the issue types you want to activate voting on. For each type of filtering, leaving all boxes unchecked will result in no filtering for that type.'),
50 '#collapsible' => TRUE,
51 );
52
53 // Add limit by project type if we're using taxonomy.
54 if (project_use_taxonomy()) {
55 $vid = _project_get_vid();
56 $tree = taxonomy_get_tree($vid, 0, -1, 1);
57 $options = array();
58 foreach ($tree as $term) {
59 $options[$term->tid] = $term->name;
60 }
61
62 $form['vote_node_types']['project_issue_voting_project_types'] = array(
63 '#type' => 'checkboxes',
64 '#title' => t('Project types'),
65 '#default_value' => variable_get('project_issue_voting_project_types', array()),
66 '#options' => $options,
67 );
68 }
69
70 $form['vote_node_types']['project_issue_voting_issue_categories'] = array(
71 '#type' => 'checkboxes',
72 '#title' => t('Categories'),
73 '#default_value' => variable_get('project_issue_voting_issue_categories', array()),
74 '#options' => project_issue_category(0),
75 );
76
77 $form['vote_node_types']['project_issue_voting_issue_states'] = array(
78 '#type' => 'checkboxes',
79 '#title' => t('States'),
80 '#default_value' => variable_get('project_issue_voting_issue_states', array()),
81 '#options' => project_issue_state(),
82 );
83
84 $form['vote_widget_settings_node'] = array(
85 '#type' => 'fieldset',
86 '#title' => t('Vote widget settings for nodes'),
87 '#collapsible' => TRUE,
88 '#collapsed' => TRUE,
89 );
90
91 $widget_options = array(
92 'disabled' => t('Disabled'),
93 'teaser' => t('Teaser view'),
94 'full' => t('Full-page view'),
95 'teaser-full' => t('Teasers and full-page view'),
96 );
97 $form['vote_widget_settings_node']['project_issue_voting_widget_node'] = array(
98 '#type' => 'select',
99 '#title' => t('Vote widget display'),
100 '#default_value' => variable_get('project_issue_voting_widget_node', 'full'),
101 '#options' => $widget_options,
102 '#description' => t('When to display the vote widget for nodes.'),
103 );
104 $form['vote_widget_settings_node']['project_issue_voting_link_node'] = array(
105 '#type' => 'select',
106 '#title' => t('Link display of total votes for an issue'),
107 '#default_value' => variable_get('project_issue_voting_link_node', 'teaser'),
108 '#options' => $widget_options,
109 '#description' => t('When to display total issue votes for nodes.'),
110 );
111
112 $form['vote_widget_settings_advanced'] = array(
113 '#type' => 'fieldset',
114 '#title' => t('Advanced settings'),
115 '#collapsible' => TRUE,
116 '#collapsed' => TRUE,
117 );
118
119 /*
120 Decided to not expose this setting to admins.
121
122 $form['vote_widget_settings_advanced']['project_issue_voting_tag'] = array(
123 '#type' => 'textfield',
124 '#title' => t('Vote tag'),
125 '#default_value' => variable_get('project_issue_voting_tag', 'issue'),
126 '#description' => t('All votes from the Project issue voting module will be tagged with this term. Using a unique value here may be useful when you deploy various voting modules that all use the Voting API. (Default: issue)'),
127 );
128 */
129
130 $form['vote_widget_settings_advanced']['project_issue_voting_reset_votes'] = array(
131 '#type' => 'radios',
132 '#title' => t("Provide a 'Reset votes' link on issues"),
133 '#default_value' => variable_get('project_issue_voting_reset_votes', 0),
134 '#options' => array(0 => t('No'), 1 => t('Yes')),
135 '#description' => t('If yes a link will be displayd on nodes that will reset the users votes on that node.'),
136 );
137
138 return system_settings_form($form);
139 }
140
141 /**
142 * Implementation of hook_menu().
143 */
144 function project_issue_voting_menu($may_cache) {
145 $items = array();
146
147 $vote_access = user_access('vote on issues');
148 $view_votes_access = user_access('view issue votes');
149 $admin_votes_access = user_access('administer issue voting');
150
151 $types = node_get_types();
152 $name = $types['project_issue']->name;
153
154 if ($may_cache) {
155 $items[] = array(
156 'path' => 'admin/project/project-issue-voting',
157 'title' => t('@project_issue_type voting', array('@project_issue_type' => $name)),
158 'description' => t('Set up voting on @project_issue_type nodes.', array('@project_issue_type' => $name)),
159 'callback' => 'drupal_get_form',
160 'callback arguments' => 'project_issue_voting_admin_settings',
161 'access' => $admin_votes_access,
162 );
163 $items[] = array(
164 'path' => 'project-issue-voting-vote',
165 'callback' => 'project_issue_voting_vote',
166 'access' => $vote_access,
167 'type' => MENU_CALLBACK,
168 );
169 $items[] = array(
170 'path' => 'project/issues/votes',
171 'title' => t('@project_issue_type votes', array('@project_issue_type' => $name)),
172 'description' => t('@project_issue_type vote summaries.', array('@project_issue_type' => $name)),
173 'callback' => 'project_issue_voting_page',
174 'access' => $view_votes_access,
175 );
176 $items[] = array(
177 'path' => 'project/issues/votes/users',
178 'title' => t('Users by votes'),
179 'callback' => 'project_issue_voting_users_votes',
180 'access' => $view_votes_access,
181 );
182 }
183 else {
184 if (arg(0) == 'node' && is_numeric(arg(1))) {
185 $node = node_load(arg(1));
186 if (project_issue_voting_check_issue_for_voting($node)) {
187 $items[] = array(
188 'path' => 'node/'. arg(1) .'/project-issue-votes',
189 'title' => t('Votes'),
190 'callback' => 'project_issue_voting_issue_votes',
191 'callback arguments' => array($node),
192 'access' => $view_votes_access,
193 'weight' => 5,
194 'type' => MENU_LOCAL_TASK,
195 );
196 drupal_add_css(drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.css');
197 drupal_add_js(drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.js');
198 drupal_add_js(
199 array(
200 'projectIssueVotingURL' => url('project-issue-voting-vote'),
201 'projectIssueVotingToken' => project_issue_voting_get_token(),
202 ),
203 'setting'
204 );
205 }
206 }
207 if (arg(0) == 'user' && is_numeric(arg(1))) {
208 $account = user_load(array('uid' => arg(1)));
209 $items[] = array(
210 'path' => 'user/'. arg(1) .'/project-issue-votes',
211 'title' => t('@project_issue_type votes', array('@project_issue_type' => $name)),
212 'callback' => 'project_issue_voting_user_votes',
213 'callback arguments' => array($account),
214 'access' => $view_votes_access,
215 'weight' => 5,
216 'type' => MENU_LOCAL_TASK,
217 );
218 }
219 if (module_exists('views')) {
220 drupal_add_css(drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.views.css');
221 }
222 }
223 return $items;
224 }
225
226 /**
227 * Implementation of hook_nodeapi().
228 */
229 function project_issue_voting_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
230 switch ($op) {
231 case 'view':
232 if (project_issue_voting_check_issue_for_voting($node) && project_issue_voting_display('node', $teaser)) {
233 $node->content['project_issue_voting'] = array(
234 '#value' => project_issue_voting_interface($node),
235 '#weight' => -50,
236 );
237 }
238 break;
239
240 case 'delete':
241 project_issue_voting_delete_votes($node);
242 break;
243 }
244 }
245
246 /**
247 * Implementation of hook_link().
248 */
249 function project_issue_voting_link($type, $node = NULL, $teaser = FALSE) {
250 $links = array();
251 switch ($type) {
252 case 'node':
253 if (project_issue_voting_check_issue_for_voting($node) && user_access('view issue votes')) {
254 $user_votes = project_issue_voting_get_issue_user_votes($node->nid);
255 // Users get a reclaim link if it's enabled and they have any votes on
256 // the issue.
257 if ($user_votes !== FALSE) {
258 if (variable_get('project_issue_voting_reset_votes', 0) && user_access('vote on issues')) {
259 $token = project_issue_voting_get_token();
260 $links['project_issue_voting_reset'] = array(
261 'title' => t('Reclaim votes'),
262 'href' => "project-issue-voting-vote/$node->nid/0/$token",
263 'attributes' => array('title' => t('Reset your votes on this issue to zero.')),
264 'query' => drupal_get_destination(),
265 );
266 }
267 }
268 $total_votes = project_issue_voting_get_total_votes($node->nid);
269 if (project_issue_voting_display('link', $teaser)) {
270 $links['project_issue_voting_user_votes'] = array(
271 'title' => format_plural($total_votes, '@count total vote', '@count total votes'),
272 'href' => "node/$node->nid/project-issue-votes",
273 'attributes' => array('id' => "project-issue-voting-total-votes-link-$node->nid", 'title' => t('View all votes for this issue.')),
274 );
275 }
276 }
277 break;
278 }
279 return $links;
280 }
281
282 /**
283 * Menu callback; Handles main project issue voting page.
284 *
285 * This just prints out all the visible menu items in the subtree
286 * under /project/issues/votes so that as other pages are added
287 * (e.g. via views and/or panels) they will show up automatically.
288 */
289 function project_issue_voting_page() {
290 $mid = menu_get_active_item();
291 $menu = menu_get_menu();
292 $items = array();
293 foreach ($menu['visible'][$mid]['children'] as $child_mid) {
294 $item = menu_get_item($child_mid);
295 $items[] = l($item['title'], $item['path']);
296 }
297 return theme('item_list', $items);
298 }
299
300 /**
301 * Users votes page for the project_issue_voting data.
302 */
303 function project_issue_voting_users_votes() {
304 $issue_states = array_filter(variable_get('project_issue_voting_issue_states', array()));
305 $placeholders = implode(',', array_fill(0, count($issue_states), '%d'));
306 $sql = "SELECT COUNT(v.value) AS number_votes, SUM(v.value) AS total_votes, v.tag, u.uid, u.name FROM {votingapi_vote} v INNER JOIN {users} u on v.uid = u.uid INNER JOIN {project_issues} pi ON pi.nid = v.content_id WHERE v.content_type = '%s' AND v.tag = '%s' AND pi.sid IN ($placeholders) GROUP BY u.name, u.uid, v.tag";
307
308 $args = array('content_type' => 'node', 'tag' => variable_get('project_issue_voting_tag', 'issue')) + $issue_states;
309 $sql_cnt = "SELECT COUNT(DISTINCT(uid)) FROM {votingapi_vote}";
310 $header = array(
311 array('data' => t('User'), 'field' => 'u.name'),
312 array('data' => t('# of issues voted'), 'field' => 'number_votes', 'sort' => 'desc'),
313 array('data' => t('Total votes'), 'field' => 'total_votes'),
314 );
315 $sql .= tablesort_sql($header);
316 $result = pager_query($sql, 30, 0, $sql_cnt, $args);
317
318 $allowed_votes = variable_get('project_issue_voting_allowed_user_votes', 20);
319
320 while ($vote = db_fetch_object($result)) {
321 $rows[] = array(
322 theme('username', $vote),
323 $vote->number_votes,
324 $vote->total_votes .'/'. check_plain($allowed_votes),
325 );
326 }
327 drupal_set_title(t('Users by votes'));
328 $output = theme('table', $header, $rows);
329 $output .= theme('pager', NULL, 30, 0);
330
331 return $output;
332 }
333
334 /**
335 * Menu callback; display all votes for an issue node.
336 */
337 function project_issue_voting_issue_votes($node) {
338 $header = array(
339 array('data' => t('User')),
340 array('data' => t('Votes')),
341 array('data' => t('Date')),
342 );
343 $votes = votingapi_get_content_votes('node', $node->nid);
344 $args = array_keys($votes);
345 $placeholders = implode(', ', array_fill(0, count($args), '%d'));
346 $args[] = 1;
347 $result = db_query("SELECT uid, name FROM {users} WHERE uid IN (". $placeholders .") AND status = %d ORDER BY name", $args);
348 while ($user = db_fetch_object($result)) {
349 $vote = $votes[$user->uid][0];
350 $rows[] = array(
351 theme('username', $user),
352 check_plain($vote->value),
353 array('data' => format_date($vote->timestamp, 'small'), 'class' => 'nowrap'),
354 );
355 }
356 drupal_set_title(check_plain($node->title));
357 return theme('table', $header, $rows);
358 }
359
360 /**
361 * Menu callback; display all votes for a user.
362 */
363 function project_issue_voting_user_votes($account) {
364 global $user;
365
366 $output = '';
367 if (!empty($account)) {
368 if (($account->uid == $user->uid && $account->status == 1) || user_access('administer issue voting')) {
369 $votes_used = project_issue_voting_get_total_user_votes($account->uid);
370 $allowed_votes = variable_get('project_issue_voting_allowed_user_votes', 20);
371 $output .= theme('project_issue_voting_user_votes_summary', $votes_used, $allowed_votes);
372
373 $header = array(
374 array('data' => t('Issue'), 'field' => 'title', 'sort' => 'asc'),
375 array('data' => t('Status'), 'field' => 'sid'),
376 array('data' => t('Votes'), 'field' => 'value'),
377 array('data' => t('Operations')),
378 );
379 $sql = db_rewrite_sql("SELECT n.nid, n.title, pi.sid, v.value FROM {node} n INNER JOIN {project_issues} pi ON n.nid = pi.nid INNER JOIN {votingapi_vote} v ON n.nid = v.content_id WHERE v.uid = %d AND v.tag = '%s' AND v.content_type = 'node' AND n.status = 1". tablesort_sql($header));
380 $result = pager_query($sql, 25, 0, NULL, $account->uid, variable_get('project_issue_voting_tag', 'issue'));
381 $reset = variable_get('project_issue_voting_reset_votes', 0);
382 $token = project_issue_voting_get_token();
383 while ($node = db_fetch_object($result)) {
384 $operations = ($reset ? l(t('Reclaim votes'), "project-issue-voting-vote/{$node->nid}/0/$token", array(), drupal_get_destination()) : '');
385 $rows[] = array(
386 l($node->title, 'node/'. $node->nid),
387 project_issue_state($node->sid),
388 check_plain($node->value),
389 $operations,
390 );
391 }
392 drupal_set_title(check_plain($account->name));
393 $output .= theme('table', $header, $rows);
394 $output .= theme('pager', NULL, 25);
395
396 return $output;
397 }
398 else {
399 return drupal_access_denied();
400 }
401 }
402 else {
403 return drupal_not_found();
404 }
405 }
406
407 /**
408 * A voting get handler with AJAX support.
409 */
410 function project_issue_voting_vote($nid, $value, $token = '', $ajax = FALSE) {
411 if (is_numeric($nid) && is_numeric($value) && project_issue_voting_valid_token($token)) {
412 $node = node_load($nid);
413
414 if (($uid = _project_issue_voting_get_uid()) && project_issue_voting_check_issue_for_voting($node) && user_access('vote on issues')) {
415 // Sanity-check the incoming values.
416 if ($value > 0) {
417 $vote->value = 1;
418 }
419 elseif ($value < 0) {
420 $vote->value = -1;
421 $subtracting_votes = TRUE;
422 }
423 else {
424 $vote->value = 0;
425 }
426
427 $current_votes = votingapi_get_user_votes('node', $nid, $uid);
428 // Increment or decrement the user's votes as necessary.
429 if ($vote->value != 0 && isset($current_votes[0])) {
430 $vote->value = $current_votes[0]->value + $vote->value;
431 }
432 // Make sure users can't set an issue's total points to a negative value.
433 elseif ($vote->value < 1) {
434 $vote->value = 0;
435 }
436
437 if ($vote->value == 0) {
438 votingapi_unset_vote('node', $nid, $uid);
439 }
440 else {
441 // Make sure the user is trying to add a vote that they
442 // still have available votes to add.
443 if (isset($subtracting_votes) || project_issue_voting_user_can_add_votes($uid)) {
444 // We have to manually add the type/tag here.
445 $vote->value_type = 'points';
446 $vote->tag = variable_get('project_issue_voting_tag', 'issue');
447 votingapi_set_vote('node', $nid, $vote, $uid);
448 }
449 else {
450 $vote->value = $current_votes[0]->value;
451 }
452 }
453 }
454 // For some reason this user can't vote, so kick 'em out.
455 else {
456 if ($ajax) {
457 return;
458 }
459 else {
460 drupal_set_message(t('An illegal voting action has occured'), 'error');
461 drupal_goto(drupal_get_destination());
462 }
463 }
464
465 if ($ajax) {
466 $issue_total_votes = project_issue_voting_get_total_votes($nid);
467 $total_user_votes_used = project_issue_voting_get_total_user_votes($uid);
468 $total_user_votes = variable_get('project_issue_voting_allowed_user_votes', 20);
469 $vote_subtract = $vote->value == 0 ? FALSE : TRUE;
470 $ajax_votes = array(
471 'total' => theme("project_issue_voting_issue_total_votes", $nid, $issue_total_votes),
472 'user' => theme("project_issue_voting_issue_user_votes", $nid, $total_user_votes_used, $vote->value, $total_user_votes),
473 'vote_add' => project_issue_voting_user_can_add_votes($uid),
474 'vote_subtract' => $vote_subtract,
475 'total_votes_link_votes' => format_plural($issue_total_votes, '@count total vote', '@count total votes'),
476 'total_votes_metadata_table' => check_plain($issue_total_votes),
477 );
478 drupal_set_header('Content-type: text/javascript');
479 print drupal_to_js($ajax_votes);
480 exit();
481 }
482 else {
483 drupal_goto(drupal_get_destination());
484 }
485 }
486 }
487
488 /**
489 * Return the voting widget display and total issue votes if neccessary.
490 */
491 function project_issue_voting_interface($node) {
492 global $user;
493
494 $nid = $node->nid;
495
496 $output = '';
497
498 if (user_access('view issue votes')) {
499 $issue_total_votes = project_issue_voting_get_total_votes($nid);
500 $output .= theme('project_issue_voting_issue_total_votes_wrapper', $nid, $issue_total_votes);
501 }
502
503 if (user_access('vote on issues')) {
504 $total_user_votes_used = project_issue_voting_get_total_user_votes($user->uid);
505 if ($total_user_votes_used !== FALSE) {
506 $issue_user_votes = project_issue_voting_get_issue_user_votes($nid);
507 $total_user_votes = variable_get('project_issue_voting_allowed_user_votes', 20);
508 // Determine if the add/remove votes selectors are enabled/disabled
509 // users can't add more if they've used all their available votes,
510 // and can't subtract more if they currently have no votes on the issue.
511 $up_class = project_issue_voting_user_can_add_votes($user->uid) ? 'act' : 'inact';
512 $down_class = $issue_user_votes ? 'act' : 'inact';
513 $output .= theme('project_issue_voting_widget', $nid, $total_user_votes_used, $issue_user_votes, $total_user_votes, $up_class, $down_class);
514 }
515 }
516
517 // Put everything in a wrapper div so it can stay together.
518 $output = theme('project_issue_voting_widget_wrapper', $output);
519
520 return $output;
521 }
522
523 /**
524 * Themes the user voting widget on project issue nodes.
525 *
526 * @param $nid
527 * Issue node ID.
528 * @param $total_user_votes_used
529 * The total votes a user has used across all issues.
530 * @param unknown_type $issue_user_votes
531 * The total votes the user has used on the current issue.
532 * @param unknown_type $total_user_votes
533 * The total votes that a user has to allocate across all issues.
534 * @param unknown_type $up_class
535 * The CSS class for increasing a vote, should be 'act' or 'inact'.
536 * @param unknown_type $down_class
537 * The CSS class for decreasing a vote, should be 'act' or 'inact'.
538 */
539 function theme_project_issue_voting_widget($nid, $total_user_votes_used, $issue_user_votes, $total_user_votes, $up_class, $down_class) {
540 $token = project_issue_voting_get_token();
541
542 $output = '';
543 $output .= '<div id="project-issue-voting-widget-'. $nid .'" class="project-issue-voting-widget">';
544 $output .= theme('project_issue_voting_issue_user_votes', $nid, $total_user_votes_used, $issue_user_votes, $total_user_votes);
545 $output .= '<span id="project-issue-voting-vote-up-'. $nid .'" class="project-issue-voting-vote-up project-issue-voting-vote-up-'. $up_class .'" title="'. t('Add 1 vote') .'" nid="'. $nid .'">'. l('', "project-issue-voting-vote/$nid/1/$token", array('class' => "project-issue-voting-vote-up-$up_class", 'title' => t('Add 1 vote')), drupal_get_destination(), NULL, FALSE, TRUE) .'</span>';
546 $output .= '<span id="project-issue-voting-vote-down-'. $nid .'" class="project-issue-voting-vote-down project-issue-voting-vote-down-'. $down_class .'" title="'. t('Subtract 1 vote') .'" nid="'. $nid .'">'. l('', "project-issue-voting-vote/$nid/-1/$token", array('class' => "project-issue-voting-vote-down-$down_class", 'title' => t('Subtract 1 vote')), drupal_get_destination(), NULL, FALSE, TRUE) .'</span>';
547 $output .= '</div>';
548
549 return $output;
550 }
551
552 /**
553 * Return HTML for the users voting display on a project issue node.
554 *
555 * This display includes a summary of their overall voting values.
556 *
557 * @param $nid
558 * Issue node ID.
559 * @param $total_user_votes_used
560 * The total votes a user has used across all issues.
561 * @param unknown_type $issue_user_votes
562 * The total votes the user has used on the current issue.
563 * @param unknown_type $total_user_votes
564 * The total votes that a user has to allocate across all issues.
565 */
566 function theme_project_issue_voting_issue_user_votes($nid, $total_user_votes_used, $issue_user_votes, $total_user_votes) {
567 $output = '';
568 $output .= '<div id="project-issue-voting-votes-'. $nid .'" class="project-issue-voting-user project-issue-voting-votes">';
569 $output .= '<div class="project-issue-voting-votes-user-label">'. t('My issue votes') .'</div>';
570 $output .= '<div class="project-issue-voting-votes-user">'. check_plain($issue_user_votes) .'</div>';
571 $output .= '<div class="project-issue-voting-votes-label">'. format_plural($issue_user_votes, 'vote', 'votes') .'</div>';
572 // Since format_plural doesn't support additional placeholders
573 // beyond @count in Drupal 5, we have to do this in two phases with
574 // a second placeholder for the total, and substitute that separately.
575 $total_line = format_plural($total_user_votes_used, '@count/@total total vote used', '@count/@total total votes used');
576 $total_line = strtr($total_line, array('@total' => check_plain($total_user_votes)));
577 $output .= '<div class="project-issue-voting-votes-label">'. $total_line .'</div>';
578 $output .= '</div>';
579
580 return $output;
581 }
582
583 function theme_project_issue_voting_widget_wrapper($output) {
584 $wrapper = '';
585 $wrapper .= '<div class="project-issue-voting-wrapper">';
586 $wrapper .= $output;
587 $wrapper .= '</div>';
588
589 return $wrapper;
590 }
591
592 /**
593 * Wrapper for the user voting widget on project issue nodes.
594 *
595 * NOTE: This display is commented out by default, because
596 * there's already a total vote count in the issue metadata
597 * table. It's been left here in case anybody wants to uncomment
598 * it to get a big themable display of the issue's total votes.
599 *
600 * @param $nid
601 * Issue node ID.
602 * @param $issue_total_votes
603 * The total number of votes placed on the issue
604 * across all users.
605 */
606 function theme_project_issue_voting_issue_total_votes_wrapper($nid, $issue_total_votes) {
607 $output = '';
608 /*
609 $output .= '<div id="project-issue-voting-votes-total-wrapper-'. $nid .'" class="project-issue-voting-total">';
610 $output .= theme('project_issue_voting_issue_total_votes', $nid, $issue_total_votes);
611 $output .= '</div>';
612 */
613 return $output;
614 }
615
616 /**
617 * Return HTML for the user voting widget on project issue nodes.
618 *
619 * NOTE: This display is disabled by default, because
620 * there's already a total vote count in the issue metadata
621 * table. It's been left here in case anybody wants to uncomment
622 * it to get a big themable display of the issue's total votes.
623 *
624 * @param $nid
625 * Issue node ID.
626 * @param $issue_total_votes
627 * The total number of votes placed on the issue
628 * across all users.
629 */
630 function theme_project_issue_voting_issue_total_votes($nid, $issue_total_votes) {
631 $output = '';
632 $output .= '<div class="project-issue-voting-votes">';
633 $output .= '<div class="project-issue-voting-votes-total-label">'. t('Total issue votes') .'</div>';
634 $output .= '<div class="project-issue-voting-votes-total">'. check_plain($issue_total_votes) .'</div>';
635 $output .= '<div class="project-issue-voting-votes-label">'. format_plural($issue_total_votes, 'vote', 'votes') .'</div>';
636 $output .= '</div>';
637 return $output;
638 }
639
640 /**
641 * Return HTML for the users's overall voting summary.
642 *
643 * @param $votes_used
644 * The total votes a user has used across all issues.
645 * @param unknown_type $allowed_votes
646 * The total votes that a user has to allocate across all issues.
647 */
648 function theme_project_issue_voting_user_votes_summary($votes_used, $allowed_votes) {
649 return '<h4>'. t('Total votes used') .': '. check_plain("$votes_used/$allowed_votes") .'</h4>';
650 }
651
652 /**
653 * Get a uid for anonymous vs. registered voting.
654 */
655 function _project_issue_voting_get_uid() {
656 global $user;
657
658 if ($user->uid) {
659 $uid = $user->uid;
660 }
661 elseif (user_access('vote on issues')) {
662 // Fake uid for anonymous users.
663 // If the IP is valid turn it into a integer and add the number of the current day.
664 // The current day is what limit anonymous voting to one vote per day and IP address.
665 $hostname = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
666 if ($long = ip2long($hostname)) {
667 $uid = abs($long) + date('z');
668 }
669 }
670 else {
671 $uid = FALSE;
672 }
673 return $uid;
674 }
675
676 /**
677 * Checks an issue node to determine if it's enabled for voting.
678 *
679 * Since the function is called multiple times, cache the test results.
680 *
681 * @param $node
682 * The issue node.
683 *
684 * @return
685 * TRUE if the issue node is enabled for voting, FALSE otherwise.
686 */
687 function project_issue_voting_check_issue_for_voting($node) {
688 static $state_check = array();
689
690 if (isset($state_check[$node->nid])) {
691 return $state_check[$node->nid];
692 }
693
694 // If it's not a project issue node, they can't vote on it.
695 if ($node->type != 'project_issue') {
696 $state_check[$node->nid] = FALSE;
697 return FALSE;
698 }
699
700 // Check for enabled project type if we're using taxonomy.
701 if (project_use_taxonomy()) {
702 $project_types = array_filter(variable_get('project_issue_voting_project_types', array()));
703
704 if (count($project_types)) {
705 // Pull all project categories.
706 $vid = _project_get_vid();
707 $tree = taxonomy_get_tree($vid, 0, -1, 1);
708
709 foreach ($tree as $term) {
710 $args[] = $term->tid;
711 }
712 $placeholders = implode(', ', array_fill(0, count($args), '%d'));
713 $args[] = $node->pid;
714
715 // Pull all categories associated with the issue.
716 $current_project_terms = db_query("SELECT tid FROM {term_node} WHERE tid IN($placeholders) AND nid = %d", $args);
717 $project_terms = array();
718 while ($project_term = db_fetch_object($current_project_terms)) {
719 $project_terms[] = $project_term->tid;
720 }
721
722 // Check if any of the issue's categories are enabled for voting.
723 if (!array_intersect($project_types, $project_terms)) {
724 $state_check[$node->nid] = FALSE;
725 return FALSE;
726 }
727 }
728 }
729
730 // Check if the issue category type is enabled.
731 $issue_categories = array_filter(variable_get('project_issue_voting_issue_categories', array()));
732 // Check if the issue is in an enabled category.
733 if (count($issue_categories) && !in_array($node->category, $issue_categories)) {
734 $state_check[$node->nid] = FALSE;
735 return FALSE;
736 }
737
738 // Check to make sure the issue has an active issue voting state.
739 $issue_states = array_filter(variable_get('project_issue_voting_issue_states', array()));
740 if (count($issue_states) && !in_array($node->sid, $issue_states)) {
741 $state_check[$node->nid] = FALSE;
742 return FALSE;
743 }
744
745 $state_check[$node->nid] = TRUE;
746 return TRUE;
747 }
748
749 /**
750 * Return the number of votes a specified user has placed on a given issue.
751 *
752 * @param $nid
753 * The issue node ID.
754 * @param $uid
755 * The user to check votes for.
756 */
757 function project_issue_voting_get_issue_user_votes($nid, $uid = NULL) {
758 global $user;
759
760 if (!isset($uid)) {
761 $uid = $user->uid;
762 }
763
764 // Make up a uid for anonymous users.
765 if ($uid == 0) {
766 $uid = _project_issue_voting_get_uid();
767 }
768
769 if ($uid) {
770 $vote_result = votingapi_get_user_votes('node', $nid, $uid);
771 return isset($vote_result[0]) ? $vote_result[0]->value : 0;
772 }
773
774 return FALSE;
775 }
776
777 /**
778 * Return the number of total votes on a specified issue.
779 *
780 * @param $nid
781 * The issue node ID.
782 */
783 function project_issue_voting_get_total_votes($nid) {
784 $vote_result = votingapi_get_voting_result('node', $nid, 'points', variable_get('project_issue_voting_tag', 'issue'), 'sum');
785 return $vote_result ? $vote_result->value : 0;
786 }
787
788 /**
789 * Validate that the entered value is a number.
790 */
791 function project_issue_voting_validate_numeric($form) {
792 if (!is_numeric($form['#value'])) {
793 form_error($form, t('@element_name must be a number.', array('@element_name' => $form['#title'])));
794 }
795 }
796
797 /**
798 * Return the number of total votes a user has cast across all issues.
799 *
800 * @param $uid
801 * The user ID.
802 */
803 function project_issue_voting_get_total_user_votes($uid = NULL) {
804 global $user;
805
806 if (!isset($uid)) {
807 $uid = $user->uid;
808 }
809
810 // Make up a uid for anonymous users.
811 if ($uid == 0) {
812 $uid = _project_issue_voting_get_uid();
813 }
814
815 if ($uid) {
816 $user_votes = db_result(db_query("SELECT SUM(value) FROM {votingapi_vote} WHERE content_type = '%s' AND value_type = '%s' AND tag = '%s' AND uid = %d", 'node', 'points', variable_get('project_issue_voting_tag', 'issue'), $uid));
817
818 return $user_votes ? $user_votes : 0;
819 }
820
821 return FALSE;
822 }
823
824 /**
825 * Check to see if a specified user has available votes to assign.
826 *
827 * @param $uid
828 * The user ID.
829 */
830 function project_issue_voting_user_can_add_votes($uid = NULL) {
831 $user_votes = project_issue_voting_get_total_user_votes($uid);
832 return $user_votes !== FALSE && $user_votes < variable_get('project_issue_voting_allowed_user_votes', 20);
833 }
834
835 /**
836 * Helper function which generates a token for voting requests.
837 */
838 function project_issue_voting_get_token() {
839 return drupal_get_token('project_issue_voting_widget');
840 }
841
842 /**
843 * Helper function which checks a token for voting requests.
844 */
845 function project_issue_voting_valid_token($token) {
846 return drupal_valid_token($token, 'project_issue_voting_widget');
847 }
848
849 /**
850 * Implementation of hook_project_issue_metadata().
851 *
852 * Adds the total votes into the issue metadata summary table in a
853 * span so that the total can be updated by the jQuery when users vote.
854 */
855 function project_issue_voting_project_issue_metadata($view, $node, &$current_data) {
856 switch ($view) {
857 case 'current':
858 if (user_access('view issue votes')) {
859 $total_issue_votes = project_issue_voting_get_total_votes($node->nid);
860 $current_data['project_issue_voting_total_issue_votes'] = array(
861 'label' => t('Total votes'),
862 'current' => '<span id="project-issue-voting-metadata-table-total-votes-'. $node->nid .'">'. check_plain($total_issue_votes) .'</span>',
863 );
864 }
865 break;
866 }
867 }
868
869 /**
870 * Implementation of hook_views_default_views.
871 *
872 * @see _project_issue_voting_views_default_views
873 */
874 function project_issue_voting_views_default_views() {
875 require_once drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.views.inc';
876 return _project_issue_voting_views_default_views();
877 }
878
879 /**
880 * Implementation of hook_panels_default_panel_views.
881 *
882 * @see _project_issue_voting_default_panel_views()
883 */
884 function project_issue_voting_default_panel_views() {
885 require_once drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.panels.inc';
886 return _project_issue_voting_default_panel_views();
887 }
888
889 /**
890 * Implementation of hook_panels_default_panel_views.
891 *
892 * @see _project_issue_voting_panels_default_panel_pages()
893 */
894 function project_issue_voting_default_panel_pages() {
895 require_once drupal_get_path('module', 'project_issue_voting') .'/project_issue_voting.panels.inc';
896 return _project_issue_voting_default_panel_pages();
897 }
898
899 /**
900 * Determine if the specified voting type should be displayed on the current page.
901 *
902 * @param $type
903 * The type of display we're checking. Can be 'node' or 'link'.
904 * @param $teaser
905 * TRUE if we're viewing a teaser, FALSE otherwise.
906 */
907 function project_issue_voting_display($type, $teaser) {
908 switch ($type) {
909 case 'node':
910 $display_type = variable_get('project_issue_voting_widget_node', 'full');
911 break;
912
913 case 'link':
914 $display_type = variable_get('project_issue_voting_link_node', 'teaser');
915 break;
916 }
917 $display = FALSE;
918 if ($teaser) {
919 if (in_array($display_type, array('teaser', 'teaser-full'))) {
920 $display = TRUE;
921 }
922 }
923 else {
924 if (in_array($display_type, array('full', 'teaser-full'))) {
925 $display = TRUE;
926 }
927 }
928 return $display;
929 }
930
931 /**
932 * Deletes all issue votes on a given issue node.
933 */
934 function project_issue_voting_delete_votes($node) {
935 if ($node->type == 'project_issue') {
936 $issue_tag = variable_get('project_issue_voting_tag', 'issue');
937 $votes = _votingapi_get_raw_votes('node', $node->nid, NULL, array($issue_tag));
938 votingapi_delete_votes($votes);
939 votingapi_recalculate_results('node', $node->nid, TRUE);
940 }
941 }

  ViewVC Help
Powered by ViewVC 1.1.2