Changeset 867
- Timestamp:
- 03/03/10 20:57:52 (5 months ago)
- Location:
- drupal-6/sites/all/modules/flag
- Files:
-
- 35 added
- 17 modified
-
CVS (added)
-
CVS/Entries (added)
-
CVS/Repository (added)
-
CVS/Root (added)
-
CVS/Tag (added)
-
CVS/Template (added)
-
LICENSE.txt (added)
-
README.txt (modified) (3 diffs)
-
flag.inc (modified) (48 diffs)
-
flag.info (modified) (1 diff)
-
flag.install (modified) (11 diffs)
-
flag.module (modified) (45 diffs)
-
flag_actions.info (modified) (1 diff)
-
flag_actions.install (modified) (3 diffs)
-
flag_actions.module (modified) (18 diffs)
-
includes/CVS (added)
-
includes/CVS/Entries (added)
-
includes/CVS/Repository (added)
-
includes/CVS/Root (added)
-
includes/CVS/Tag (added)
-
includes/CVS/Template (added)
-
includes/flag.actions.inc (added)
-
includes/flag.activity.inc (added)
-
includes/flag.admin.inc (added)
-
includes/flag.export.inc (added)
-
includes/flag.features.inc (added)
-
includes/flag.rules.inc (modified) (6 diffs)
-
includes/flag.services.inc (added)
-
includes/flag.views_default.inc (modified) (2 diffs)
-
includes/flag_handler_field_ops.inc (modified) (4 diffs)
-
includes/flag_handler_filter_flagged.inc (modified) (2 diffs)
-
includes/flag_handler_relationships.inc (modified) (3 diffs)
-
includes/flag_plugin_argument_validate_flaggability.inc (modified) (2 diffs)
-
tests/flag.test (modified) (4 diffs)
-
theme/CVS (added)
-
theme/CVS/Entries (added)
-
theme/CVS/Repository (added)
-
theme/CVS/Root (added)
-
theme/CVS/Tag (added)
-
theme/CVS/Template (added)
-
theme/flag-admin.css (added)
-
theme/flag-admin.js (added)
-
theme/flag.js (modified) (4 diffs)
-
theme/flag.tpl.php (modified) (2 diffs)
-
translations/CVS (added)
-
translations/CVS/Entries (added)
-
translations/CVS/Repository (added)
-
translations/CVS/Root (added)
-
translations/CVS/Tag (added)
-
translations/CVS/Template (added)
-
translations/da.po (added)
-
translations/fr.po (added)
Legend:
- Unmodified
- Added
- Removed
-
drupal-6/sites/all/modules/flag/README.txt
r535 r867 1 // $Id: README.txt,v 1.1.4.6 2008/10/07 16:41:26 mooffieExp $1 // $Id: README.txt,v 1.1.4.6.2.1 2009/10/28 00:01:31 quicksketch Exp $ 2 2 3 3 You may want to visit the handbook of this module, at: … … 46 46 displays possible relating to the number of times an item has been flagged. 47 47 48 This module was formerly known as Views Bookmark. 48 This module was formerly known as Views Bookmark, which was originally was 49 written by Earl Miles. Flag was written by Nathan Haug and mystery man Mooffie. 49 50 50 Ongoing development by Nathan Haug and mystery man Mooffie. 51 52 Originally written by Earl Miles. 51 This module built by robots: http://www.lullabot.com 53 52 54 53 Recommended Modules 55 54 ------------------- 56 55 - Views 56 - Session API 57 57 58 58 Installation … … 61 61 62 62 2) Enable the module using Administer -> Modules (/admin/build/modules) 63 64 Optional Installation 65 --------------------- 66 1) The ability for anonymous users to flag content is provided by the Session 67 API module, available at http://drupal.org/project/session_api. 63 68 64 69 Configuration -
drupal-6/sites/all/modules/flag/flag.inc
r865 r867 1 1 <?php 2 // $Id: flag.inc,v 1.1.2.3 2 2010/01/08 05:00:45quicksketch Exp $2 // $Id: flag.inc,v 1.1.2.30.2.20 2010/01/08 05:14:24 quicksketch Exp $ 3 3 4 4 /** … … 110 110 // database columns. 111 111 var $title = ''; 112 var $roles = array(DRUPAL_AUTHENTICATED_RID);113 112 var $global = FALSE; 114 113 // The sub-types, e.g. node types, this flag applies to. … … 137 136 unset($flag->options, $flag->type); 138 137 139 $options = (array)unserialize($row->options); 138 // Populate the options with the defaults. 139 $options = (array) unserialize($row->options); 140 $options += $flag->options(); 141 140 142 // Make the unserialized options accessible as normal properties. 141 143 foreach ($options as $option => $value) { … … 148 150 } 149 151 150 $flag->roles = empty($row->roles) ? array() : explode(',', $row->roles);151 152 152 return $flag; 153 153 } … … 185 185 * Derived classes should want to override this. 186 186 */ 187 function default_options() {188 returnarray(187 function options() { 188 $options = array( 189 189 'flag_short' => '', 190 190 'flag_long' => '', 191 191 'flag_message' => '', 192 'flag_confirmation' => '',193 192 'unflag_short' => '', 194 193 'unflag_long' => '', 195 194 'unflag_message' => '', 196 'unflag_ confirmation' => '',195 'unflag_denied_text' => '', 197 196 'link_type' => 'toggle', 198 ); 197 'roles' => array( 198 'flag' => array(DRUPAL_AUTHENTICATED_RID), 199 'unflag' => array(DRUPAL_AUTHENTICATED_RID), 200 ), 201 ); 202 203 // Merge in options from the current link type. 204 $link_type = $this->get_link_type(); 205 $options = array_merge($options, $link_type['options']); 206 207 // Allow other modules to change the flag options. 208 drupal_alter('flag_options', $options, $this); 209 return $options; 199 210 } 200 211 … … 211 222 */ 212 223 function construct() { 213 $options = $this-> default_options();224 $options = $this->options(); 214 225 foreach ($options as $option => $value) { 215 226 $this->$option = $value; … … 227 238 } 228 239 // But checkboxes need some massaging: 229 $this->roles = array_values(array_filter($this->roles)); 240 $this->roles['flag'] = array_values(array_filter($this->roles['flag'])); 241 $this->roles['unflag'] = array_values(array_filter($this->roles['unflag'])); 230 242 $this->types = array_values(array_filter($this->types)); 231 243 // Clear internal titles cache: … … 234 246 235 247 /** 236 * Validates a flag settings 248 * Validates this flag's options. 249 * 250 * @return 251 * A list of errors encountered while validating this flag's options. 237 252 */ 238 253 function validate() { 239 $this->validate_name(); 240 } 241 254 // TODO: It might be nice if this used automatic method discovery rather 255 // than hard-coding the list of validate functions. 256 return array_merge_recursive( 257 $this->validate_name(), 258 $this->validate_access() 259 ); 260 } 261 262 /** 263 * Validates that the current flag's name is valid. 264 */ 242 265 function validate_name() { 266 $errors = array(); 267 243 268 // Ensure a safe machine name. 244 269 if (!preg_match('/^[a-z_][a-z0-9_]*$/', $this->name)) { 245 form_set_error('name', t('The flag name may only contain lowercase letters, underscores, and numbers.')); 270 $errors['name'][] = array( 271 'error' => 'flag_name_characters', 272 'message' => t('The flag name may only contain lowercase letters, underscores, and numbers.'), 273 ); 246 274 } 247 275 // Ensure the machine name is unique. 248 if (!isset($this->fid)) { 249 $flag = flag_get_flag($this->name); 250 if (!empty($flag)) { 251 form_set_error('name', t('Flag names must be unique. This flag name is already in use.')); 252 } 253 } 276 $flag = flag_get_flag($this->name); 277 if (!empty($flag) && (!isset($this->fid) || $flag->fid != $this->fid)) { 278 $errors['name'][] = array( 279 'error' => 'flag_name_unique', 280 'message' => t('Flag names must be unique. This flag name is already in use.'), 281 ); 282 } 283 284 return $errors; 285 } 286 287 /** 288 * Validates that the current flag's access settings are valid. 289 */ 290 function validate_access() { 291 $errors = array(); 292 293 // Require an unflag access denied message a role is not allowed to unflag. 294 if (empty($this->unflag_denied_text)) { 295 foreach ($this->roles['flag'] as $key => $rid) { 296 if ($rid && empty($this->roles['unflag'][$key])) { 297 $errors['unflag_denied_text'][] = array( 298 'error' => 'flag_denied_text_required', 299 'message' => t('The "Unflag not allowed text" is required if any user roles are not allowed to unflag.'), 300 ); 301 break; 302 } 303 } 304 } 305 306 // Do not allow unflag access without flag access. 307 foreach ($this->roles['unflag'] as $key => $rid) { 308 if ($rid && empty($this->roles['flag'][$key])) { 309 $errors['roles'][] = array( 310 'error' => 'flag_roles_unflag', 311 'message' => t('Any user role that has the ability to unflag must also have the ability to flag.'), 312 ); 313 break; 314 } 315 } 316 317 return $errors; 254 318 } 255 319 … … 294 358 295 359 /** 360 * @defgroup access Access control 361 * @{ 362 */ 363 364 /** 296 365 * Returns TRUE if the flag applies to the given content. 297 366 * Derived classes must implement this. … … 315 384 316 385 /** 386 * Returns TRUE if user has access to use this flag. 387 * 388 * @param $action 389 * Optional. The action to test, either "flag" or "unflag". If none given, 390 * "flag" will be tested, which is the minimum permission to use a flag. 391 * @param $account 392 * Optional. The user object. If none given, the current user will be used. 393 * 394 * @return 395 * Boolean TRUE if the user is allowed to flag/unflag. FALSE otherwise. 396 */ 397 function user_access($action = 'flag', $account = NULL) { 398 if (!isset($account)) { 399 $account = $GLOBALS['user']; 400 } 401 402 // Anonymous user can't use this system unless Session API is installed. 403 if ($account->uid == 0 && !module_exists('session_api')) { 404 return FALSE; 405 } 406 407 $matched_roles = array_intersect($this->roles[$action], array_keys($account->roles)); 408 return !empty($matched_roles) || $account->uid == 1; 409 } 410 411 /** 412 * Returns TRUE if the user can flag, or unflag, the given content. 413 * 414 * @param $content_id 415 * The content ID to flag/unflag. 416 * @param $account 417 * The user on whose behalf to test the flagging action. Leave NULL for the 418 * current user. 419 * @param $action 420 * The action to test. Either 'flag' or 'unflag'. Leave NULL to determine 421 * by flag status. 422 */ 423 function access($content_id, $action = NULL, $account = NULL) { 424 if (!isset($account)) { 425 $account = $GLOBALS['user']; 426 } 427 428 if (isset($content_id) && !$this->applies_to_content_id($content_id) ){ 429 // Flag does not apply to this content. 430 return FALSE; 431 } 432 433 if (!isset($action)) { 434 $uid = $account->uid; 435 $sid = flag_get_sid($uid); 436 $action = $this->is_flagged($content_id, $uid, $sid) ? 'unflag' : 'flag'; 437 } 438 439 // Base initial access on the user's basic permission to use this flag. 440 $access = $this->user_access($action, $account); 441 442 // Allow modules to disallow (or allow) access to flagging. 443 $access_array = module_invoke_all('flag_access', $this, $content_id, $action, $account); 444 445 foreach ($access_array as $set_access) { 446 if (isset($set_access)) { 447 $access = $set_access; 448 } 449 } 450 451 return $access; 452 } 453 454 /** 455 * Similar to access() but works on multiple IDs at once. It is called in the 456 * pre_render() stage of the 'Flag links' field within Views to find out where 457 * that link applies. The reason we do a separate DB query, and not lump this 458 * test in the Views query, is to make 'many to one' tests possible without 459 * interfering with the rows, and also to reduce the complexity of the code. 460 * 461 * @param $content_ids 462 * The array of content IDs to check. The keys are the content IDs, the 463 * values are the actions to test: either 'flag' or 'unflag'. 464 * @param $account 465 * Optional. The account for which the actions will be compared against. 466 * If left empty, the current user will be used. 467 */ 468 function access_multiple($content_ids, $account = NULL) { 469 $account = isset($account) ? $account : $GLOBALS['user']; 470 $access = array(); 471 472 // First check basic user access for this action. 473 foreach ($content_ids as $content_id => $action) { 474 $access[$content_id] = $this->user_access($content_ids[$content_id], $account); 475 } 476 477 // Merge in module-defined access. 478 foreach (module_implements('flag_access_multiple') as $module) { 479 $module_access = module_invoke($module, 'flag_access_multiple', $this, $content_ids, $account); 480 foreach ($module_access as $content_id => $content_access) { 481 if (isset($content_access)) { 482 $access[$content_id] = $content_access; 483 } 484 } 485 } 486 487 return $access; 488 } 489 490 /** 491 * @} End of "defgroup access". 492 */ 493 494 /** 317 495 * Given a content object, returns its ID. 318 496 * Derived classes must implement this. … … 333 511 334 512 /** 335 * Returns TRUE if user has access to use this flag. 336 * 337 * @param $account 338 * Optional. The user object. If none given, the current user will be used. 339 * 340 * @return 341 * Boolean TRUE if the user is allowed to flag/unflag. FALSE otherwise. 342 */ 343 function user_access($account = NULL) { 344 if (!isset($account)) { 345 $account = $GLOBALS['user']; 346 } 347 $matched_roles = array_intersect($this->roles, array_keys($account->roles)); 348 return !empty($matched_roles) || empty($this->roles) || $account->uid == 1; 349 } 350 351 /** 352 * Flags, on unflags, an item. 513 * Returns TRUE if this flag requires anonymous user cookies. 514 */ 515 function uses_anonymous_cookies() { 516 global $user; 517 return $user->uid == 0 && variable_get('cache', CACHE_DISABLED) > 0; 518 } 519 520 /** 521 * Flags, or unflags, an item. 353 522 * 354 523 * @param $action … … 371 540 return FALSE; 372 541 } 373 374 if (!$account->uid) { 375 // Anonymous users can't flag with this system. For now. 376 // 377 // @todo This is legacy code. $flag->user_access() should handle this. 378 // This will also make it posible to have flags that do support anonymous 379 // users. 380 return FALSE; 381 } 382 383 if (!$skip_permission_check && !$this->user_access($account)) { 384 // User has no permission to use this flag. 385 return FALSE; 386 } 387 if (!$this->applies_to_content_id($content_id)) { 388 // Flag does not apply to this content. 389 return FALSE; 542 if (!$skip_permission_check) { 543 if (!$this->access($content_id, $action, $account)) { 544 // User has no permission to flag/unflag this object. 545 return FALSE; 546 } 547 } 548 else { 549 // We are skipping permission checks. However, at a minimum we must make 550 // sure the flag applies to this content type: 551 if (!$this->applies_to_content_id($content_id)) { 552 return FALSE; 553 } 390 554 } 391 555 … … 393 557 // wrong counts or false flaggings. 394 558 flag_get_counts(NULL, NULL, TRUE); 395 flag_get_user_flags(NULL, NULL, NULL, TRUE);559 flag_get_user_flags(NULL, NULL, NULL, NULL, TRUE); 396 560 397 561 // Perform the flagging or unflagging of this flag. 398 562 $uid = $this->global ? 0 : $account->uid; 399 $flagged = $this->_is_flagged($content_id, $uid); 400 if ($action == 'unflag' && $flagged) { 401 $this->_unflag($content_id, $uid); 402 // Let other modules perform actions. 403 module_invoke_all('flag', 'unflag', $this, $content_id, $account); 404 } 405 elseif ($action == 'flag' && !$flagged) { 406 $this->_flag($content_id, $uid); 407 // Let other modules perform actions. 408 module_invoke_all('flag', 'flag', $this, $content_id, $account); 563 $sid = $this->global ? 0 : flag_get_sid($uid); 564 $flagged = $this->_is_flagged($content_id, $uid, $sid); 565 if ($action == 'unflag') { 566 if ($this->uses_anonymous_cookies()) { 567 $this->_unflag_anonymous($content_id); 568 } 569 if ($flagged) { 570 $fcid = $this->_unflag($content_id, $uid, $sid); 571 module_invoke_all('flag', 'unflag', $this, $content_id, $account, $fcid); 572 } 573 } 574 elseif ($action == 'flag') { 575 if ($this->uses_anonymous_cookies()) { 576 $this->_flag_anonymous($content_id); 577 } 578 if (!$flagged) { 579 $fcid = $this->_flag($content_id, $uid, $sid); 580 module_invoke_all('flag', 'flag', $this, $content_id, $account, $fcid); 581 } 409 582 } 410 583 … … 422 595 * current user will be used. 423 596 */ 424 function is_flagged($content_id, $uid = NULL) { 425 $uid = !isset($uid) ? $GLOBALS['user']->uid : $uid; 597 function is_flagged($content_id, $uid = NULL, $sid = NULL) { 598 $uid = $this->global ? 0 : (!isset($uid) ? $GLOBALS['user']->uid : $uid); 599 $sid = $this->global ? 0 : (!isset($sid) ? flag_get_sid($uid) : $sid); 600 426 601 // flag_get_user_flags() does caching. 427 $user_flags = flag_get_user_flags($this->content_type, $content_id, $uid );602 $user_flags = flag_get_user_flags($this->content_type, $content_id, $uid, $sid); 428 603 return isset($user_flags[$this->name]); 429 604 } … … 441 616 * @private 442 617 */ 443 function _is_flagged($content_id, $uid ) {444 return db_result(db_query("SELECT fid FROM {flag_content} WHERE fid = %d AND uid = %d AND content_id = %d", $this->fid, $uid, $content_id));618 function _is_flagged($content_id, $uid, $sid) { 619 return db_result(db_query("SELECT fid FROM {flag_content} WHERE fid = %d AND uid = %d AND sid = %d AND content_id = %d", $this->fid, $uid, $sid, $content_id)); 445 620 } 446 621 … … 453 628 * @private 454 629 */ 455 function _flag($content_id, $uid) { 456 db_query("INSERT INTO {flag_content} (fid, content_type, content_id, uid, timestamp) VALUES (%d, '%s', %d, %d, %d)", $this->fid, $this->content_type, $content_id, $uid, time()); 630 function _flag($content_id, $uid, $sid) { 631 db_query("INSERT INTO {flag_content} (fid, content_type, content_id, uid, sid, timestamp) VALUES (%d, '%s', %d, %d, %d, %d)", $this->fid, $this->content_type, $content_id, $uid, $sid, time()); 632 $fcid = db_last_insert_id('flag_content', 'fcid'); 457 633 $this->_update_count($content_id); 634 return $fcid; 458 635 } 459 636 … … 466 643 * @private 467 644 */ 468 function _unflag($content_id, $uid) { 469 db_query("DELETE FROM {flag_content} WHERE fid = %d AND uid = %d AND content_id = %d", $this->fid, $uid, $content_id); 470 $this->_update_count($content_id); 645 function _unflag($content_id, $uid, $sid) { 646 $fcid = db_result(db_query("SELECT fcid FROM {flag_content} WHERE fid = %d AND content_id = %d AND uid = %d AND sid = %d", $this->fid, $content_id, $uid, $sid)); 647 if ($fcid) { 648 db_query("DELETE FROM {flag_content} WHERE fcid = %d", $fcid); 649 $this->_update_count($content_id); 650 } 651 // Remove anonymous cookies (if any). 652 if (isset($_COOKIE['flag'][$this->name . '_' . $content_id])) { 653 unset($_COOKIE['flags'][$this->name . '_' . $content_id]); 654 } 655 return $fcid; 471 656 } 472 657 … … 490 675 491 676 /** 677 * Set a cookie for anonymous users to record their flagging. 678 * 679 * @private 680 */ 681 function _flag_anonymous($content_id) { 682 // Global flags persist for the length of the minimum cache lifetime. 683 if ($this->global) { 684 $cookie_key = 'flag_global_' . str_replace('_', '-', $this->name) . '_' . $content_id; 685 $cookie_lifetime = (variable_get('cache', 0) > CACHE_DISABLED) ? variable_get('cache_lifetime', 0) : -1; 686 // Do not let the cookie lifetime be 0 (which is the no cache limit on 687 // anonymous page caching), since it would expire immediately. Usually 688 // the no cache limit means caches are cleared on cron, which usually runs 689 // at least once an hour. 690 if ($cookie_lifetime == 0) { 691 $cookie_lifetime = 3600; 692 } 693 setcookie($cookie_key, 1, time() + $cookie_lifetime, base_path()); 694 $_COOKIE[$cookie_key] = 1; 695 } 696 // The anonymous per-user flags are stored in a single cookie, so that all 697 // of them persist as long as the Drupal cookie lifetime. 698 else { 699 $cookie_flags = isset($_COOKIE['flags']) ? $_COOKIE['flags'] : ''; 700 $cookie_flags = explode(' ', $cookie_flags); 701 $cookie_key = str_replace('_', '-', $this->name) . '_' . $content_id; 702 $cookie_lifetime = min((int) ini_get('session.cookie_lifetime'), (int) ini_get('session.gc_maxlifetime')); 703 if (array_search($cookie_key, $cookie_flags) === FALSE) { 704 $cookie_flags[] = $cookie_key; 705 $cookie_flags = implode(' ', array_filter($cookie_flags)); 706 setcookie('flags', $cookie_flags, time() + $cookie_lifetime, base_path()); 707 $_COOKIE['flags'] = $cookie_flags; 708 } 709 } 710 } 711 712 /** 713 * Remove the cookie for anonymous users to record their unflagging. 714 * 715 * @private 716 */ 717 function _unflag_anonymous($content_id) { 718 // Global flags are easy, just delete the global cookie. 719 if ($this->global) { 720 $cookie_key = 'flag_global_' . str_replace('_', '-', $this->name) . '_' . $content_id; 721 $cookie_lifetime = (variable_get('cache', 0) > CACHE_DISABLED) ? variable_get('cache_lifetime', 0) : -1; 722 // Do not let the cookie lifetime be 0 (which is the no cache limit on 723 // anonymous page caching), since it would expire immediately. Usually 724 // the no cache limit means caches are cleared on cron, which usually runs 725 // at least once an hour. 726 if ($cookie_lifetime == 0) { 727 $cookie_lifetime = 3600; 728 } 729 setcookie($cookie_key, 0, time() + $cookie_lifetime, base_path()); 730 $_COOKIE[$cookie_key] = 0; 731 } 732 // User flags, update the single cookie for all user-data. 733 else { 734 $cookie_flags = isset($_COOKIE['flags']) ? $_COOKIE['flags'] : ''; 735 $cookie_flags = explode(' ', $cookie_flags); 736 $cookie_key = str_replace('_', '-', $this->name) . '_' . $content_id; 737 $cookie_lifetime = min((int) ini_get('session.cookie_lifetime'), (int) ini_get('session.gc_maxlifetime')); 738 $cookie_index = array_search($cookie_key, $cookie_flags); 739 if ($cookie_index !== FALSE) { 740 unset($cookie_flags[$cookie_index]); 741 $cookie_flags = implode(' ', $cookie_flags); 742 setcookie('flags', $cookie_flags, $cookie_lifetime, base_path()); 743 $_COOKIE['flags'] = $cookie_flags; 744 } 745 } 746 } 747 748 /** 492 749 * Returns the number of times an item is flagged. 493 750 * … … 503 760 * Returns the number of items a user has flagged. 504 761 * 505 * For global flags, pass '0' as the user ID .506 */ 507 function get_user_count($uid ) {508 return db_result(db_query('SELECT COUNT(*) FROM {flag_content} WHERE fid = %d AND uid = %d ', $this->fid, $uid));762 * For global flags, pass '0' as the user ID and session ID. 763 */ 764 function get_user_count($uid, $sid) { 765 return db_result(db_query('SELECT COUNT(*) FROM {flag_content} WHERE fid = %d AND uid = %d AND sid = %d', $this->fid, $uid, $sid)); 509 766 } 510 767 … … 537 794 538 795 /** 796 * Get the link type for this flag. 797 */ 798 function get_link_type() { 799 $link_types = flag_get_link_types(); 800 return (isset($this->link_type) && isset($link_types[$this->link_type])) ? $link_types[$this->link_type] : $link_types['normal']; 801 } 802 803 /** 539 804 * Replaces tokens in a label. Only the 'global' token context is regognized 540 805 * by default, so derived classes should override this method to add all … … 641 906 return array(); 642 907 } 643 908 644 909 /** 645 910 * Defines the Rules argument for flag actions or conditions … … 648 913 return array(); 649 914 } 650 915 651 916 /** 652 917 * @} End of "addtogroup rules". … … 671 936 672 937 /** 673 * Similar to applies_to_content_id() but works on a bunch of IDs. It is674 * called in the pre_render() stage of the 'Flag links' field to find out where675 * that link applies. The reason we do a separate DB query, and not lump this676 * test in the Views query, is to make 'many to one' tests possible without677 * interfering with the rows, and also to reduce the complexity of the code.678 */679 function applies_to_content_id_array($content_ids) {680 return array();681 }682 683 /**684 938 * @} End of "addtogroup views". 685 939 */ … … 691 945 if (isset($this->fid)) { 692 946 $this->update(); 947 $this->is_new = FALSE; 693 948 } 694 949 else { 695 950 $this->insert(); 696 } 951 $this->is_new = TRUE; 952 } 953 // Clear the page cache for anonymous users. 954 cache_clear_all('*', 'cache_page', TRUE); 697 955 } 698 956 … … 701 959 */ 702 960 function update() { 703 db_query("UPDATE {flags} SET name = '%s', title = '%s', roles = '%s', global = %d, options = '%s' WHERE fid = %d", $this->name, $this->title, implode(',', $this->roles), $this->global, $this->get_serialized_options(), $this->fid);961 db_query("UPDATE {flags} SET name = '%s', title = '%s', global = %d, options = '%s' WHERE fid = %d", $this->name, $this->title, $this->global, $this->get_serialized_options(), $this->fid); 704 962 db_query("DELETE FROM {flag_types} WHERE fid = %d", $this->fid); 705 963 foreach ($this->types as $type) { … … 712 970 */ 713 971 function insert() { 714 if (function_exists('db_last_insert_id')) { 715 // Drupal 6. We have a 'serial' primary key. 716 db_query("INSERT INTO {flags} (content_type, name, title, roles, global, options) VALUES ('%s', '%s', '%s', '%s', %d, '%s')", $this->content_type, $this->name, $this->title, implode(',', $this->roles), $this->global, $this->get_serialized_options()); 717 $this->fid = db_last_insert_id('flags', 'fid'); 718 } 719 else { 720 // Drupal 5. We have an 'integer' primary key. 721 $this->fid = db_next_id('{flags}_fid'); 722 db_query("INSERT INTO {flags} (fid, content_type, name, title, roles, global, options) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $this->fid, $this->content_type, $this->name, $this->title, implode(',', $this->roles), $this->global, $this->get_serialized_options()); 723 } 972 db_query("INSERT INTO {flags} (content_type, name, title, global, options) VALUES ('%s', '%s', '%s', %d, '%s')", $this->content_type, $this->name, $this->title, $this->global, $this->get_serialized_options()); 973 $this->fid = db_last_insert_id('flags', 'fid'); 724 974 foreach ($this->types as $type) { 725 975 db_query("INSERT INTO {flag_types} (fid, type) VALUES (%d, '%s')", $this->fid, $type); … … 731 981 */ 732 982 function get_serialized_options() { 733 $option_names = array_keys($this-> default_options());983 $option_names = array_keys($this->options()); 734 984 $options = array(); 735 985 foreach ($option_names as $option) { … … 778 1028 */ 779 1029 function theme($action, $content_id, $after_flagging = FALSE) { 780 if (!_flag_is_drupal_5()) { 781 // We're running Drupal 6. 782 return theme($this->theme_suggestions(), $this, $action, $content_id, $after_flagging); 783 } 784 else { 785 // We're running Drupal 5. Noting to do: The theme_suggestions[] are 786 // handed to phptemplate in phptemplate_flag(), if the user bothered to 787 // copy that function into her 'template.php'. 788 return theme('flag', $this, $action, $content_id, $after_flagging); 789 } 1030 static $js_added = array(); 1031 1032 // If the flagging user is anonymous and the page cache is enabled, always 1033 // show the "flag" link, and then set the unflag link through JavaScript. 1034 if ($this->uses_anonymous_cookies() && !$after_flagging) { 1035 $js_action = $this->global ? ($action == 'flag' ? 'unflag' : 'flag') : 'flag'; 1036 if (!isset($js_added[$this->name . '_' . $content_id])) { 1037 $js_added[$this->name . '_' . $content_id] = TRUE; 1038 $js_template = theme($this->theme_suggestions(), $this, 'unflag', $content_id, $after_flagging); 1039 drupal_add_js(array('flag' => array('templates' => array($this->name . '_' . $content_id => $js_template))), 'setting'); 1040 } 1041 } 1042 1043 return theme($this->theme_suggestions(), $this, $action, $content_id, $after_flagging); 790 1044 } 791 1045 … … 805 1059 */ 806 1060 class flag_node extends flag_flag { 807 function default_options() {808 $options = parent:: default_options();1061 function options() { 1062 $options = parent::options(); 809 1063 $options += array( 810 1064 'show_on_page' => TRUE, 811 1065 'show_on_teaser' => TRUE, 812 1066 'show_on_form' => FALSE, 1067 'access_author' => '', 813 1068 'i18n' => 0, 814 1069 ); … … 818 1073 function options_form(&$form) { 819 1074 parent::options_form($form); 820 // Note there isn't a translation helpers module in Drupal 5, 821 // this feature is essentially Drupal 6 only. 1075 // Support for i18n flagging requires Translation helpers module. 822 1076 $form['i18n'] = array( 823 1077 '#type' => 'radios', … … 832 1086 '#weight' => 5, 833 1087 ); 1088 1089 $form['access']['access_author'] = array( 1090 '#type' => 'radios', 1091 '#title' => t('Flag access by content authorship'), 1092 '#options' => array( 1093 '' => t('No additional restrictions'), 1094 'own' => t('Users may only flag content they own'), 1095 'others' => t('Users may only flag content of others'), 1096 ), 1097 '#default_value' => $this->access_author, 1098 '#description' => t("Restrict access to this flag based on the user's ownership of the content. Users must also have access to the flag through the role settings."), 1099 ); 1100 834 1101 $form['display']['show_on_teaser'] = array( 835 1102 '#type' => 'checkbox', … … 864 1131 } 865 1132 1133 function access_multiple($content_ids, $account = NULL) { 1134 $access = parent::access_multiple($content_ids, $account); 1135 1136 // Ensure that only flaggable node types are granted access. This avoids a 1137 // node_load() on every type, usually done by applies_to_content_id(). 1138 $nids = implode(',', array_map('intval', array_keys($content_ids))); 1139 $placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'")); 1140 $result = db_query("SELECT nid as content_id FROM {node} WHERE nid IN ($nids) AND type NOT IN ($placeholders)", $this->types); 1141 while ($row = db_fetch_object($result)) { 1142 $access[$row->content_id] = FALSE; 1143 } 1144 1145 return $access; 1146 } 1147 866 1148 function get_content_id($node) { 867 1149 return $node->nid; … … 898 1180 } 899 1181 900 901 function is_flagged($content_id, $uid = NULL) { 1182 function is_flagged($content_id, $uid = NULL, $sid = NULL) { 902 1183 $content_id = $this->get_translation_id($content_id); 903 return parent::is_flagged($content_id, $uid );1184 return parent::is_flagged($content_id, $uid, $sid); 904 1185 } 905 1186 … … 909 1190 910 1191 function replace_tokens($label, $contexts, $content_id) { 911 if ( $content_id&& ($node = $this->fetch_content($content_id))) {1192 if (is_numeric($content_id) && ($node = $this->fetch_content($content_id))) { 912 1193 $contexts['node'] = $node; 1194 } 1195 // Nodes accept the node-type as a $content_id in the case that a new node 1196 // is being created and a full node object does not yet exist. 1197 elseif (!empty($content_id) && ($type = node_get_types('type', $content_id))) { 1198 $content_id = NULL; 1199 $contexts['node'] = (object) array( 1200 'nid' => NULL, 1201 'type' => $type->type, 1202 'title' => '', 1203 ); 913 1204 } 914 1205 return parent::replace_tokens($label, $contexts, $content_id); … … 948 1239 ); 949 1240 } 950 1241 951 1242 function rules_get_element_argument_definition() { 952 1243 return array('type' => 'node', 'label' => t('Flagged content')); … … 964 1255 ); 965 1256 } 966 967 function applies_to_content_id_array($content_ids) {968 $passed = array();969 $content_ids = implode(',', array_map('intval', $content_ids));970 $placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'"));971 $result = db_query("SELECT nid FROM {node} WHERE nid IN ($content_ids) AND type in ($placeholders)", $this->types);972 while ($row = db_fetch_object($result)) {973 $passed[$row->nid] = TRUE;974 }975 return $passed;976 }977 978 1257 } 979 1258 … … 982 1261 */ 983 1262 class flag_comment extends flag_flag { 984 function default_options() {985 $options = parent:: default_options();1263 function options() { 1264 $options = parent::options(); 986 1265 $options += array( 1266 'access_author' => '', 987 1267 'show_on_comment' => TRUE, 988 1268 ); … … 992 1272 function options_form(&$form) { 993 1273 parent::options_form($form); 1274 1275 $form['access']['access_author'] = array( 1276 '#type' => 'radios', 1277 '#title' => t('Flag access by content authorship'), 1278 '#options' => array( 1279 '' => t('No additional restrictions'), 1280 'comment_own' => t('Users may only flag own comments'), 1281 'comment_others' => t('Users may only flag comments by others'), 1282 'node_own' => t('Users may only flag comments of nodes they own'), 1283 'node_others' => t('Users may only flag comments of nodes by others'), 1284 ), 1285 '#default_value' => $this->access_author, 1286 '#description' => t("Restrict access to this flag based on the user's ownership of the content. Users must also have access to the flag through the role settings."), 1287 ); 1288 994 1289 $form['display']['show_on_comment'] = array( 995 1290 '#type' => 'checkbox', … … 1009 1304 } 1010 1305 return FALSE; 1306 } 1307 1308 function access_multiple($content_ids, $account = NULL) { 1309 $account = isset($account) ? $account : $GLOBALS['user']; 1310 $access = parent::access_multiple($content_ids, $account); 1311 1312 // Ensure node types are granted access. This avoids a 1313 // node_load() on every type, usually done by applies_to_content_id(). 1314 $cids = implode(',', array_map('intval', array_keys($content_ids))); 1315 $placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'")); 1316 $result = db_query("SELECT cid as content_id FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid WHERE cid IN ($cids) and n.type NOT IN ($placeholders)", $this->types); 1317 while ($row = db_fetch_object($result)) { 1318 $access[$row->content_id] = FALSE; 1319 } 1320 1321 return $access; 1011 1322 } 1012 1323 … … 1063 1374 ); 1064 1375 } 1065 1376 1066 1377 function rules_get_element_argument_definition() { 1067 1378 return array('type' => 'comment', 'label' => t('Flagged comment')); … … 1079 1390 ); 1080 1391 } 1081 1082 function applies_to_content_id_array($content_ids) {1083 $passed = array();1084 $content_ids = implode(',', array_map('intval', $content_ids));1085 $placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'"));1086 $result = db_query("SELECT cid FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid WHERE cid IN ($content_ids) and n.type IN ($placeholders)", $this->types);1087 while ($row = db_fetch_object($result)) {1088 $passed[$row->cid] = TRUE;1089 }1090 return $passed;1091 }1092 1392 } 1093 1393 … … 1096 1396 */ 1097 1397 class flag_user extends flag_flag { 1098 function default_options() {1099 $options = parent:: default_options();1398 function options() { 1399 $options = parent::options(); 1100 1400 $options += array( 1101 1401 'show_on_profile' => TRUE, 1402 'access_uid' => '', 1102 1403 ); 1103 1404 return $options; … … 1106 1407 function options_form(&$form) { 1107 1408 parent::options_form($form); 1108 $form['types'] = array( 1109 // A user flag doesn't support node types. (Maybe will support roles instead, in the future.) 1409 $form['access']['types'] = array( 1410 // A user flag doesn't support node types. 1411 // TODO: Maybe support roles instead of node types. 1110 1412 '#type' => 'value', 1111 1413 '#value' => array(0 => 0), 1414 ); 1415 $form['access']['access_uid'] = array( 1416 '#type' => 'checkbox', 1417 '#title' => t('Users may flag themselves'), 1418 '#description' => t('Disabling this option may be useful when setting up a "friend" flag, when a user flagging themself does not make sense.'), 1419 '#default_value' => $this->access_uid ? 0 : 1, 1112 1420 ); 1113 1421 $form['display']['show_on_profile'] = array( … … 1119 1427 } 1120 1428 1429 function form_input($form_values) { 1430 parent::form_input($form_values); 1431 // The access_uid value is intentionally backwards from the UI, to avoid 1432 // confusion caused by checking a box to disable a feature. 1433 $this->access_uid = empty($form_values['access_uid']) ? 'others' : ''; 1434 } 1435 1121 1436 function _load_content($content_id) { 1122 1437 return user_load(array('uid' => $content_id)); … … 1130 1445 } 1131 1446 return FALSE; 1447 } 1448 1449 function access($content_id, $action = NULL, $account = NULL) { 1450 $access = parent::access($content_id, $action, $account); 1451 $account = isset($account) ? $account : $GLOBALS['user']; 1452 1453 // Prevent users from flagging themselves. 1454 if ($this->access_uid == 'others' && $content_id == $account->uid) { 1455 $access = FALSE; 1456 } 1457 1458 return $access; 1459 } 1460 1461 function access_multiple($content_ids, $account = NULL) { 1462 $account = isset($account) ? $account : $GLOBALS['user']; 1463 $access = parent::access_multiple($content_ids, $account); 1464 1465 // Exclude anonymous. 1466 if (array_key_exists(0, $access)) { 1467 $access[0] = FALSE; 1468 } 1469 1470 // Prevent users from flagging themselves. 1471 if ($this->access_uid == 'others' && array_key_exists($account->uid, $access)) { 1472 $access[$account->uid] = FALSE; 1473 } 1474 1475 return $access; 1132 1476 } 1133 1477 … … 1177 1521 ); 1178 1522 } 1179 1523 1180 1524 function rules_get_element_argument_definition() { 1181 1525 return array('type' => 'user', 'label' => t('Flagged user')); … … 1193 1537 ); 1194 1538 } 1195 1196 function applies_to_content_id_array($content_ids) {1197 // This user flag doesn't currently support subtypes so all users are1198 // applicable for flagging.1199 $passed = array();1200 foreach ($content_ids as $uid) {1201 if ($uid) { // Exclude anonymous.1202 $passed[$uid] = TRUE;1203 }1204 }1205 return $passed;1206 }1207 1208 1539 } 1209 1540 … … 1220 1551 } 1221 1552 1222 // Returns TRUE if we're running under Drupal 5. 1223 // 1224 // I use this function because I don't want to maintain two versions of a file 1225 // just because a handful of lines of code. 1226 function _flag_is_drupal_5() { 1227 return !function_exists('theme_get_registry'); 1553 /** 1554 * A shortcut function to output the link URL. 1555 */ 1556 function _flag_url($path, $fragment = NULL, $absolute = TRUE) { 1557 return url($path, array('fragment' => $fragment, 'absolute' => $absolute)); 1228 1558 } 1229 1230 // That's ugly, but duplicating this logic is uglier.1231 function _flag_url($path, $fragment = NULL, $absolute = TRUE) {1232 return _flag_is_drupal_5()1233 ? url($path, NULL, $fragment, $absolute)1234 : url($path, array('absolute' => TRUE, 'fragment' => $fragment));1235 }1236 -
drupal-6/sites/all/modules/flag/flag.info
r865 r867 4 4 core = 6.x 5 5 package = Flags 6 7 ; Information added by drupal.org packaging script on 2010-01-088 version = "6.x-1.2"9 core = "6.x"10 project = "flag"11 datestamp = "1262929205"12 -
drupal-6/sites/all/modules/flag/flag.install
r865 r867 1 1 <?php 2 // $Id: flag.install,v 1.2.2.3 4 2010/01/08 05:00:45quicksketch Exp $2 // $Id: flag.install,v 1.2.2.32.2.8 2010/01/08 04:42:32 quicksketch Exp $ 3 3 4 4 /** … … 23 23 } 24 24 25 $success = drupal_install_schema('flag'); 26 27 if ($success) { 28 // Install a demonstration flag. 25 drupal_install_schema('flag'); 26 } 27 28 /** 29 * Implementation of hook_uninstall(). 30 */ 31 function flag_uninstall() { 32 drupal_uninstall_schema('flag'); 33 $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'flag_%'"); 34 while ($row = db_fetch_object($result)) { 35 variable_del($row->name); 36 } 37 38 drupal_set_message(t('Flag has been uninstalled.')); 39 } 40 41 /** 42 * Implementation of hook_enable(). 43 * 44 * We create the demonstration flag on enable, so hook implementations in flag 45 * module will fire correctly, as the APIs are not available on install. 46 */ 47 function flag_enable() { 48 // Load the flag API in case we want to use it when enabling. 49 include_once(drupal_get_path('module', 'flag') .'/flag.module'); 50 51 if (!flag_get_flags()) { 52 // Install a demonstration flag only if no flag exists. This is to prevent 53 // a case where a disables and enables the module, and the demonstration 54 // flag is overwritten or re-created. 29 55 $flag = flag_flag::factory_by_content_type('node'); 30 56 $configuration = array( … … 49 75 $flag->save(); 50 76 } 51 52 if ($success) {53 drupal_set_message(st('Flag module installed tables successfully.'));54 }55 else {56 drupal_set_message(st('The installation of Flag module failed.'), 'error');57 }58 }59 60 /**61 * Implementation of hook_uninstall().62 */63 function flag_uninstall() {64 drupal_uninstall_schema('flag');65 $result = db_query("SELECT name FROM {variable} WHERE name LIKE 'flag_%'");66 while ($row = db_fetch_object($result)) {67 variable_del($row->name);68 }69 70 drupal_set_message(t('Flag has been uninstalled.'));71 77 } 72 78 … … 81 87 if ($phase == 'install') { 82 88 if (!defined('MAINTENANCE_MODE') && _flag_flag_content_installed()) { 83 $requirements['flag_content_clash']['title'] = $t('Flag'); 84 $requirements['flag_content_clash']['severity'] = REQUIREMENT_ERROR; 85 $requirements['flag_content_clash']['description'] = _flag_flag_content_message(); 86 } 87 } 88 89 if ($phase == 'runtime' && module_exists('translation') && !module_exists('translation_helpers')) { 90 $requirements['flag_translation']['title'] = $t('Flag'); 91 $requirements['flag_translation']['severity'] = REQUIREMENT_ERROR; 92 $requirements['flag_translation']['description'] = $t('To have the flag module work with translations, you need to install and enable the <a href="http://drupal.org/project/translation_helpers">Translation helpers</a> module.'); 93 $requirements['flag_translation']['value'] = $t('Translation helpers module not found.'); 89 $requirements['flag_content_clash'] = array( 90 'title' => $t('Flag'), 91 'severity' => REQUIREMENT_ERROR, 92 'description' => _flag_flag_content_message(), 93 ); 94 } 95 } 96 97 if ($phase == 'runtime') { 98 if (module_exists('translation') && !module_exists('translation_helpers')) { 99 $requirements['flag_translation'] = array( 100 'title' => $t('Flag'), 101 'severity' => REQUIREMENT_ERROR, 102 'description' => $t('To have the flag module work with translations, you need to install and enable the <a href="http://drupal.org/project/translation_helpers">Translation helpers</a> module.'), 103 'value' => $t('Translation helpers module not found.'), 104 ); 105 } 106 if (module_exists('session_api')) { 107 if (file_exists('./robots.txt')) { 108 $flag_path = url('flag') . '/'; 109 $robots_string = 'Disallow: ' . $flag_path; 110 $contents = file_get_contents('./robots.txt'); 111 if (strpos($contents, $robots_string) === FALSE) { 112 $requirements['flag_robots'] = array( 113 'title' => $t('Flag robots.txt problem'), 114 'severity' => REQUIREMENT_WARNING, 115 'description' => $t('Flag module may currently be used with anonymous users, however the robots.txt file does not exlude the "@flag-path" path, which may cause search engines to randomly flag and unflag content when they index the site. It is highly recommended to add "@robots-string" to your robots.txt file (located in the root of your Drupal installation).', array('@flag-path' => $flag_path, '@robots-string' => $robots_string)), 116 'value' => $t('Search engines flagging content'), 117 ); 118 } 119 } 120 } 94 121 } 95 122 return $requirements; … … 197 224 'default' => 0, 198 225 ), 226 'sid' => array( 227 'type' => 'int', 228 'unsigned' => TRUE, 229 'not null' => TRUE, 230 'default' => 0, 231 ), 199 232 'timestamp' => array( 200 233 'type' => 'int', … … 207 240 'primary key' => array('fcid'), 208 241 'unique keys' => array( 209 'fid_content_ type_content_id_uid' => array('fid', 'content_type', 'content_id', 'uid'),242 'fid_content_id_uid_sid' => array('fid', 'content_id', 'uid', 'sid'), 210 243 ), 211 244 'indexes' => array( 212 245 'content_type_content_id' => array('content_type', 'content_id'), 213 'content_type_uid ' => array('content_type', 'uid'),246 'content_type_uid_sid' => array('content_type', 'uid', 'sid'), 214 247 ), 215 248 ); … … 269 302 'fid_content_type' => array('fid', 'content_type'), 270 303 'content_type_content_id' => array('content_type', 'content_id'), 304 'count' => array('count'), 271 305 ), 272 306 ); … … 375 409 $ret = array(); 376 410 377 if ( _flag_column_exists('flags', 'flag_short')) {411 if (db_column_exists('flags', 'flag_short')) { 378 412 $result = db_query("SELECT * FROM {flags}"); 379 413 while ($flag = db_fetch_object($result)) { … … 404 438 $ret = array(); 405 439 406 if ( !_flag_column_exists('flag_content', 'fcid')) {440 if (db_column_exists('flag_content', 'fcid')) { 407 441 db_drop_primary_key($ret, 'flag_content'); 408 442 db_add_field($ret, 'flag_content', 'fcid', array( … … 447 481 448 482 /** 449 * Add auto-increment to the flags.fid column for users upgrading from Drupal 5.483 * Remove count = 0 rows from the count tables. 450 484 */ 451 485 function flag_update_6004() { 452 // Update removed and included in flag_update_6000()486 // Same update as flag_update_6203() 453 487 return array(); 454 488 } 455 489 456 490 /** 457 * Remove count = 0 rows from the flag_counts table for consistency. 458 */ 459 function flag_update_6005() { 491 * Convert role access to have separate "flag" and "unflag" permissions. 492 */ 493 function flag_update_6200() { 494 $ret = array(); 495 496 if (db_column_exists('flags', 'roles')) { 497 $result = db_query('SELECT * FROM {flags}'); 498 while ($flag = db_fetch_object($result)) { 499 $roles = array_filter(explode(',', $flag->roles)); 500 $options = unserialize($flag->options); 501 $options['roles'] = array( 502 'flag' => $roles, 503 'unflag' => $roles, 504 ); 505 db_query("UPDATE {flags} SET options = '%s' WHERE fid = %d", serialize($options), $flag->fid); 506 } 507 db_drop_field($ret, 'flags', 'roles'); 508 } 509 510 return $ret; 511 } 512 513 /** 514 * Refine the indexes. 515 * 516 * The content type inclusion actually slowed down on unique key. And a count 517 * index would be helpful for sorting by counts. 518 */ 519 function flag_update_6201() { 520 $ret = array(); 521 522 // Remove "content type" from one key, see http://drupal.org/node/612602. 523 db_drop_unique_key($ret, 'flag_content', 'fid_content_type_content_id_uid'); 524 db_add_unique_key($ret, 'flag_content', 'fid_content_id_uid', array('fid', 'content_id', 'uid')); 525 526 // Add a count index, see http://drupal.org/node/489610. 527 db_add_index($ret, 'flag_counts', 'count', array('count')); 528 529 return $ret; 530 } 531 532 /** 533 * Add the sid column and unique index on the flag_content table. 534 */ 535 function flag_update_6202() { 536 $ret = array(); 537 538 // Drop the keys affected by the addition of the SID column. 539 db_drop_unique_key($ret, 'flag_content', 'fid_content_id_uid'); 540 db_drop_index($ret, 'flag_content', 'content_type_uid'); 541 542 // Add the column. 543 db_add_field($ret, 'flag_content', 'sid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)); 544 545 // Re-add the removed keys. 546 db_add_unique_key($ret, 'flag_content', 'fid_content_id_uid_sid', array('fid', 'content_id', 'uid', 'sid')); 547 db_add_index($ret, 'flag_content', 'content_type_uid_sid', array('content_type', 'uid', 'sid')); 548 549 return $ret; 550 } 551 552 /** 553 * Remove count = 0 rows from the count tables. 554 */ 555 function flag_update_6203() { 460 556 $ret = array(); 461 557 $ret[] = update_sql("DELETE FROM {flag_counts} WHERE count = 0"); … … 474 570 return array('success' => $result !== FALSE, 'query' => check_plain($sql)); 475 571 } 476 477 // D5/6 compatible version of db_column_exists().478 function _flag_column_exists($table, $column) {479 if (function_exists('db_column_exists')) {480 return db_column_exists($table, $column);481 }482 483 switch ($GLOBALS['db_type']) {484 case 'mysql':485 case 'mysqli':486 return (bool) db_fetch_object(db_query("SHOW COLUMNS FROM {flags} LIKE 'flag_short'"));487 case 'pgsql':488 return (bool) db_result(db_query("SELECT COUNT(pg_attribute.attname) FROM pg_class, pg_attribute WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relname = '{". db_escape_table($table) ."}' AND attname = '". db_escape_table($column) ."'"));489 }490 } -
drupal-6/sites/all/modules/flag/flag.module
r865 r867 1 1 <?php 2 // $Id: flag.module,v 1.11.2.7 8 2010/01/08 04:47:21quicksketch Exp $2 // $Id: flag.module,v 1.11.2.72.2.31 2010/01/08 05:17:57 quicksketch Exp $ 3 3 4 4 /** … … 6 6 * The Flag module. 7 7 */ 8 9 define('FLAG_API_VERSION', 2); 8 10 9 11 include_once dirname(__FILE__) .'/flag.inc'; … … 58 60 'file' => 'includes/flag.admin.inc', 59 61 'type' => MENU_LOCAL_TASK, 62 'weight' => 1, 63 ); 64 $items['admin/build/flags/import'] = array( 65 'title' => 'Import', 66 'page callback' => 'drupal_get_form', 67 'page arguments' => array('flag_import_form'), 68 'access arguments' => array('administer flags'), 69 'type' => MENU_LOCAL_TASK, 70 'file' => 'includes/flag.export.inc', 71 'weight' => 2, 72 ); 73 $items['admin/build/flags/export'] = array( 74 'title' => 'Export', 75 'page callback' => 'drupal_get_form', 76 'page arguments' => array('flag_export_form'), 77 'access arguments' => array('administer flags'), 78 'type' => MENU_LOCAL_TASK, 79 'file' => 'includes/flag.export.inc', 80 'weight' => 3, 81 ); 82 $items['admin/build/flags/update/%'] = array( 83 'title' => 'Update', 84 'page callback' => 'flag_update_page', 85 'page arguments' => array(4), 86 'access arguments' => array('administer flags'), 87 'type' => MENU_CALLBACK, 88 'file' => 'includes/flag.export.inc', 60 89 ); 61 90 $items['flag'] = array( … … 89 118 include_once $path .'/includes/flag.token.inc'; 90 119 } 120 if (module_exists('session_api')) { 121 // Set the anonymous user SID immediately, in case the user logs in. 122 flag_set_sid(); 123 } 91 124 } 92 125 … … 102 135 103 136 /** 137 * Implementation of hook_features_api(). 138 */ 139 function flag_features_api() { 140 return array( 141 'flag' => array( 142 'feature_source' => TRUE, 143 'default_hook' => 'flag_default_flags', 144 'file' => drupal_get_path('module', 'flag') . '/includes/flag.features.inc', 145 ), 146 ); 147 } 148 149 /** 104 150 * Implementation of hook_perm(). 105 151 */ … … 114 160 */ 115 161 function flag_access($flag, $account = NULL) { 116 return $flag->user_access( $account);162 return $flag->user_access('flag', $account); 117 163 } 118 164 … … 145 191 global $user; 146 192 147 // Anonymous users can't create flags with this system.148 if (!$user->uid) {149 return;150 }151 152 193 // Get all possible flags for this content-type. 153 194 $flags = flag_get_flags($type); 154 195 155 196 foreach ($flags as $flag) { 156 if (!$flag->user_access($user)) { 157 // User has no permission to use this flag. 158 continue; 159 } 197 $content_id = $flag->get_content_id($object); 198 160 199 if (!$flag->uses_hook_link($teaser)) { 161 200 // Flag is not configured to show its link here. 162 201 continue; 163 202 } 164 if (!$flag->applies_to_content_object($object)) { 165 // Flag does not apply to this content. 203 if (!$flag->access($content_id) && (!$flag->is_flagged($content_id) || !$flag->access($content_id, 'flag'))) { 204 // User has no permission to use this flag or flag does not apply to this 205 // content. The link is not skipped if the user has "flag" access but 206 // not "unflag" access (this way the unflag denied message is shown). 166 207 continue; 167 208 } 168 209 169 $content_id = $flag->get_content_id($object);170 210 // The flag links are actually fully rendered theme functions. 171 211 // The HTML attribute is set to TRUE to allow whatever the themer desires. … … 201 241 $token = flag_get_token($content_id); 202 242 return array( 203 'href' => "flag/". ($flag->link_type == 'confirm' ? 'confirm/' : '') ."$action/$flag->name/$content_id",243 'href' => 'flag/'. ($flag->link_type == 'confirm' ? 'confirm/' : '') ."$action/$flag->name/$content_id", 204 244 'query' => drupal_get_destination() . ($flag->link_type == 'confirm' ? '' : '&token='. $token), 205 245 ); … … 211 251 function flag_flag_link_types() { 212 252 return array( 213 'toggle' => t('JavaScript toggle'), 214 'normal' => t('Normal link'), 215 'confirm' => t('Confirmation form'), 253 'toggle' => array( 254 'title' => t('JavaScript toggle'), 255 'description' => t('An AJAX request will be made and degrades to type "Normal link" if JavaScript is not available.'), 256 ), 257 'normal' => array( 258 'title' => t('Normal link'), 259 'description' => t('A normal non-JavaScript request will be made and the current page will be reloaded.'), 260 ), 261 'confirm' => array( 262 'title' => t('Confirmation form'), 263 'description' => t('The user will be taken to a confirmation form on a separate page to confirm the flag.'), 264 'options' => array( 265 'flag_confirmation' => '', 266 'unflag_confirmation' => '', 267 ), 268 ), 216 269 ); 217 270 } … … 256 309 $form['workflow']['flag'][$var] = array( 257 310 '#type' => 'checkbox', 258 '#title' => $flag->get_label('flag_short' ),311 '#title' => $flag->get_label('flag_short', $form['#node_type']->type), 259 312 '#default_value' => variable_get($var .'_'. $form['#node_type']->type, 0), 260 313 '#return_value' => 1, … … 274 327 } 275 328 } 276 elseif (isset($form['type']) && isset($form['#node']) 277 && ($form_id == $form['type']['#value'] .'_node_form')) { 278 if (!$user->uid) { 279 return; 280 } 281 329 elseif (isset($form['type']) && isset($form['#node']) && ($form_id == $form['type']['#value'] .'_node_form')) { 282 330 $nid = !empty($form['nid']['#value']) ? $form['nid']['#value'] : NULL; 283 284 331 $flags = flag_get_flags('node', $form['type']['#value'], $user); 285 332 286 333 // Filter out flags which need to be included on the node form. 334 $flags_in_form = 0; 335 $flags_visible = 0; 287 336 foreach ($flags as $name => $flag) { 288 337 if (!$flag->show_on_form) { 289 unset($flags[$name]); 290 } 291 } 292 293 if (count($flags)) { 294 $form['flag'] = array( 295 '#type' => 'fieldset', 338 continue; 339 } 340 341 if (isset($form['#node']->flag[$flag->name])) { 342 $flag_status = $form['#node']->flag[$flag->name]; 343 } 344 else { 345 $flag_status_default = variable_get('flag_' . $flag->name . '_default_' . $form['type']['#value'], 0); 346 $flag_status = $nid ? $flag->is_flagged($nid) : $flag_status_default; 347 } 348 349 // If the flag is not global and the user doesn't have access, skip it. 350 // Global flags have their value set even if the user doesn't have access 351 // to it, similar to the way "published" and "promote" keep the default 352 // values even if the user doesn't have "administer nodes" permission. 353 $access = $flag->access($nid, $flag_status ? 'unflag' : 'flag', $user); 354 if (!$access && !$flag->global) { 355 continue; 356 } 357 358 // Add the flag checkbox if displaying on the form. 359 $form['flag'][$flag->name] = array( 360 '#type' => 'checkbox', 361 '#title' => $flag->get_label('flag_short', $nid ? $nid : $form['type']['#value']), 362 '#description' => $flag->get_label('flag_long', $nid ? $nid : $form['type']['#value']), 363 '#default_value' => $flag_status, 364 '#return_value' => 1, 365 ); 366 // If the user does not have access to the flag, set as a value. 367 if (!$access) { 368 $form['flag'][$flag->name]['#type'] = 'value'; 369 $form['flag'][$flag->name]['#value'] = $flag_status; 370 } 371 else { 372 $flags_visible++; 373 } 374 $flags_in_form++; 375 } 376 if ($flags_in_form) { 377 $form['flag'] += array( 296 378 '#weight' => module_exists('content') ? content_extra_field_weight($form['#node']->type, 'flags') : 1, 297 379 '#tree' => TRUE, 380 ); 381 } 382 if ($flags_visible) { 383 $form['flag'] += array( 384 '#type' => 'fieldset', 298 385 '#title' => t('Flags'), 299 386 '#collapsible' => TRUE, … … 301 388 } 302 389 303 foreach ($flags as $flag) {304 if (isset($form['#node']->flag[$flag->name])) {305 $flag_status = $form['#node']->flag[$flag->name];306 }307 else {308 $flag_status_default = variable_get('flag_' . $flag->name . '_default_' . $form['type']['#value'], 0);309 $flag_status = $nid ? $flag->is_flagged($nid) : $flag_status_default;310 }311 $form['flag'][$flag->name] = array(312 '#type' => 'checkbox',313 '#title' => $flag->get_label('flag_short', $nid),314 '#description' => $flag->get_label('flag_long', $nid),315 '#default_value' => $flag_status,316 '#return_value' => 1,317 );318 }319 390 } 320 391 } … … 341 412 $remembered = TRUE; 342 413 } 343 flag($state ? 'flag' : 'unflag', $name, $node->nid );414 flag($state ? 'flag' : 'unflag', $name, $node->nid, $user, TRUE); 344 415 } 345 416 } … … 377 448 function flag_user($op, &$edit, &$account, $category = NULL) { 378 449 switch ($op) { 450 case 'login': 451 // Migrate anonymous flags to this user's account. 452 if (module_exists('session_api')) { 453 // The @ symbol suppresses errors if the user flags a piece of content 454 // they have already flagged as a logged-in user. 455 @db_query("UPDATE {flag_content} SET uid = %d, sid = 0 WHERE uid = 0 AND sid = %d", $account->uid, flag_get_sid(0)); 456 // Delete any remaining flags this user had as an anonymous user. 457 db_query("DELETE FROM {flag_content} WHERE uid = 0 AND sid = %d", flag_get_sid(0)); 458 // Clean up anonymous cookies. 459 if (isset($_COOKIE['flags'])) { 460 setcookie('flags', FALSE, 0, base_path()); 461 unset($_COOKIE['flags']); 462 } 463 foreach ($_COOKIE as $key => $value) { 464 if (strpos($key, 'flag_global_') === 0) { 465 setcookie($key, FALSE, 0, base_path()); 466 unset($_COOKIE[$key]); 467 } 468 } 469 } 470 break; 379 471 case 'delete': 380 472 // Remove flags by this user. … … 390 482 $flag_items = array(); 391 483 foreach ($flags as $flag) { 392 if (!$flag-> user_access()) {484 if (!$flag->access($account->uid)) { 393 485 // User has no permission to use this flag. 394 continue;395 }396 if (!$flag->applies_to_content_object($account)) {397 // Flag does not apply to this content.398 486 continue; 399 487 } … … 422 510 423 511 /** 512 * Implementation of hook_session_api_cleanup(). 513 * 514 * Clear out anonymous user flaggings during Session API cleanup. 515 */ 516 function flag_session_api_cleanup($arg = 'run') { 517 // Session API 1.1 version: 518 if ($arg == 'run') { 519 $result = db_query("SELECT fc.sid FROM {flag_content} fc LEFT JOIN {session_api} s ON (fc.sid = s.sid) WHERE fc.sid <> 0 AND s.sid IS NULL"); 520 while ($row = db_fetch_object($result)) { 521 db_query("DELETE FROM {flag_content} WHERE sid = %d", $row->sid); 522 } 523 } 524 // Session API 1.2+ version. 525 elseif (is_array($arg)) { 526 $outdated_sids = $arg; 527 db_query('DELETE FROM {flag_content} WHERE sid IN (' . implode(',', $outdated_sids) . ')'); 528 } 529 } 530 531 /** 424 532 * Implementation of hook_node_type(). 425 533 */ … … 431 539 break; 432 540 } 541 } 542 543 /** 544 * Implementation of hook_activity_info(). 545 */ 546 function flag_activity_info() { 547 $info = new stdClass(); 548 $info->api = 2; 549 $info->name = 'flag'; 550 // The order of objects here matters. If a user is both the author and the 551 // flagging user, the flagging user message takes precedence. 552 $info->objects = array('node author' => 'node', 'flagging user' => 'account', 'comment author' => 'comment'); 553 $info->hooks = array('flag' => array('flag', 'unflag')); 554 555 // Figure out the activity access control realms and the types. 556 $flags = flag_get_flags(); 557 foreach ($flags as $fid => $flag) { 558 $info->realms["flag_" . $flag->fid] = $flag->title; 559 // Currently, flagging a user cannot be recorded. 560 if ($flag->content_type != 'user') { 561 $info->type_options[$flag->fid] = $flag->title; 562 } 563 } 564 $info->object_type = 'flag'; 565 $info->path = drupal_get_path('module', 'flag') . '/includes'; 566 return $info; 433 567 } 434 568 … … 557 691 function flag_flag($action, $flag, $content_id, $account) { 558 692 if (module_exists('trigger')) { 559 560 $flag_action = $flag->get_flag_action($content_id); 561 $flag_action->action = $action; 562 $context = (array)$flag_action; 563 $aids = _trigger_get_hook_aids($action, $action); 564 foreach ($aids as $aid => $action_info) { 693 $context['hook'] = 'flag'; 694 $context['account'] = $account; 695 $context['flag'] = $flag; 696 $context['op'] = $action; 697 698 // We add to the $context all the objects we know about: 699 $context = array_merge($flag->get_relevant_action_objects($content_id), $context); 700 701 // Generic "all flags" actions. 702 foreach (_trigger_get_hook_aids($action, $action) as $aid => $action_info) { 565 703 // The 'if ($aid)' is a safeguard against http://drupal.org/node/271460#comment-886564 566 704 if ($aid) { … … 568 706 } 569 707 } 570 708 // Actions specifically for this flag. 709 foreach (_trigger_get_hook_aids($action . '_' . $flag->name, $action) as $aid => $action_info) { 710 if ($aid) { 711 actions_do($aid, $flag, $context); 712 } 713 } 571 714 } 572 715 … … 579 722 580 723 /** 724 * Implementation of hook_flag_access(). 725 */ 726 function flag_flag_access($flag, $content_id, $action, $account) { 727 // Restrict access by authorship. It's important that TRUE is never returned 728 // here, otherwise we'd grant permission even if other modules denied access. 729 if ($flag->content_type == 'node') { 730 $node = node_load($content_id); 731 if ($flag->access_author == 'own' && $node->uid != $account->uid) { 732 return FALSE; 733 } 734 elseif ($flag->access_author == 'others' && $node->uid == $account->uid) { 735 return FALSE; 736 } 737 } 738 739 // Restrict access by comment authorship. 740 if ($flag->content_type == 'comment') { 741 $comment = _comment_load($content_id); 742 $node = node_load($comment->nid); 743 if ($flag->access_author == 'node_own' && $node->uid != $account->uid) { 744 return FALSE; 745 } 746 elseif ($flag->access_author == 'node_others' && $node->uid == $account->uid) { 747 return FALSE; 748 } 749 elseif ($flag->access_author == 'comment_own' && $comment->uid != $account->uid) { 750 return FALSE; 751 } 752 elseif ($flag->access_author == 'comment_others' && $comment->uid == $account->uid) { 753 return FALSE; 754 } 755 } 756 } 757 758 /** 759 * Implementation of hook_flag_access_multiple(). 760 */ 761 function flag_flag_access_multiple($flag, $content_ids, $account) { 762 $access = array(); 763 764 if ($flag->content_type == 'node') { 765 // Restrict access by authorship. This is similar to flag_flag_access() 766 // above, but returns an array of 'nid' => $access values. Similarly, we 767 // should never return TRUE in any of these access values, only FALSE if we 768 // want to deny access, or use the current access value provided by Flag. 769 $nids = implode(',', array_map('intval', array_keys($content_ids))); 770 $placeholders = implode(',', array_fill(0, sizeof($flag->types), "'%s'")); 771 $result = db_query("SELECT nid, uid FROM {node} WHERE nid IN ($nids) AND type in ($placeholders)", $flag->types); 772 while ($row = db_fetch_object($result)) { 773 if ($flag->access_author == 'own') { 774 $access[$row->nid] = $row->uid != $account->uid ? FALSE : NULL; 775 } 776 elseif ($flag->access_author == 'others') { 777 $access[$row->nid] = $row->uid == $account->uid ? FALSE : NULL; 778 } 779 } 780 } 781 782 if ($flag->content_type == 'comment') { 783 // Restrict access by comment ownership. 784 $cids = implode(',', array_map('intval', array_keys($content_ids))); 785 $result = db_query("SELECT c.cid, c.nid, c.uid as comment_uid, n.nid as node_uid FROM {comments} c LEFT JOIN {node} n ON c.nid = n.nid WHERE cid IN ($cids)"); 786 while ($row = db_fetch_object($result)) { 787 if ($flag->access_author == 'node_own') { 788 $access[$row->cid] = $row->node_uid != $account->uid ? FALSE : NULL; 789 } 790 elseif ($flag->access_author == 'node_others') { 791 $access[$row->cid] = $row->node_uid == $account->uid ? FALSE : NULL; 792 } 793 elseif ($flag->access_author == 'comment_own') { 794 $access[$row->cid] = $row->comment_uid != $account->uid ? FALSE : NULL; 795 } 796 elseif ($flag->access_author == 'comment_others') { 797 $access[$row->cid] = $row->comment_uid == $account->uid ? FALSE : NULL; 798 } 799 } 800 } 801 802 // Always return an array (even if empty) of accesses. 803 return $access; 804 } 805 /** 806 * Trim a flag to a certain size. 807 * 808 * @param $fid 809 * The flag object. 810 * @param $account 811 * The user object on behalf the trimming will occur. 812 * @param $cutoff_size 813 * The number of flaggings allowed. Any flaggings beyond that will be trimmed. 814 */ 815 function flag_trim_flag($flag, $account, $cutoff_size) { 816 $result = db_query("SELECT * FROM {flag_content} WHERE fid = %d AND (uid = %d OR uid = 0) ORDER BY timestamp DESC", $flag->fid, $account->uid); 817 $i = 1; 818 while ($row = db_fetch_object($result)) { 819 if ($i++ > $cutoff_size) { 820 flag('unflag', $flag->name, $row->content_id, $account); 821 } 822 } 823 } 824 825 /** 581 826 * Implementation of hook_node_operations(). 582 827 * … … 590 835 591 836 foreach ($flags as $flag) { 592 $operations['flag_' . $flag->name] = array(837 $operations['flag_' . $flag->name] = array( 593 838 'label' => $flag->get_label('flag_short'), 594 839 'callback' => 'flag_nodes', … … 596 841 'behavior' => array(), 597 842 ); 598 $operations['unflag_' . $flag->name] = array(843 $operations['unflag_' . $flag->name] = array( 599 844 'label' => $flag->get_label('unflag_short'), 600 845 'callback' => 'flag_nodes', … … 614 859 $performed |= flag($action, $flag_name, $nid); 615 860 } 616 // Drupal 6 doesn't display a confirmation message itself, so it's our responsibility.617 861 if ($performed) { 618 862 drupal_set_message(t('The update has been performed.')); 863 } 864 } 865 866 /** 867 * Implementation of hook_user_operations(). 868 */ 869 function flag_user_operations() { 870 global $user; 871 872 $flags = flag_get_flags('user', NULL, $user); 873 $operations = array(); 874 875 foreach ($flags as $flag) { 876 $operations['flag_' . $flag->name] = array( 877 'label' => $flag->get_label('flag_short'), 878 'callback' => 'flag_users', 879 'callback arguments' => array('flag', $flag->name), 880 ); 881 $operations['unflag_' . $flag->name] = array( 882 'label' => $flag->get_label('unflag_short'), 883 'callback' => 'flag_users', 884 'callback arguments' => array('unflag', $flag->name), 885 ); 886 } 887 return $operations; 888 } 889 /** 890 * Callback function for hook_user_operations(). 891 */ 892 function flag_users($users, $action, $flag_name) { 893 foreach ($users as $uid) { 894 flag($action, $flag_name, $uid); 619 895 } 620 896 } … … 630 906 break; 631 907 } 908 } 909 910 /** 911 * Implementation of hook_service(). 912 */ 913 function flag_service() { 914 $items = array(); 915 916 $items[] = array( 917 '#method' => 'flag.flag', 918 '#callback' => 'flag_service_flag', 919 '#access callback' => 'flag_service_flag_access', 920 '#file' => array( 921 'file' => 'inc', 922 'module' => 'flag', 923 'file name' => 'includes/flag.services', 924 ), 925 '#args' => array( 926 array( 927 '#name' => 'flag_name', 928 '#type' => 'string', 929 '#description' => t('The name of the flag.'), 930 ), 931 array( 932 '#name' => 'content_id', 933 '#type' => 'int', 934 '#description' => t('The content ID.'), 935 ), 936 array( 937 '#name' => 'uid', 938 '#type' => 'int', 939 '#description' => t('The user ID for which to flag.'), 940 '#optional' => TRUE, 941 ), 942 array( 943 '#name' => 'action', 944 '#type' => 'string', 945 '#description' => t('Optional; The action to perform, default is "flag". Should be "flag" or "unflag".'), 946 '#optional' => TRUE, 947 ), 948 array( 949 '#name' => 'skip_permission_check', 950 '#type' => 'boolean', 951 '#description' => t('Optional; Flag the content even if the user does not have permission to do so. FALSE by default'), 952 '#optional' => TRUE, 953 ), 954 ), 955 '#return' => 'boolean', 956 '#help' => t('Flags (or unflags) a content.') 957 ); 958 959 $items[] = array( 960 '#method' => 'flag.is_flagged', 961 '#callback' => 'flag_service_is_flagged', 962 '#access callback' => 'flag_service_flag_access', 963 '#file' => array( 964 'file' => 'inc', 965 'module' => 'flag', 966 'file name' => 'includes/flag.services', 967 ), 968 '#args' => array( 969 array( 970 '#name' => 'flag_name', 971 '#type' => 'string', 972 '#description' => t('The name of the flag.'), 973 ), 974 array( 975 '#name' => 'content_id', 976 '#type' => 'int', 977 '#description' => t('The content ID.'), 978 ), 979 array( 980 '#name' => 'uid', 981 '#type' => 'int', 982 '#description' => t('The user ID that might have flagged the content.'), 983 '#optional' => TRUE, 984 ), 985 ), 986 '#return' => 'boolean', 987 '#help' => t('Check if a content was flagged by a user.') 988 ); 989 990 return $items; 632 991 } 633 992 … … 651 1010 'arguments' => array('flags' => NULL, 'default_flags' => NULL), 652 1011 ), 1012 'flag_form_roles' => array( 1013 'arguments' => array('element' => NULL), 1014 ), 653 1015 'flag_rules_radios' => array( 654 1016 'arguments' => array(), … … 668 1030 * 669 1031 * See 'flag.tpl.php' for their documentation. 670 *671 * Note: The Drupal 5 version of this module calls this function directly.672 1032 */ 673 1033 function template_preprocess_flag(&$variables) { 1034 global $user; 674 1035 static $first_time = TRUE; 675 1036 … … 678 1039 $action = $variables['action']; 679 1040 $content_id = $variables['content_id']; 1041 $flag_css_name = str_replace('_', '-', $flag->name); 680 1042 681 1043 // Generate the link URL. 682 $link_types = flag_get_link_types(); 683 $link_type_module = $link_types[$flag->link_type]['module']; 684 $link = module_invoke($link_type_module, 'flag_link', $flag, $action, $content_id); 1044 $link_type = $flag->get_link_type(); 1045 $link = module_invoke($link_type['module'], 'flag_link', $flag, $action, $content_id); 685 1046 if (isset($link['title']) && empty($link['html'])) { 686 1047 $link['title'] = check_plain($link['title']); 687 1048 } 688 1049 689 if ($flag->link_type == 'toggle' && $first_time) { 1050 // Replace the link with the access denied text if unable to flag. 1051 if ($action == 'unflag' && !$flag->access($content_id, 'unflag')) { 1052 $link['title'] = $flag->get_label('unflag_denied_text', $content_id); 1053 unset($link['href']); 1054 } 1055 1056 // Tell the template file to add JavaScript/CSS if using the toggle link type. 1057 // Anonymous users always need the JavaScript to maintain their flag state. 1058 if (($flag->link_type == 'toggle' || $user->uid == 0) && $first_time) { 690 1059 $variables['setup'] = $first_time; 691 1060 $first_time = FALSE; … … 695 1064 } 696 1065 697 $variables['link_href'] = check_url(url($link['href'], $link));1066 $variables['link_href'] = isset($link['href']) ? check_url(url($link['href'], $link)) : FALSE; 698 1067 $variables['link_text'] = isset($link['title']) ? $link['title'] : $flag->get_label($action . '_short', $content_id); 699 1068 $variables['link_title'] = isset($link['attributes']['title']) ? check_plain($link['attributes']['title']) : check_plain(strip_tags($flag->get_label($action . '_long', $content_id))); 700 $variables['flag_name_css'] = str_replace('_', '-', $flag->name);701 1069 $variables['last_action'] = ($action == 'flag' ? 'unflagged' : 'flagged'); 1070 1071 $variables['flag_wrapper_classes_array'] = array(); 1072 $variables['flag_wrapper_classes_array'][] = 'flag-wrapper'; 1073 $variables['flag_wrapper_classes_array'][] = 'flag-' . $flag_css_name; 1074 $variables['flag_wrapper_classes_array'][] = 'flag-' . $flag_css_name . '-' . $content_id; 1075 $variables['flag_wrapper_classes'] = implode(' ', $variables['flag_wrapper_classes_array']); 1076 702 1077 $variables['flag_classes_array'] = array(); 703 1078 $variables['flag_classes_array'][] = 'flag'; 704 1079 $variables['flag_classes_array'][] = $variables['action'] .'-action'; 705 1080 $variables['flag_classes_array'][] = 'flag-link-'. $flag->link_type; 706 707 1081 if (isset($link['attributes']['class'])) { 708 1082 $variables['flag_classes_array'][] = $link['attributes']['class']; 709 1083 } 710 711 1084 if ($variables['after_flagging']) { 712 1085 $inverse_action = ($action == 'flag' ? 'unflag' : 'flag'); … … 714 1087 $variables['flag_classes_array'][] = $variables['last_action']; 715 1088 } 716 717 1089 $variables['flag_classes'] = implode(' ', $variables['flag_classes_array']); 718 1090 } … … 797 1169 } 798 1170 1171 /** 1172 * Return an array of flag link type descriptions. 1173 */ 1174 function _flag_link_type_descriptions() { 1175 $options = array(); 1176 $types = flag_get_link_types(); 1177 foreach ($types as $type_name => $type) { 1178 $options[$type_name] = $type['description']; 1179 } 1180 return $options; 1181 } 1182 1183 /** 1184 * Return an array of flag link fields that are dependent on a link type. 1185 */ 1186 function _flag_link_type_fields() { 1187 $options = array(); 1188 $types = flag_get_link_types(); 1189 foreach ($types as $type_name => $type) { 1190 $options[$type_name] = array_keys($type['options']); 1191 } 1192 return $options; 1193 } 1194 799 1195 // --------------------------------------------------------------------------- 800 1196 // Non-Views public API … … 835 1231 836 1232 /** 1233 * Get the total count of items flagged within a flag. 1234 * 1235 * @param $flag_name 1236 * The flag name for which to retrieve a flag count. 1237 * @param $reset 1238 * Reset the internal cache and execute the SQL query another time. 1239 */ 1240 function flag_get_flag_counts($flag_name, $reset = FALSE) { 1241 static $counts; 1242 1243 if ($reset) { 1244 $counts = array(); 1245 } 1246 if (!isset($counts[$flag_name])) { 1247 $flag = flag_get_flag($flag_name); 1248 $counts[$flag_name] = db_result(db_query("SELECT COUNT(*) FROM {flag_content} WHERE fid = %d", $flag->fid)); 1249 } 1250 1251 return $counts[$flag_name]; 1252 } 1253 1254 /** 837 1255 * Load a single flag either by name or by flag ID. 838 1256 * … … 856 1274 } 857 1275 } 1276 return FALSE; 858 1277 } 859 1278 … … 917 1336 } 918 1337 } 1338 1339 // Allow modules implementing hook_flag_alter(&$flag) to modify each flag. 1340 foreach ($flags as $flag) { 1341 drupal_alter('flag', $flag); 1342 } 919 1343 } 920 1344 … … 961 1385 $flag = flag_flag::factory_by_array($config); 962 1386 $flag->module = $module; 1387 1388 // Disable flags that are not at the current API version. 1389 if (!isset($flag->api_version) || $flag->api_version < FLAG_API_VERSION) { 1390 $flag->status = FALSE; 1391 $flag->api_version = isset($flag->api_version) ? $flag->api_version : 1; 1392 } 1393 963 1394 // Add flags that have been enabled. 964 1395 if ((!isset($flag_status[$flag->name]) && (!isset($flag->status) || $flag->status)) || !empty($flag_status[$flag->name])) { … … 966 1397 $default_flags[$flag->name] = $flag; 967 1398 } 1399 // Add flags that have been disabled. 968 1400 elseif ($include_disabled) { 969 1401 $flag->status = FALSE; … … 974 1406 975 1407 return $default_flags; 1408 } 1409 1410 /** 1411 * Get all flagged content in a flag. 1412 * 1413 * @param 1414 * The flag name for which to retrieve flagged content. 1415 */ 1416 function flag_get_flagged_content($flag_name) { 1417 $return = array(); 1418 $flag = flag_get_flag($flag_name); 1419 $result = db_query("SELECT * FROM {flag_content} WHERE fid = %d", $flag->fid); 1420 while ($row = db_fetch_object($result)) { 1421 $return[] = $row; 1422 } 1423 return $return; 1424 } 1425 1426 /** 1427 * Get content ID from a flag content ID. 1428 * 1429 * @param $fcid 1430 * The flag content ID for which to look up the content ID. 1431 */ 1432 function flag_get_content_id($fcid) { 1433 return db_result(db_query("SELECT content_id FROM {flag_content} WHERE fcid = %d", $fcid)); 976 1434 } 977 1435 … … 987 1445 * Optional. The user ID whose flags we're checking. If none given, the 988 1446 * current user will be used. 1447 * @param $sid 1448 * Optional. The user SID (provided by Session API) whose flags we're 1449 * checking. If none given, the current user will be used. The SID is 0 for 1450 * logged in users. 989 1451 * @param $reset 990 1452 * Reset the internal cache and execute the SQL query another time. … … 998 1460 * 999 1461 */ 1000 function flag_get_user_flags($content_type, $content_id = NULL, $uid = NULL, $ reset = FALSE) {1462 function flag_get_user_flags($content_type, $content_id = NULL, $uid = NULL, $sid = NULL, $reset = FALSE) { 1001 1463 static $flagged_content; 1002 1464 … … 1009 1471 1010 1472 $uid = !isset($uid) ? $GLOBALS['user']->uid : $uid; 1473 $sid = !isset($sid) ? flag_get_sid($uid) : $sid; 1011 1474 1012 1475 if (isset($content_id)) { 1013 1476 if (!isset($flagged_content[$uid][$content_type][$content_id])) { 1014 1477 $flag_names = _flag_get_flag_names(); 1015 $flagged_content[$uid][$ content_type][$content_id] = array();1016 $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND content_id = %d AND (uid = %d OR uid = 0) ", $content_type, $content_id, $uid);1478 $flagged_content[$uid][$sid][$content_type][$content_id] = array(); 1479 $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND content_id = %d AND (uid = %d OR uid = 0) AND sid = %s", $content_type, $content_id, $uid, $sid); 1017 1480 while ($flag_content = db_fetch_object($result)) { 1018 $flagged_content[$uid][$ content_type][$content_id][$flag_names[$flag_content->fid]] = $flag_content;1019 } 1020 } 1021 return $flagged_content[$uid][$ content_type][$content_id];1481 $flagged_content[$uid][$sid][$content_type][$content_id][$flag_names[$flag_content->fid]] = $flag_content; 1482 } 1483 } 1484 return $flagged_content[$uid][$sid][$content_type][$content_id]; 1022 1485 } 1023 1486 1024 1487 else { 1025 if (!isset($flagged_content[$uid][ 'all'][$content_type])) {1488 if (!isset($flagged_content[$uid][$sid]['all'][$content_type])) { 1026 1489 $flag_names = _flag_get_flag_names(); 1027 $flagged_content[$uid][ 'all'][$content_type] = TRUE;1028 $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND (uid = %d OR uid = 0) ", $content_type, $uid);1490 $flagged_content[$uid][$sid]['all'][$content_type] = TRUE; 1491 $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND (uid = %d OR uid = 0) AND sid = %s", $content_type, $uid, $sid); 1029 1492 while ($flag_content = db_fetch_object($result)) { 1030 $flagged_content[$uid][$ content_type]['all'][$flag_names[$flag_content->fid]][$flag_content->content_id] = $flag_content;1031 } 1032 } 1033 return $flagged_content[$uid][$ content_type]['all'];1493 $flagged_content[$uid][$sid][$content_type]['all'][$flag_names[$flag_content->fid]][$flag_content->content_id] = $flag_content; 1494 } 1495 } 1496 return $flagged_content[$uid][$sid][$content_type]['all']; 1034 1497 } 1035 1498 … … 1038 1501 /** 1039 1502 * Return a list of users who have flagged a piece of content. 1040 */ 1041 function flag_get_content_flags($content_type, $content_id, $reset = FALSE) { 1503 * 1504 * @param $content_type 1505 * The type of content that will be retrieved. Usually 'node'. 1506 * @param $content_id 1507 * The content ID to check for flagging. 1508 * @param $flag_name 1509 * Optional. The name of a flag if wanting a list specific to a single flag. 1510 * @param $reset 1511 * Reset the internal cache of flagged content. 1512 * @return 1513 * If no flag name is given, an array of flagged content, keyed by the user 1514 * ID that flagged the content. Each flagged content array is structured as 1515 * an array of flag information for each flag, keyed by the flag name. If 1516 * a flag name is specified, only the information for that flag is returned. 1517 */ 1518 function flag_get_content_flags($content_type, $content_id, $flag_name = NULL, $reset = FALSE) { 1042 1519 static $content_flags; 1043 1520 … … 1046 1523 $result = db_query("SELECT * FROM {flag_content} WHERE content_type = '%s' AND content_id = %d ORDER BY timestamp DESC", $content_type, $content_id); 1047 1524 while ($flag_content = db_fetch_object($result)) { 1525 // Build a list of flaggings for all flags by user. 1048 1526 $content_flags[$content_type][$content_id]['users'][$flag_content->uid][$flag_names[$flag_content->fid]] = $flag_content; 1049 } 1050 } 1051 1052 return $content_flags[$content_type][$content_id]['users']; 1527 // Build a list of flaggings for each individual flag. 1528 $content_flags[$content_type][$content_id]['flags'][$flag_names[$flag_content->fid]][$flag_content->uid] = $flag_content; 1529 } 1530 } 1531 1532 return isset($flag_name) ? $content_flags[$content_type][$content_id]['flags'][$flag_name] : $content_flags[$content_type][$content_id]['users']; 1053 1533 } 1054 1534 … … 1073 1553 return; 1074 1554 } 1075 if (!$flag-> user_access()) {1555 if (!$flag->access($content_id)) { 1076 1556 // User has no permission to use this flag. 1077 return;1078 }1079 if (!$flag->applies_to_content_id($content_id)) {1080 // Flag does not apply to this content.1081 1557 return; 1082 1558 } … … 1094 1570 foreach (module_implements('flag_link_types') as $module) { 1095 1571 $module_types = module_invoke($module, 'flag_link_types'); 1096 foreach ($module_types as $type_name => $type_title) { 1097 $link_types[$type_name] = array( 1098 'module' => $module, 1099 'title' => $type_title, 1572 foreach ($module_types as $type_name => $info) { 1573 $link_types[$type_name] = $info; 1574 $link_types[$type_name]['module'] = $module; 1575 $link_types[$type_name] += array( 1576 'title' => '', 1577 'description' => '', 1578 'options' => array(), 1100 1579 ); 1101 1580 } 1102 1581 } 1582 drupal_alter('flag_link_types', $link_types); 1103 1583 } 1104 1584 … … 1109 1589 * Get a private token used to protect links from spoofing - CSRF. 1110 1590 */ 1111 function flag_get_token($nid) { 1112 return drupal_get_token($nid); 1591 function flag_get_token($content_id) { 1592 // Anonymous users get a less secure token, since it must be the same for all 1593 // anonymous users on the entire site to work with page caching. 1594 return ($GLOBALS['user']->uid) ? drupal_get_token($content_id) : md5(drupal_get_private_key() . $content_id); 1113 1595 } 1114 1596 … … 1116 1598 * Check to see if a token value matches the specified node. 1117 1599 */ 1118 function flag_check_token($token, $seed) { 1119 return drupal_get_token($seed) == $token; 1120 } 1600 function flag_check_token($token, $content_id) { 1601 return flag_get_token($content_id) == $token; 1602 } 1603 1604 /** 1605 * Set the Session ID for a user. Utilizes the Session API module. 1606 * 1607 * This function is only called in flag_init(), to set the current user's 1608 * SID in case the user logs in during this request. 1609 */ 1610 function flag_set_sid($uid = NULL) { 1611 static $sids = array(); 1612 1613 if (!isset($uid)) { 1614 $uid = $GLOBALS['user']->uid; 1615 } 1616 1617 if (!isset($sids[$uid])) { 1618 if (module_exists('session_api') && session_api_available() && $uid == 0) { 1619 $sids[$uid] = session_api_get_sid(); 1620 } 1621 else { 1622 $sids[$uid] = 0; 1623 } 1624 } 1625 1626 return $sids[$uid]; 1627 } 1628 1629 /** 1630 * Get the Session ID for a user. Utilizes the Session API module. 1631 */ 1632 function flag_get_sid($uid = NULL) { 1633 return flag_set_sid($uid); 1634 } -
drupal-6/sites/all/modules/flag/flag_actions.info
r865 r867 5 5 dependencies[] = flag 6 6 package = Flags 7 ; Information added by drupal.org packaging script on 2010-01-088 version = "6.x-1.2"9 core = "6.x"10 project = "flag"11 datestamp = "1262929205"12 -
drupal-6/sites/all/modules/flag/flag_actions.install
r535 r867 1 1 <?php 2 // $Id: flag_actions.install,v 1.1.2.2 2008/09/30 03:08:49quicksketch Exp $2 // $Id: flag_actions.install,v 1.1.2.2.2.1 2009/09/19 01:30:46 quicksketch Exp $ 3 3 4 4 /** … … 48 48 'type' => 'int', 49 49 'size' => 'small', 50 'not null' => FALSE, 50 'not null' => TRUE, 51 'default' => 0, 52 'disp-width' => '5', 53 ), 54 'repeat_threshold' => array( 55 'type' => 'int', 56 'size' => 'small', 57 'not null' => TRUE, 58 'default' => 0, 51 59 'disp-width' => '5', 52 60 ), … … 68 76 return $schema; 69 77 } 78 79 /** 80 * Add a "repeat_threshold" value to all existing Flag actions. 81 */ 82 function flag_actions_update_6200() { 83 $ret = array(); 84 85 // Add the new repeat_threshold column. 86 if (!db_column_exists('flag_actions', 'repeat_threshold')) { 87 $column = array( 88 'type' => 'int', 89 'size' => 'small', 90 'not null' => TRUE, 91 'default' => 0, 92 'disp-width' => '5', 93 ); 94 db_add_field($ret, 'flag_actions', 'repeat_threshold', $column); 95 } 96 97 // Update the normal threshold column to default to 0. 98 $column = array( 99 'type' => 'int', 100 'size' => 'small', 101 'not null' => TRUE, 102 'default' => 0, 103 'disp-width' => '5', 104 ); 105 db_change_field($ret, 'flag_actions', 'threshold', 'threshold', $column); 106 107 return $ret; 108 } -
drupal-6/sites/all/modules/flag/flag_actions.module
r865 r867 1 1 <?php 2 // $Id: flag_actions.module,v 1.1.2.1 3 2009/09/14 11:58:32quicksketch Exp $2 // $Id: flag_actions.module,v 1.1.2.12.2.5 2009/09/29 02:27:37 quicksketch Exp $ 3 3 4 4 /** … … 79 79 function flag_actions_get_actions($flag_name = NULL, $reset = FALSE) { 80 80 static $flag_actions; 81 module_load_include('inc', 'flag', 'includes/flag.actions'); 81 82 82 83 // Get a list of all possible actions defined by modules. … … 126 127 * @param $fid 127 128 * The flag object ID. 129 * @param $event 130 * The flag event, such as "flag" or "unflag". 128 131 * @param $threshold 129 132 * The flagging threshold at which this action will be executed. 133 * @param $repeat_threshold 134 * The number of additional flaggings after which the action will be repeated. 130 135 * @param $callback 131 136 * The action callback to be executed. … … 133 138 * The action parameters. 134 139 */ 135 function flag_actions_insert_action($fid, $event, $threshold, $ callback, $parameters) {136 db_query("INSERT INTO {flag_actions} (fid, event, threshold, callback, parameters) VALUES (%d, '%s', %d, '%s', '%s')", $fid, $event, $threshold, $callback, serialize($parameters));140 function flag_actions_insert_action($fid, $event, $threshold, $repeat_threshold, $callback, $parameters) { 141 db_query("INSERT INTO {flag_actions} (fid, event, threshold, repeat_threshold, callback, parameters) VALUES (%d, '%s', %d, %d, '%s', '%s')", $fid, $event, $threshold, $repeat_threshold, $callback, serialize($parameters)); 137 142 return db_last_insert_id('flag_actions', 'aid'); 138 143 } … … 143 148 * @param $aid 144 149 * The flag action ID to update. 150 * @param $event 151 * The flag event, such as "flag" or "unflag". 145 152 * @param $threshold 146 153 * The flagging threshold at which this action will be executed. 154 * @param $repeat_threshold 155 * The number of additional flaggings after which the action will be repeated. 147 156 * @param $parameters 148 157 * The action parameters. 149 158 */ 150 function flag_actions_update_action($aid, $event, $threshold, $ parameters) {151 return db_query("UPDATE {flag_actions} SET event = '%s', threshold = %d, parameters = '%s' WHERE aid = %d", $event, $threshold, serialize($parameters), $aid);159 function flag_actions_update_action($aid, $event, $threshold, $repeat_threshold, $parameters) { 160 return db_query("UPDATE {flag_actions} SET event = '%s', threshold = %d, repeat_threshold = %d, parameters = '%s' WHERE aid = %d", $event, $threshold, $repeat_threshold, serialize($parameters), $aid); 152 161 } 153 162 … … 177 186 $node_changed = FALSE; 178 187 foreach ($actions as $aid => $action) { 179 $threshold = ($action->event == $event) && 180 (($action->event == 'flag' && $count == $action->threshold) || 181 ($action->event == 'unflag' && $count == $action->threshold - 1)); 182 if ($threshold && !$action->missing) { 188 if ($action->event == 'flag') { 189 $at_threshold = ($count == $action->threshold); 190 $repeat = $action->repeat_threshold ? (($count > $action->threshold) && (($count - $action->threshold) % $action->repeat_threshold == 0)) : FALSE; 191 } 192 elseif ($action->event == 'unflag') { 193 $at_threshold = ($count == $action->threshold - 1); 194 $repeat = $action->repeat_threshold ? (($count < $action->threshold - 1) && (($count - $action->threshold - 1) % $action->repeat_threshold == 0)) : FALSE; 195 } 196 if (($at_threshold || $repeat) && $action->event == $event && !$action->missing) { 183 197 $context = $action->parameters; 184 198 $context['callback'] = $action->callback; … … 240 254 $flag = flag_get_flag($action->flag); 241 255 256 // Build a sample string representing repeating actions. 257 if ($action->repeat_threshold) { 258 $repeat_count = 3; 259 $repeat_subtract = ($action->event == 'flag') ? 1 : -1; 260 $repeat_samples = array(); 261 for ($n = 1; $n < $repeat_count + 2; $n++) { 262 $sample = $action->threshold + (($n * $action->repeat_threshold) * $repeat_subtract); 263 if ($sample > 0) { 264 $repeat_samples[] = $sample; 265 } 266 } 267 if (count($repeat_samples) > $repeat_count) { 268 $repeat_samples[$repeat_count] = '…'; 269 } 270 $repeat_string = implode(', ', $repeat_samples); 271 } 272 else { 273 $repeat_string = '-'; 274 } 275 242 276 $row = array(); 243 277 $row[] = $flag->get_title(); 244 $row[] = ($action->event == 'flag' ? '⥠' : '< ') . $action->threshold; 278 $row[] = ($action->event == 'flag' ? '≥ ' : '< ') . $action->threshold; 279 $row[] = $repeat_string; 245 280 $row[] = empty($action->missing) ? $action->description : '<div class="error">' . $action->description . '</div>'; 246 281 $row[] = l(t('edit'), 'admin/build/flags/actions/configure/'. $action->aid); … … 256 291 t('Flag'), 257 292 t('Threshold'), 293 t('Repeats'), 258 294 t('Action'), 259 295 array('data' => t('Operations'), 'colspan' => 2), … … 380 416 $action->event = 'flag'; 381 417 $action->threshold = 10; 418 $action->repeat_threshold = 0; 382 419 drupal_set_title(t('Add "@action" action to the @title flag', array('@action' => $action->description, '@title' => $flag->get_title()))); 383 420 } … … 388 425 '#theme' => 'flag_actions_flag_form', 389 426 '#action' => $action, 427 '#flag' => $flag, 390 428 ); 391 429 … … 422 460 ); 423 461 462 $form['flag']['repeat_threshold'] = array( 463 '#type' => 'textfield', 464 '#size' => 6, 465 '#maxlength' => 6, 466 '#default_value' => $action->repeat_threshold, 467 ); 468 469 if ($flag->global) { 470 $form['flag']['threshold']['#disabled'] = 1; 471 $form['flag']['threshold']['#value'] = 1; 472 $form['flag']['repeat_threshold']['#access'] = FALSE; 473 $form['flag']['repeat_threshold']['#value'] = 0; 474 } 475 476 // Merge in the standard flag action form. 424 477 $action_form = $callback .'_form'; 478 $edit = array(); 425 479 if (function_exists($action_form)) { 426 $edit = $action->parameters;480 $edit += $action->parameters; 427 481 $edit['actions_description'] = $action->description; 428 482 $edit['actions_type'] = $action->type; 429 $form = array_merge($form, $action_form($edit)); 430 } 431 483 $edit['actions_flag'] = $flag->name; 484 $additions = flag_actions_form_additions($action_form, $edit); 485 $form = array_merge($form, $additions); 486 } 487 488 // Add a few customizations to existing flag actions. 432 489 $flag_actions_form = 'flag_actions_'. $callback .'_form'; 433 490 if (function_exists($flag_actions_form)) { 434 $flag_actions_form($form, $flag, isset($edit) ? $edit : array());491 $flag_actions_form($form, $flag, $edit); 435 492 } 436 493 … … 441 498 442 499 return $form; 500 } 501 502 /** 503 * Execute an action form callback to retrieve form additions. 504 * 505 * This function prevents the form callback from modifying local variables. 506 */ 507 function flag_actions_form_additions($callback, $edit) { 508 return $callback($edit); 443 509 } 444 510 … … 455 521 } 456 522 457 $aid = $form_state['values']['flag']['aid']; 458 $flag = $form_state['values']['flag']['flag']; 459 $event = $form_state['values']['flag']['event']; 460 $threshold = $form_state['values']['flag']['threshold']; 461 $callback = $form_state['values']['flag']['callback']; 523 $aid = $form_state['values']['flag']['aid']; 524 $flag = $form_state['values']['flag']['flag']; 525 $event = $form_state['values']['flag']['event']; 526 $threshold = $form_state['values']['flag']['threshold']; 527 $repeat_threshold = $form_state['values']['flag']['repeat_threshold']; 528 $callback = $form_state['values']['flag']['callback']; 462 529 463 530 $parameters = $form_state['values']; … … 465 532 466 533 if (empty($aid)) { 467 $aid = flag_actions_insert_action($flag->fid, $event, $threshold, $ callback, $parameters);534 $aid = flag_actions_insert_action($flag->fid, $event, $threshold, $repeat_threshold, $callback, $parameters); 468 535 $form_state['values']['flag']['aid'] = $aid; 469 536 $form_state['values']['flag']['is_new'] = TRUE; 470 537 } 471 538 else { 472 flag_actions_update_action($aid, $event, $threshold, $ parameters);539 flag_actions_update_action($aid, $event, $threshold, $repeat_threshold, $parameters); 473 540 } 474 541 … … 482 549 $event = drupal_render($form['event']); 483 550 $threshold = drupal_render($form['threshold']); 551 $repeat_threshold = drupal_render($form['repeat_threshold']); 484 552 $action = $form['#action']->description; 485 553 … … 487 555 $output .= '<div class="container-inline">'; 488 556 $output .= t('Perform action when content !event !threshold flags', array('!event' => $event, '!threshold' => $threshold)); 557 if ($form['#flag']->global) { 558 $output .= ' ' . t('(global flags always have a threshold of 1)'); 559 } 560 $output .= '</div>'; 561 $output .= '<div class="container-inline">'; 562 if (!$form['#flag']->global) { 563 $output .= t('Repeat this action every !repeat_threshold additional flags after the threshold is reached', array('!repeat_threshold' => $repeat_threshold)); 564 } 489 565 $output .= '</div>'; 490 566 491 567 $element = array( 492 568 '#title' => t('Flagging threshold'), 493 '#description' => t('Set the event for which this action should be executed.'),494 569 '#required' => TRUE, 495 570 ); … … 527 602 } 528 603 604 /** 605 * Make modifications to the "Send e-mail" action form. 606 */ 529 607 function flag_actions_system_send_email_action_form(&$form, &$flag, $context) { 530 608 $form['flag_tip'] = array( … … 536 614 '#weight' => -1, 537 615 ); 538 return $form; 539 } 540 616 } 617 618 /** 619 * Make modifications to the "Send tokenized e-mail" action form. 620 */ 541 621 function flag_actions_token_actions_send_email_action_form(&$form, &$flag, $context) { 542 622 if (!isset($context['recipient'])) { -
drupal-6/sites/all/modules/flag/includes/flag.rules.inc
r865 r867 1 1 <?php 2 // $Id: flag.rules.inc,v 1.1.2.2 2009/05/06 23:37:47quicksketch Exp $2 // $Id: flag.rules.inc,v 1.1.2.2.2.2 2009/11/03 01:53:36 quicksketch Exp $ 3 3 4 4 /** … … 46 46 47 47 /** 48 * Returns radios for selecting a flag of the type given in 48 * Returns radios for selecting a flag of the type given in 49 49 * $info['flag_type']. 50 50 */ … … 83 83 $flags = flag_get_flags(); 84 84 foreach ($flags as $flag) { 85 85 86 86 $arguments = array( 87 87 // First, define ubiquitous arguments. … … 166 166 if ($flag->rules_get_element_argument_definition()) { 167 167 $args += array('object' => $flag->rules_get_element_argument_definition()); 168 168 169 169 $items += array( 170 170 'flag_rules_action_flag_'. $type => array( … … 215 215 216 216 /** 217 * Base action implementation .217 * Base action implementation: Trim flag. 218 218 */ 219 219 function flag_rules_action_trim($flag, $flagging_user, $cutoff_size, $settings) { 220 // We can't use db_query_range(), because we can't specify 'infinity'. 221 $result = db_query("SELECT * FROM {flag_content} WHERE fid = %d AND (uid = %d OR uid = 0) ORDER BY timestamp DESC", $flag->fid, $flagging_user->uid); 222 $i = 1; 223 while ($row = db_fetch_object($result)) { 224 if ($i++ > $cutoff_size) { 225 flag('unflag', $flag->name, $row->content_id, $flagging_user); 226 } 227 } 220 flag_trim_flag($flag, $flagging_user, $cutoff_size); 228 221 } 229 222 … … 244 237 if ($flag->rules_get_element_argument_definition()) { 245 238 $args += array('object' => $flag->rules_get_element_argument_definition()); 246 239 247 240 $items += array( 248 241 'flag_rules_condition_threshold_'. $type => array( -
drupal-6/sites/all/modules/flag/includes/flag.views_default.inc
r535 r867 1 1 <?php 2 // $Id: flag.views_default.inc,v 1.1.2.5 2009/02/22 22:20:39quicksketch Exp $2 // $Id: flag.views_default.inc,v 1.1.2.5.2.1 2009/09/28 02:05:06 quicksketch Exp $ 3 3 4 4 /** … … 104 104 $access = array( 105 105 'type' => 'role', 106 'role' => drupal_map_assoc($flag->roles ),106 'role' => drupal_map_assoc($flag->roles['flag']), 107 107 'perm' => '', 108 108 ); -
drupal-6/sites/all/modules/flag/includes/flag_handler_field_ops.inc
r865 r867 1 1 <?php 2 // $Id: flag_handler_field_ops.inc,v 1.1.2. 6 2010/01/08 04:48:43quicksketch Exp $2 // $Id: flag_handler_field_ops.inc,v 1.1.2.5.2.3 2010/01/08 04:43:17 quicksketch Exp $ 3 3 4 4 /** … … 83 83 'numeric' => TRUE, 84 84 ); 85 $join->extra[] = array( 86 'field' => 'sid', 87 'value' => flag_get_sid(), 88 'numeric' => TRUE, 89 ); 85 90 } 86 91 $flag_table = $this->query->add_table('flag_content', $parent, $join); … … 103 108 $flag = $this->get_flag(); 104 109 105 if (!$flag->user_access()) {106 // User has no permission to use this flag.107 return;108 }109 110 110 $ids = array(); 111 111 foreach ($values as $row) { 112 112 $content_id = $row->{$this->aliases['content_id']}; 113 $is_flagged = $row-&
