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

Contents of /contributions/modules/userpoints/userpoints.module

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


Revision 1.68 - (show annotations) (download) (as text)
Mon Sep 22 16:04:39 2008 UTC (14 months ago) by kbahey
Branch: MAIN
CVS Tags: HEAD
Changes since 1.67: +4 -4 lines
File MIME type: text/x-php
Correct use of 6.x access arguments.
1 <?php
2 //$Id: userpoints.module,v 1.67 2008/03/26 20:12:43 kbahey Exp $
3
4 // Copyright 2005-2007 Khalid Baheyeldin http://2bits.com
5
6 define('USERPOINTS_PERM_VIEW', 'view userpoints');
7 //The permission(PERM_USE) was removed from use as per #158490 it'll remain
8 //out until code exists to use the permission (jredding 12/26/2007)
9 define('USERPOINTS_PERM_USE', 'use userpoints');
10 define('USERPOINTS_PERM_ADMIN', 'admin userpoints');
11
12 define('USERPOINTS_TRANS_UCPOINTS', 'userpoints_trans_ucpoints');
13 define('USERPOINTS_TRANS_LCPOINTS', 'userpoints_trans_lcpoints');
14 define('USERPOINTS_TRANS_LCPOINT', 'userpoints_trans_lcpoint');
15 define('USERPOINTS_TRANS_UNCAT', 'userpoints_trans_uncat');
16
17 define('USERPOINTS_STATUS', 'userpoints_status');
18
19 define('USERPOINTS_POINTS_MODERATION', 'userpoints_points_moderation');
20
21 define('USERPOINTS_TXN_STATUS_APPROVED', 0);
22 define('USERPOINTS_TXN_STATUS_PENDING', 1);
23 define('USERPOINTS_TXN_STATUS_DECLINED', 2);
24
25
26 define('USERPOINTS_EXPIRY_DESCRIPTION', 'userpoints_expiry_description');
27 define('USERPOINTS_EXPIREON_DATE', 'userpoints_expireon_date');
28 define('USERPOINTS_EXPIREAFTER_DATE', 'userpoints_expireafter_date');
29 define('USERPOINTS_DISPLAY_MESSAGE', 'userpoints_display_message');
30
31 define('USERPOINTS_REPORT_USERCOUNT', 'userpoints_report_usercount');
32 define('USERPOINTS_REPORT_LIMIT', 'userpoints_report_limit');
33 define('USERPOINTS_REPORT_DISPLAYZERO', 'userpoints_report_displayzero');
34
35 define('USERPOINTS_CATEGORY_NAME', 'Userpoints');
36 define('USERPOINTS_CATEGORY_DEFAULT_VID', 'userpoints_category_default_vid');
37 define('USERPOINTS_CATEGORY_DEFAULT_TID', 'userpoints_category_default_tid');
38
39 /**
40 * Purpose: Returns an array of common translation placeholders
41 */
42 function userpoints_translation() {
43 static $trans;
44
45 if (!isset($trans)) {
46 $trans = array(
47 '!Points' => variable_get(USERPOINTS_TRANS_UCPOINTS, 'Points'),
48 '!points' => variable_get(USERPOINTS_TRANS_LCPOINTS, 'points'),
49 '!point' => variable_get(USERPOINTS_TRANS_LCPOINT, 'point'),
50 '!Uncategorized' => variable_get(USERPOINTS_TRANS_UNCAT, 'Uncategorized'),
51 );
52 }
53 return $trans;
54 }
55
56 /*
57 * Purpose: Returns an array of possible transaction statuses
58 */
59 function userpoints_txn_status() {
60 return array(
61 USERPOINTS_TXN_STATUS_APPROVED => t('Approved'),
62 USERPOINTS_TXN_STATUS_PENDING => t('Pending'),
63 USERPOINTS_TXN_STATUS_DECLINED => t('Declined'),
64 );
65 }
66
67 /**
68 * Implementation of hook_help().
69 */
70 function userpoints_help($section) {
71 switch ($section) {
72 case 'admin/settings/userpoints':
73 $output = t('Configure userpoints moderation and branding translation', userpoints_translation());
74 break;
75 case 'admin/help#userpoints':
76 $output = t('Users earn !points as they post nodes, comments, and vote on nodes', userpoints_translation());
77 }
78 return $output;
79 }
80
81 /**
82 * Implementation of hook_menu().
83 */
84 function userpoints_menu() {
85 $items = array();
86 $items['admin/settings/userpoints'] = array(
87 'title' => '!Points settings',
88 'title arguments' => userpoints_translation(),
89 'page callback' => 'drupal_get_form',
90 'page arguments' => array('userpoints_admin_settings'),
91 'access arguments' => array(USERPOINTS_PERM_ADMIN),
92 'type' => MENU_NORMAL_ITEM
93 );
94 $items['admin/user/userpoints'] = array(
95 'title' => '!Points',
96 'title arguments' => userpoints_translation(),
97 'description' => 'Manage !points',
98 'page callback' => 'userpoints_admin_points',
99 'access arguments' => array(USERPOINTS_PERM_ADMIN)
100 );
101 $items['admin/user/userpoints/list'] = array(
102 'title' => 'List',
103 'title arguments' => userpoints_translation(),
104 'description' => 'List users by points',
105 'access arguments' => array(USERPOINTS_PERM_VIEW),
106 'type' => MENU_DEFAULT_LOCAL_TASK,
107 'weight' => -2,
108 );
109 $items['admin/user/userpoints/moderate'] = array(
110 'title' => 'Moderation',
111 'title arguments' => userpoints_translation(),
112 'description' => 'Review points in moderation',
113 'page callback' => 'userpoints_admin_points',
114 'access arguments' => array(USERPOINTS_PERM_ADMIN),
115 'type' => MENU_LOCAL_TASK,
116 'weight' => -1,
117 );
118 $items['admin/user/userpoints/add'] = array(
119 'title' => 'Add',
120 'description' => 'Admin add/delete userpoints',
121 'page callback' => 'drupal_get_form',
122 'page arguments' => array('userpoints_admin_txn'),
123 'access arguments' => array(USERPOINTS_PERM_ADMIN),
124 'type' => MENU_LOCAL_TASK,
125 'weight' => 0,
126 );
127 $items['admin/user/userpoints/edit'] = array(
128 'title' => 'Edit',
129 'page callback' => 'drupal_get_form',
130 'page arguments' => array('userpoints_admin_txn'),
131 'access arguments' => array(USERPOINTS_PERM_ADMIN),
132 'type' => MENU_CALLBACK
133 );
134
135 $items['admin/user/userpoints/approve'] = array(
136 'title' => 'Approve Userpoints',
137 'page callback' => 'userpoints_admin_approve',
138 'access arguments' => array(USERPOINTS_PERM_ADMIN),
139 'type' => MENU_CALLBACK
140 );
141 $items['admin/user/userpoints/decline'] = array(
142 'title' => 'Approve Userpoints',
143 'page callback' => 'userpoints_admin_approve',
144 'access arguments' => array(USERPOINTS_PERM_ADMIN),
145 'type' => MENU_CALLBACK
146 );
147
148 $items['userpoints'] = array(
149 'title' => 'Users by !points',
150 'title arguments' => userpoints_translation(),
151 'page callback' => 'userpoints_list_users',
152 'access' => array(USERPOINTS_PERM_VIEW),
153 'type' => MENU_NORMAL_ITEM,
154 );
155
156 $items['myuserpoints'] = array(
157 'title' => 'My !points',
158 'title arguments' => userpoints_translation(),
159 'page callback' => 'userpoints_my_userpoints',
160 'access callback' => 'userpoints_access_my_points',
161 'type' => MENU_NORMAL_ITEM
162 );
163 return $items;
164 }
165
166 /**
167 * Checks if user can access their points - used via hook_menu().
168 *
169 * @return true if user has permissions to view userpoints and if the user is logged in
170 */
171 function userpoints_access_my_points() {
172 global $user;
173 return (user_access(USERPOINTS_PERM_VIEW) && user_is_logged_in());
174 }
175
176 /**
177 * Implementation of hook_perm().
178 */
179 function userpoints_perm() {
180 return array(USERPOINTS_PERM_VIEW, USERPOINTS_PERM_ADMIN);
181 }
182
183 /**
184 * Implementation of hook_theme().
185 */
186 function userpoints_theme() {
187 $themes = array();
188 $themes['userpoints_list_users'] = array(
189 'arguments' => array(
190 'header',
191 'rows',
192 'tid',
193 'pager_limit',
194 ),
195 );
196 $themes['userpoints_list_users_header'] = array(
197 );
198 $themes['userpoints_list_users_row'] = array(
199 'arguments' => array(
200 'row'
201 ),
202 );
203 $themes['userpoints_my_userpoints'] = array(
204 'arguments' => array(
205 'args',
206 'header',
207 'rows',
208 ),
209 );
210 return $themes;
211 }
212
213 /**
214 * menu callback for settings form.
215 */
216 function userpoints_admin_settings() {
217 $form = array();
218 $group = 'status';
219 $form[$group] = array(
220 '#type' => 'fieldset',
221 '#title' => t('Moderation'),
222 '#collapsible' => TRUE,
223 '#collapsed' => TRUE,
224 '#weight' => -1,
225 );
226
227 $form[$group][USERPOINTS_POINTS_MODERATION] = array(
228 '#type' => 'radios',
229 '#title' => t('Transaction status'),
230 '#default_value' => variable_get(USERPOINTS_POINTS_MODERATION, 0),
231 '#options' => array(t('Approved'), t('Moderated')),
232 '#description' => t('Select whether all !points should be approved automatically, or moderated, and require admin approval', userpoints_translation()),
233 );
234
235 $group = 'renaming';
236 $form[$group] = array(
237 '#type' => 'fieldset',
238 '#collapsible' => TRUE,
239 '#collapsed' => TRUE,
240 '#title' => t('Points branding'),
241 );
242
243 $form[$group][USERPOINTS_TRANS_UCPOINTS] = array(
244 '#type' => 'textfield',
245 '#title' => t('Word to use in the interface for the upper case plural word !Points', userpoints_translation()),
246 '#default_value' => variable_get(USERPOINTS_TRANS_UCPOINTS, 'Points'),
247 '#size' => 20,
248 '#maxlength' => 20,
249 );
250
251 $form[$group][USERPOINTS_TRANS_LCPOINTS] = array(
252 '#type' => 'textfield',
253 '#title' => t('Word to use in the interface for the lower case plural word !points', userpoints_translation()),
254 '#default_value' => variable_get(USERPOINTS_TRANS_LCPOINTS, 'points'),
255 '#size' => 20,
256 '#maxlength' => 20,
257 );
258
259 $form[$group][USERPOINTS_TRANS_LCPOINT] = array(
260 '#type' => 'textfield',
261 '#title' => t('Word to use in the interface for the lower case singular word !point', userpoints_translation()),
262 '#default_value' => variable_get(USERPOINTS_TRANS_LCPOINT, 'point'),
263 '#size' => 20,
264 '#maxlength' => 20,
265 );
266 $form[$group][USERPOINTS_TRANS_UNCAT] = array(
267 '#type' => 'textfield',
268 '#title' => t('Word to use for the uncategorized category'),
269 '#default_value' => variable_get(USERPOINTS_TRANS_UNCAT, 'Uncategorized'),
270 '#size' => 20,
271 '#maxlength' => 20,
272 );
273 $group = "Points expiration";
274 $form[$group] = array(
275 '#type' => 'fieldset',
276 '#collapsible' => TRUE,
277 '#collapsed' => TRUE,
278 '#title' => t('!Points expiration', userpoints_translation()),
279 '#description' => t('These settings affect new points only, they are not retroactive!
280 Point expiration depends upon cron.
281 '),
282 );
283
284 $form[$group][USERPOINTS_EXPIREAFTER_DATE] = array(
285 '#type' => 'select',
286 '#title' => t('Expire !points after', userpoints_translation()),
287 '#description' => t('Once points have been obtained by the user
288 they will expire according to this setting'),
289 '#options' => expiry_dates(),
290 '#default_value' => variable_get(USERPOINTS_EXPIREAFTER_DATE, NULL),
291 );
292
293 /**
294 * If the expiration date is earlier than today
295 * new points will last forever. Although this may be desirable
296 * it could also be an oversight so we'll display a message
297 * to the administrator
298 *
299 */
300 $warning="";
301 if (userpoints_date_to_timestamp(variable_get(USERPOINTS_EXPIREON_DATE, array('day' => 1, 'month' => 1, 'year' => 1900))) < time()) {
302 $warning = '<br /><strong>'. t('This setting will not take affect, date must be in the future') .'</strong>';
303 }
304
305 $form[$group][USERPOINTS_EXPIREON_DATE] = array(
306 '#type' => 'date',
307 '#title' => t('Expire !points on this date', userpoints_translation()),
308 '#description' => t('Once points have been obtained by the user they will
309 last until this date. This setting overrides the
310 "Expire after setting" above'. $warning),
311 '#default_value' => variable_get(USERPOINTS_EXPIREON_DATE, array('day' => 1, 'month' => 1, 'year' => 1980)),
312 );
313 $form[$group][USERPOINTS_EXPIRY_DESCRIPTION] = array(
314 '#type' => 'textarea',
315 '#title' => t('Expiration entry description'),
316 '#description' => t('A negating expiration entry is made to expire
317 points leaving the original entry intact
318 (e.g. original points + expiration points = 0).
319 When the expiration entry is made this description will
320 be placed on the entry. This is useful so the users will
321 know what happened to their point balance. In crafting
322 your message you can use the following variables.
323 <br /> !points = The name used in branding
324 above (also use !Points and !point)
325 <br />!operation = Original operation that granted the points
326 <br/> !description = Original description for the point
327 <br /> !txn_id Original transaction ID
328 <br /> !date = Date of the original entry'),
329 '#default_value' => variable_get(USERPOINTS_EXPIRY_DESCRIPTION, ''),
330 );
331
332 $group = "misc";
333 $form[$group] = array(
334 '#type' => 'fieldset',
335 '#collapsible' => TRUE,
336 '#collapsed' => TRUE,
337 '#title' => t('Messages'),
338 '#description' => t('Control the behavior of messages users see. '),
339 );
340
341 $form[$group][USERPOINTS_DISPLAY_MESSAGE] = array(
342 '#type' => 'radios',
343 '#title' => t('Display message'),
344 '#default_value' => variable_get(USERPOINTS_DISPLAY_MESSAGE, 1),
345 '#options' => array(0 => t('No'), 1 => t('Yes')),
346 '#description' => t('Determines if a message should be displayed whenever !points are awarded/substracted ', userpoints_translation()),
347 );
348 $group = "reports";
349 $form[$group] = array(
350 '#type' => 'fieldset',
351 '#collapsible' => TRUE,
352 '#collapsed' => TRUE,
353 '#title' => t('Report Settings'),
354 '#description' => t(''),
355 );
356
357 $form[$group][USERPOINTS_REPORT_LIMIT] = array(
358 '#type' => 'select',
359 '#title' => t('Transactions per page'),
360 '#default_value' => variable_get(USERPOINTS_REPORT_LIMIT, 10),
361 '#options' => array(10 => 10, 20 => 20, 30 => 30, 40 => 40, 50 => 50, 100 => 100),
362 '#description' => t('Limits the number of transactions displayed per page'),
363 );
364 $form[$group][USERPOINTS_REPORT_DISPLAYZERO] = array(
365 '#type' => 'radios',
366 '#title' => t('Display zero !point users?', userpoints_translation()),
367 '#default_value' => variable_get(USERPOINTS_REPORT_DISPLAYZERO, 1),
368 '#options' => array(t('No'), t('Yes')),
369 '#description' => t('If set to "No" users with zero !points will not be displayed in the reports ', userpoints_translation()),
370 );
371 $form[$group][USERPOINTS_REPORT_USERCOUNT] = array(
372 '#type' => 'select',
373 '#title' => t('Users per page'),
374 '#default_value' => variable_get(USERPOINTS_REPORT_USERCOUNT, 30),
375 '#options' => array(10 => 10, 20 => 20, 30 => 30, 40 => 40, 50 => 50, 100 => 100),
376 '#description' => t('When listing !points by user limit how many users are displayed on a single page', userpoints_translation()),
377 );
378
379
380 /* Categories will only appear if the taxonomy module is enabled as
381 * the module is required for this functionality but not necessarily
382 * a requirement for the module.
383 */
384 if (module_exists('taxonomy')) {
385 $group = 'category';
386 $form[$group] = array(
387 '#type' => 'fieldset',
388 '#collapsible' => TRUE,
389 '#collapsed' => TRUE,
390 '#title' => t('!Points Categorization', userpoints_translation()),
391 );
392 $form[$group][USERPOINTS_CATEGORY_DEFAULT_TID] = array(
393 '#type' => 'select',
394 '#title' => t('Default Category'),
395 '#default_value' => variable_get(USERPOINTS_CATEGORY_DEFAULT_TID, NULL),
396 '#options' => userpoints_get_categories(),
397 '#description' => t('By default all points are assigned to this category. You can modify what categories are available by modifying the <a href="!url">Userpoints taxonomy</a>',
398 array('!url' => url('admin/content/taxonomy/'. variable_get(USERPOINTS_CATEGORY_DEFAULT_VID, '')))),
399 );
400 }
401
402 $form['setting'] = module_invoke_all('userpoints', 'setting');
403 return system_settings_form($form);
404 }
405
406 /**
407 * @param uid: user id of the user to get or lose the points
408 *
409 * @return number of current points in that user's account
410 */
411 function userpoints_get_current_points($uid = NULL, $tid = NULL) {
412 if (!$uid) {
413 global $user;
414 $uid = $user->uid;
415 }
416 if (!$tid) {
417 $tid = userpoints_get_default_tid();
418 }
419 elseif ($tid == 'all') {
420 return (int)db_result(db_query('SELECT SUM(points) FROM {userpoints} WHERE uid = %d', $uid));
421 }
422 return (int)db_result(db_query('SELECT points FROM {userpoints} WHERE uid = %d AND tid = %d', $uid, $tid));
423 }
424
425 /**
426 * @param uid: user id of the user to get or lose the points
427 *
428 * @return number of max points in that user's account
429 */
430 function userpoints_get_max_points($uid = NULL, $tid = NULL) {
431 if (!$uid) {
432 global $user;
433 $uid = $user->uid;
434 }
435 if (!$tid) {
436 $tid = userpoints_get_default_tid();
437 }
438 elseif ($tid == 'all') {
439 return (int)db_result(db_query('SELECT SUM(max_points) FROM {userpoints} WHERE uid = %d', $uid));
440 }
441 return (int)db_result(db_query('SELECT max_points FROM {userpoints} WHERE uid = %d AND tid = %d', $uid, $tid));
442 }
443
444 /**
445 * @param $params(array) or (int)
446 * if (int) assumed to be points for current user
447 * Accepts an array of keyed variables and parameters
448 * 'points' => # of points (int) (required)
449 * 'moderate' => TRUE/FALSE
450 * 'uid' => $user->uid
451 * 'operation' => 'published' 'moderated' etc.
452 * 'tid' => 'category ID'
453 * 'expirydate' => timestamp or 0, 0 = non-expiring; NULL = site default
454 * 'description' => 'description'
455 * 'reference' => reserved for module specific use
456 * 'display' => whether or not to display "points awarded" message
457 * 'txn_id' => Transaction ID of points, If present an UPDATE is performed
458 * 'entity_id' => ID of an entity in the Database. ex. $node->id or $user->uid
459 * 'entity_type' => string of the entity type. ex. 'node' or 'user' NOT 'node-content-custom'
460 *
461 * @return array with status and reason.
462 * 'status' => FALSE when no action is take, TRUE when points are credited or debited
463 * 'reason' => (string) error message to indicate reason for failure
464 */
465 function userpoints_userpointsapi($params) {
466
467 //Test for the existence of parameters and set defaults if necessary
468 if (!isset($params['txn_id'])) {
469 //If a txn_id is passed in we'll do an UPDATE thus the std check don't apply
470 if (is_numeric($params)) {
471 $points = $params;
472 $params = array();
473 $params['points'] = $points;
474 unset($points);
475 }
476 if (!is_array($params)) {
477 //has to be an array to continue
478 return array(
479 'status' => false,
480 'reason' => 'Parameters did not properly form as an array,
481 this is an internal module error.
482 ',
483 );
484 }
485 if (!isset($params['uid'])) {
486 global $user;
487 $params['uid'] = $user->uid;
488 }
489 if (!isset($params['operation'])) {
490 $params['operation'] = NULL;
491 }
492 if (!isset($params['description'])) {
493 $params['description'] = NULL;
494 }
495 if (!isset($params['reference'])) {
496 $params['reference'] = NULL;
497 }
498 if (!isset($params['display'])) {
499 $params['display'] = NULL;
500 }
501 if (!isset($params['moderate'])) {
502 //if not passed then site default is used
503 $params['status'] = variable_get(USERPOINTS_POINTS_MODERATION, 0);
504 }
505 else {
506 if ($params['moderate'] == true) {
507 $params['status'] = 1;
508 }
509 else {
510 $params['status'] = 0;
511 }
512 }
513 if (!isset($params['tid']) || !is_numeric($params['tid'])) {
514 //if not passed then site default is used
515 $params['tid'] = variable_get(USERPOINTS_CATEGORY_DEFAULT_TID, NULL);
516 }
517 if (!isset($params['entity_id'])) {
518 $params['entity_id'] = NULL;
519 }
520 if (!isset($params['entity_type'])) {
521 $params['entity_type'] = NULL;
522 }
523 // anonymous users do not get points, and there have to be points to process
524 if (($params['uid'] == 0 || $params['points'] == 0)) {
525 return array(
526 'status' => false,
527 'reason' => 'uid or points = 0. Anonymous users do not get points
528 and there must be points to process.
529 ',
530 );
531 }
532 }
533 else {
534 //We have a txn_id so we can look up some user information
535 $sql = "SELECT uid from {userpoints_txn} WHERE txn_id = %d";
536 $params['uid'] = db_result(db_query($sql, $params['txn_id']));
537 } //if txn_id
538
539 // Load the user object that will be awarded the points
540 $account = user_load(array('uid' => $params['uid']));
541
542 // Call the _userpoints hook, and stop if one of them returns FALSE
543 $rc = module_invoke_all('userpoints', 'points before', $params['points'], $account->uid, $params['event']);
544
545 foreach ($rc as $key => $value) {
546 if ($value == FALSE) {
547 // Do not process the points
548 return array(
549 'status' => false,
550 'reason' => t('%key returned false from the hook_userpoints points before call', array('%key' => $key)),
551 );
552 }
553 }
554 if ($params['points'] < 0) {
555 $msg = t('lost');
556 }
557 elseif ($params['status'] == 2) {
558 //points have been declined
559 $msg = t('was declined');
560 }
561 else {
562 $msg = t('earned');
563 }
564
565
566 $ret = _userpoints_transaction($params);
567 if ($ret == false) {
568 return array(
569 'status' => false,
570 'reason' => 'transaction failed in _userpoints_transaction, this is an internal module error',
571 );
572 }
573
574 if ($params['status'] == 1) {
575 $mesg = (t('User %uname %op %pointsvalue !points, pending administrator approval.',
576 array_merge(userpoints_translation(), array(
577 '%uname' => $account->name,
578 '%op' => $msg,
579 '%pointsvalue' => abs($params['points']),
580 '%total' => userpoints_get_current_points($params['uid'], $params['tid'])
581 ))));
582 }
583 else {
584
585 $mesg = (t('User %uname %op %pointsvalue !points! Total now is %total points.',
586 array_merge(userpoints_translation(), array(
587 '%uname' => $account->name,
588 '%op' => $msg,
589 '%pointsvalue' => abs($params['points']),
590 '%total' => userpoints_get_current_points($params['uid'], $params['tid'])
591 ))));
592 } //if $params['status']
593
594 if ($mesg && ($params['display'] || ($params['display'] === null && variable_get(USERPOINTS_DISPLAY_MESSAGE, 1) == 1))) {
595 drupal_set_message($mesg);
596 }
597 // Call the _userpoints hook to allow modules to act after points are awarded
598 module_invoke_all('userpoints', 'points after', $params['points'], $account->uid, $params['operation']);
599 return array(
600 'status' => true,
601 );
602 }
603
604 /*
605 * Adds the points to the txn table
606 * PRIVATE FUNCTION use userpoints_userpointsapi!
607 */
608 function _userpoints_transaction(&$params) {
609 //Check, again, for a properly formed array
610 if (!is_array($params)) {
611 return false;
612 }
613 if (!isset($params['txn_id'])) {
614 //If a txn_id is preset we UPDATE the record instead of adding one
615 //the standard checks don't apply
616 if (!is_numeric($params['points'])) {
617 return false;
618 }
619 if (!isset($params['uid'])) {
620 global $user;
621 $params['uid'] = $user->uid;
622 //there must be a UID, anonymous does not receive points
623 if (!$params['uid'] > 0) {
624 return false;
625 }
626 }
627 if (!isset($params['moderate'])) {
628 //if not passed then site default is used
629 $params['status'] = variable_get(USERPOINTS_POINTS_MODERATION, 0);
630 }
631 else {
632 if ($params['moderate'] == true) {
633 $params['status'] = 1;
634 }
635 else {
636 $params['status'] = 0;
637 }
638 }
639 if (!isset($params['operation'])) {
640 $params['operation'] = NULL;
641 }
642 if (!isset($params['description'])) {
643 $params['description'] = NULL;
644 }
645 if (!isset($params['reference'])) {
646 $params['reference'] = NULL;
647 }
648 if (!isset($params['tid']) || !is_numeric($params['tid'])) {
649 $params['tid'] = variable_get(USERPOINTS_CATEGORY_DEFAULT_TID, NULL);
650 }
651 elseif ($params['tid'] == 0) {
652 //tid with 0 are uncategorized and are set to NULL
653 //this is a backwards compatibilty issue
654 $params['tid'] = NULL;
655 }
656 if (!isset($params['expirydate'])) {
657 $params['expirydate'] = userpoints_get_default_expiry_date();
658 }
659 if (!isset($params['expired'])) {
660 $params['expired'] = NULL;
661 }
662 if (!isset($params['parent_txn_id'])) {
663 $params['parent_txn_id'] = NULL;
664 }
665 if (!isset($params['entity_id'])) {
666 $params['entity_id'] = NULL;
667 }
668 if (!isset($params['entity_type'])) {
669 $params['entity_type'] = NULL;
670 }
671 } // if txn_id
672 if (is_numeric($params['txn_id'])) {
673 //A transaction ID was passed in so we'll update the transaction
674 $result = db_query("SELECT txn_id, uid, approver_uid, points,
675 time_stamp, status, operation, description, reference, expirydate, expired,
676 parent_txn_id, tid, entity_id, entity_type
677 FROM {userpoints_txn}
678 WHERE txn_id = %d",
679 $params['txn_id']);
680 $txn = db_fetch_array($result);
681 foreach ($txn as $key => $value) {
682 if (isset($params[$key])) {
683 $arr[] = $key .' = \''. $params[$key] .'\'';
684 }
685 else {
686 $params[$key] = $value;
687 }
688 }
689
690 db_query('UPDATE {userpoints_txn} SET '. implode(', ', $arr) .'
691 WHERE txn_id = %d',
692 $params['txn_id']
693 );
694 _userpoints_update_cache($params);
695 }
696 else {
697 $ret = db_query("INSERT INTO {userpoints_txn}
698 (uid, points, time_stamp, status, operation, description,
699 reference, expirydate, expired, parent_txn_id, tid, entity_id, entity_type)
700 VALUES (%d, %d, %d, %d, '%s', '%s', '%s', %d, %d, %d, %d, %d, '%s')",
701 $params['uid'],
702 $params['points'],
703 time(),
704 $params['status'],
705 $params['operation'],
706 $params['description'],
707 $params['reference'],
708 $params['expirydate'],
709 $params['expired'],
710 $params['parent_txn_id'],
711 $params['tid'],
712 $params['entity_id'],
713 $params['entity_type']
714 );
715 if ($params['status'] != true && $ret != false) {
716 _userpoints_update_cache($params);
717 }
718 }
719 return TRUE;
720 } //function userpoints_transaction
721
722 /*
723 * Update the caching table
724 */
725 function _userpoints_update_cache(&$params) {
726 if ( $params['status'] != 0 || $params['expired'] == 1) {
727 //Only update the cache for fully approved non-expired points
728 return false;
729 }
730 if (!isset($params['tid'])) {
731 $params['tid'] = NULL;
732 }
733
734 // Calculate the current points based upon the tid
735 $current_points = (int)$params['points'] + userpoints_get_current_points($params['uid'], $params['tid']);
736 //Grab the user's maximum points to preserve it
737 $max_points = db_result(db_query('SELECT max_points FROM {userpoints} WHERE uid = %d AND tid = %d',
738 $params['uid'], $params['tid']));
739 if ($params['points'] > 0) {
740 //points are greater than zero, update their max_points
741 $max_points = (int)$params['points'] + (int)$max_points;
742 }
743
744 // insert or update the userpoints caching table with the user's current points
745 if (_userpoints_user_exists($params['uid'], $params['tid'])) {
746 db_query("UPDATE {userpoints}
747 SET points = %d, max_points = %d, last_update = %d
748 WHERE uid = %d AND tid = %d",
749 $current_points,
750 $max_points,
751 time(),
752 $params['uid'],
753 $params['tid']
754 );
755 }
756 else {
757 $result = db_query("INSERT INTO {userpoints}
758 (uid, points, max_points, last_update, tid)
759 VALUES (%d, %d, %d, %d, %d )",
760 $params['uid'],
761 $current_points,
762 $max_points,
763 time(),
764 $params['tid']
765 );
766 }
767 unset($params);
768 }
769
770
771 /* Purpose: Determines the correct default expiration date
772 * Returns: timestamp
773 */
774 function userpoints_get_default_expiry_date() {
775 $expirydate = userpoints_date_to_timestamp(variable_get(USERPOINTS_EXPIREON_DATE, NULL));
776 if ($expirydate < time()) {
777 $expirydate = variable_get(USERPOINTS_EXPIREAFTER_DATE, NULL);
778 if ($expirydate) {
779 $expirydate = time() + $expirydate;
780 }
781 }
782 return $expirydate;
783 } //userpoints_get_default_expiry_date
784
785 /*
786 * Purpose: Checks to ensure that a user exists corresponding to a category
787 * @param $uid User ID to check for existence of points for the user
788 * @param $tid taxonomy id of the category to limit to, if omitted
789 * if the use has points in any category the return is true
790 * Returns : true if user found, falase otherwise
791 */
792 function _userpoints_user_exists($uid, $tid = NULL) {
793 if ( is_numeric($tid) ) {
794 return (int)db_result(
795 db_query('SELECT COUNT(uid)
796 FROM {userpoints}
797 WHERE uid = %d AND tid = %d ',
798 $uid, $tid));
799 }
800 else {
801 return (int)db_result(
802 db_query('SELECT COUNT(uid)
803 FROM {userpoints}
804 WHERE uid = %d',
805 $uid ));
806
807 }
808 }
809
810 function userpoints_user($op, &$edit, &$account, $category = '') {
811 switch ($op) {
812 case 'delete':
813 // The user is being deleted, delete all traces in userpoints and txn tables
814 db_query('DELETE FROM {userpoints} WHERE uid = %d', $account->uid);
815 db_query('DELETE FROM {userpoints_txn} WHERE uid = %d', $account->uid);
816 break;
817
818 case 'view':
819 // Get the points for the user
820 $points = userpoints_get_current_points($account->uid);
821 if (user_access(USERPOINTS_PERM_ADMIN)) {
822 $points = l($points, 'admin/user/userpoints/add/'. $account->uid, array('title' => t('Manage points')));
823 }
824 if (user_access(USERPOINTS_PERM_VIEW)) {
825 $disp_points[] = array(
826 'title' => t('User !points', userpoints_translation()),
827 'value' => $points,
828 );
829 return array(t('!Points', userpoints_translation()) => $disp_points);
830 }
831 break;
832 }
833 }
834
835 function userpoints_admin_manage() {
836 $tid = arg(4);
837 $cat_count = count(userpoints_get_categories());
838
839 $header = array(
840 array('data' => t('User'), 'field' => 'uid', 'sort' => 'desc'),
841 array('data' => t('Time stamp'), 'field' => 'time_stamp'),
842 array('data' => t('!Points', userpoints_translation()), 'field' => 'points'),
843 array('data' => t('Operation'), 'field' => 'operation'),
844 array('data' => t('Category'), 'field' => 'cat'),
845 array('data' => t('Operation')),
846 );
847
848 $sql = "SELECT p.txn_id, p.uid, p.time_stamp, p.points, p.operation, p.status,
849 p.entity_type, p.entity_id, t.name as cat
850 FROM {userpoints_txn} p
851 LEFT JOIN {term_data} t ON p.tid = t.tid
852 WHERE p.status = %d";
853
854 //Check for filtering
855 if (is_numeric($tid) && $tid == 0) {
856 $sql .= " AND (p.tid IS NULL OR p.tid = '')";
857 $cat = t('!Uncategorized', userpoints_translation());
858 }
859 elseif (is_numeric($tid)) {
860 $sql .= " AND p.tid = %d";
861 $cat = db_result(db_query("SELECT name from {term_data} WHERE tid = %d", $tid));
862 }
863 else {
864 $cat = t('All');
865 }
866
867 //Set the title of the page
868 drupal_set_title(t($cat) ." ". t("!points", userpoints_translation()));
869
870 $sql .= tablesort_sql($header);
871 $pager_limit = variable_get(USERPOINTS_REPORT_USERCOUNT, 30);
872 $result = pager_query($sql, $pager_limit, 0, NULL, USERPOINTS_TXN_STATUS_PENDING, $tid);
873 while ($data = db_fetch_object($result)) {
874 $user = user_load(array('uid' => $data->uid));
875 if (!$data->cat) {
876 $data->cat = t('!Uncategorized', userpoints_translation());
877 }
878 $operation = module_invoke_all('userpoints', 'entity_type', $data);
879
880 if (!$operation) {
881 switch ($data->entity_type) {
882 case 'node' :
883 $node = node_load($data->entity_id);
884 if ($node) {
885 $operation = l($data->operation, 'node/'. $node->nid, array('title' => $node->title));
886 }
887 else {
888 $operation = $data->operation;
889 }
890 break;
891 case 'comment' :
892 if (module_exists('comment')) {
893 //We have to load the comment to get the nid for the comment
894 $comment = _comment_load($data->entity_id);
895 if ($comment) {
896 $operation = l($data->operation, 'node/'. $comment->nid, array('title' => $comment->subject), NULL, 'comment-'. $comment->cid);
897 }
898 else {
899 $operation = $data->operation;
900 }
901 }
902 break;
903 default:
904 $operation = $data->operation;
905 }
906 }
907 $rows[] = array(
908 array('data' => theme('username', $user)),
909 array('data' => format_date($data->time_stamp, 'custom', 'Y-m-d H:i')),
910 array('data' => $data->points, 'align' => 'right'),
911 array('data' => $operation),
912 array('data' => $data->cat),
913 array('data' => l('approve', "admin/user/userpoints/approve/$data->txn_id") .
914 ' '. l('decline', "admin/user/userpoints/decline/$data->txn_id") .
915 ' '. l('edit', "admin/user/userpoints/edit/$data->txn_id")
916 ),
917 );
918 }
919 if (!$rows) {
920 //no points in moderation
921 $rows[] = array(array('data' => t('No !points awaiting moderation', userpoints_translation()),
922 'colspan' => 6, 'align' => 'center')
923 ); //$rows[]
924 }
925
926 if ($cat_count > 1) {
927 $output = drupal_get_form('userpoints_filter_cat_select', 'admin/user/userpoints/moderate/', arg(4));
928 $output .= theme('table', $header, $rows);
929 $output .= theme('pager', NULL, $pager_limit, 0);
930 }
931 else {
932 $output = theme('table', $header, $rows);
933 $output .= theme('pager', NULL, $pager_limit, 0);
934 }
935 return $output;
936 }
937
938 /*
939 * Purpose: Approves moderated points
940 */
941 function userpoints_admin_approve() {
942 $operation = arg(3);
943 $txn_id = (int)arg(4);
944 return drupal_get_form('userpoints_confirm_approve', $operation, $txn_id);
945 }
946
947 function userpoints_confirm_approve($operation, $txn_id) {
948 $form = array(
949 'operation' => array(
950 '#type' => 'value',
951 '#value' => $operation,
952 ),
953 'txn_id' => array(
954 '#type' => 'value',
955 '#value' => $txn_id,
956 ),
957 );
958
959 return confirm_form(
960 $form,
961 t('Are you sure you want to @op txn @txn_id', array('@op' => $operation, '@txn_id' => $txn_id)),
962 'admin/user/userpoints/moderate'
963 );
964 }
965
966 function userpoints_confirm_approve_submit($form, &$form_state) {
967 global $user;
968
969 $form_values = $form_state['values'];
970
971 switch ($form_state['clicked_button']['#value']) {
972 case 'approve':
973 $status = USERPOINTS_TXN_STATUS_APPROVED;
974 break;
975 case 'decline':
976 $status = USERPOINTS_TXN_STATUS_DECLINED;
977 break;
978 default :
979 return false;
980 }
981
982 $params = array(
983 'txn_id' => $form_values['txn_id'],
984 'approver_uid' => $user->uid,
985 'status' => $status,
986 );
987
988 userpoints_userpointsapi($params);
989
990 $form_state['redirect'] = 'admin/user/userpoints/moderate';
991 }
992
993 function userpoints_admin_txn($form_state) {
994 global $user;
995
996 $mode = arg(3);
997
998 $timestamp = format_date(time(), 'custom', 'Y-m-d H:i O');
999
1000 if ($mode == 'edit' && arg(4)) {
1001 $txn_id = (int)arg(4);
1002 $result = db_query('SELECT * FROM {userpoints_txn} WHERE txn_id = %d', $txn_id);
1003 $txn = db_fetch_object($result);
1004 $timestamp = format_date($txn->time_stamp, 'custom', 'Y-m-d H:i O');
1005 $txn_user = user_load(array('uid' => $txn->uid));
1006 }
1007 elseif ($mode == 'add' && arg(4)) {
1008 $uid = (int)arg(4);
1009 $txn_user = user_load(array('uid' => $uid));
1010 }
1011
1012 $form['txn_user'] = array(
1013 '#type' => 'textfield',
1014 '#title' => t('User Name'),
1015 '#size' => 30,
1016 '#maxlength' => 60,
1017 '#default_value' => $txn_user->name,
1018 '#autocomplete_path' => 'user/autocomplete',
1019 '#description' => t('User Name for the user you want the points to affect'),
1020 );
1021
1022 $form['points'] = array(
1023 '#type' => 'textfield',
1024 '#title' => t('Points'),
1025 '#size' => 10,
1026 '#maxlength' => 10,
1027 '#default_value' => $txn->points,
1028 '#description' => t('Number of points to add/subtract from the user. For example, 25 (to add points) or -25 (to subtract points).'),
1029 );
1030
1031 $form['time_stamp'] = array(
1032 '#type' => 'textfield',
1033 '#title' => t('Date/Time'),
1034 '#default_value' => $timestamp,
1035 '#size' => 30,
1036 '#maxlength' => 30,
1037 '#description' => t('Date and time of this transaction, in the form YYYY-MM-DD HH:MM +ZZZZ'),
1038 );
1039
1040 if ($txn->txn_id) {
1041 if ($txn->expirydate > 0) {
1042 $expirydate = format_date($txn->expirydate, 'custom', 'Y-m-d H:i O');
1043 }
1044 }
1045 else {
1046 //If we're not editing we use site defaults
1047 $expirydate = userpoints_get_default_expiry_date();
1048 if ($expirydate) {
1049 $expirydate = format_date($expirydate, 'custom', 'Y-m-d H:i O');
1050 }
1051 }
1052 $form['expirydate'] = array(
1053 '#type' => 'textfield',
1054 '#title' => t('Expiration date'),
1055 '#default_value' => $expirydate,
1056 '#size' => 30,
1057 '#maxlength' => 30,
1058 '#description' => t('Date and time to expire these points, in the form YYYY-MM-DD HH:MM +ZZZZ') .
1059 '<br/>'. t('Leave blank for non-expiring points'),
1060 );
1061 if (module_exists('taxonomy')) {
1062 $form['tid'] = array(
1063 '#type' => 'select',
1064 '#title' => t('Category'),
1065 '#default_value' => variable_get(USERPOINTS_CATEGORY_DEFAULT_TID, 0),
1066 '#options' => userpoints_get_categories(),
1067 '#description' => t('Category to apply these points to'),
1068 );
1069 }
1070
1071 $form['reference'] = array(
1072 '#type' => 'textfield',
1073 '#title' => t('Reference'),
1074 '#default_value' => $txn->reference,
1075 '#size' => 30,
1076 '#maxlength' => 128,
1077 '#description' => t('Enter optional reference for this transaction. This field will be indexed and searchable.'),
1078 );
1079
1080 $form['description'] = array(
1081 '#type' => 'textarea',
1082 '#title' => t('Description'),
1083 '#default_value' => $txn->description,
1084 '#width' => 70,
1085 '#lines' => 5,
1086 '#description' => t('Enter an optional description for this transaction, such as the reason it is created.'),
1087 );
1088
1089
1090 switch ($mode) {
1091 case 'add':
1092 $form['approver_uid'] = array(
1093 '#type' => 'hidden',
1094 '#value' => $user->uid,
1095 );
1096
1097 $form['operation'] = array(
1098 '#type' => 'hidden',
1099 '#value' => 'admin',
1100 );
1101
1102 $form['status'] = array(
1103 '#type' => 'hidden',
1104 '#value' => USERPOINTS_TXN_STATUS_PENDING,
1105 );
1106
1107 $form['mode'] = array(
1108 '#type' => 'hidden',
1109 '#value' => $mode,
1110 );
1111 break;
1112
1113 case 'edit':
1114
1115 $form['txn_user']['#disabled'] = true;
1116 unset($form['txn_user']['#autocomplete_path']);
1117
1118 $form['txn_uid'] = array(
1119 '#type' => 'value',
1120 '#value' => $txn->uid,
1121 );
1122 $form['txn_id'] = array(
1123 '#type' => 'value',
1124 '#value' => $txn_id,
1125 );
1126 $form['approver_uid'] = array(
1127 '#type' => 'textfield',
1128 '#description' => t('Approver ID'),
1129 '#default_value' => $txn->approver_uid,
1130 '#size' => 10,
1131 '#maxlength' => 7,
1132 '#description' => t('The user ID of the person who approved this transaction. 0 means not yet approved.'),
1133 );
1134
1135 $form['operation'] = array(
1136 '#type' => 'textfield',
1137 '#description' => t('Operation'),
1138 '#default_value' =>