# This patch file was generated by NetBeans IDE # It uses platform neutral UTF-8 encoding and \n newlines. --- Base (BASE) +++ Locally Modified (Based On LOCAL) @@ -6,7 +6,10 @@ define('USERPOINTS_POST', 'userpoints_post_'); define('USERPOINTS_POST_COMMENT', 'userpoints_post_comment'); +define('USERPOINTS_POST_UNDO_ON_DELETE', 'userpoints_post__undo_points_on_delete'); define('USERPOINTS_MODERATE_COMMENT', 'userpoints_moderate_comment'); +define('USERPOINTS_NODE_WORDS', 'userpoints_node_words'); +define('USERPOINTS_COMMENT_WORDS', 'userpoints_comment_words'); //define a variable to trigger the use of the v2bug please read drupal.org/node/183520 define('USERPOINTS_USE_V2BUG', 'userpoints_use_v2bug'); @@ -28,12 +31,20 @@ '#title' => t('!Points for posting nodes', userpoints_translation()), ); - $form[$group][USERPOINTS_POST . '_undo_points_on_delete'] = array( + $form[$group][USERPOINTS_POST_UNDO_ON_DELETE] = array( '#type' => 'checkbox', '#title' => t('Take away !points on node delete', array_merge(userpoints_translation())), - '#default_value' => variable_get(USERPOINTS_POST . '_undo_points_on_delete', true), + '#default_value' => variable_get(USERPOINTS_POST_UNDO_ON_DELETE, TRUE), ); + $form[$group][USERPOINTS_NODE_WORDS] = array( + '#type' => 'textfield', + '#title' => t('Minimum number of words required to earn !Points for posting a node', userpoints_translation()), + '#default_value' => variable_get(USERPOINTS_NODE_WORDS, 1), + '#size' => 5, + '#maxlength' => 5, + ); + foreach (node_get_types() as $type => $name) { $form[$group][USERPOINTS_POST . $type] = array( '#type' => 'textfield', @@ -43,6 +54,7 @@ '#maxlength' => 5, ); } + $group = 'comment'; $form[$group] = array( '#type' => 'fieldset', @@ -50,6 +62,15 @@ '#collapsed' => TRUE, '#title' => t('!Points for posting comments', userpoints_translation()), ); + + $form[$group][USERPOINTS_COMMENT_WORDS] = array( + '#type' => 'textfield', + '#title' => t('Minimum number of words required to earn !Points for posting a comment', userpoints_translation()), + '#default_value' => variable_get(USERPOINTS_COMMENT_WORDS, 1), + '#size' => 5, + '#maxlength' => 5, + ); + $form[$group][USERPOINTS_POST_COMMENT] = array( '#type' => 'textfield', '#title' => t('!Points for posting a comment', userpoints_translation()), @@ -65,6 +86,7 @@ '#size' => 5, '#maxlength' => 5, ); + $group = 'v2compatibility'; $form[$group] = array( '#type' => 'fieldset', @@ -97,210 +119,241 @@ } } +/** + * Implementation of hook_nodeapi + */ function userpoints_nodeapi(&$node, $op, $teaser, $page) { - //static up_orig_uid please read drupal.org/node/183520 + + // Static up_orig_uid used by v2 bugfix. See http://drupal.org/node/183520 static $up_orig_uid; + + // Get points for this node type $points = variable_get(USERPOINTS_POST . $node->type, 0); + switch ($op) { case 'insert': - $params = array( - 'points' => $points, - 'uid' => $node->uid, - 'operation' => 'insert', - 'entity_id' => $node->nid, - 'entity_type' => 'node' - ); - userpoints_userpointsapi($params); + userpoints_nc_entity_insert($node->nid, 'node', $node->uid, $points, $node->body); break; case 'delete': - if (variable_get(USERPOINTS_POST . '_undo_points_on_delete', true)) { - $points = -$points; - $params = array( - 'points' => $points, - 'uid' => $node->uid, - 'operation' => 'operation', - 'entity_id' => $node->nid, - 'entity_type' => 'node', - ); - userpoints_userpointsapi($params); + if (variable_get(USERPOINTS_POST_UNDO_ON_DELETE, TRUE)) { + userpoints_nc_entity_delete($node->nid, 'node', $node->uid); + // TODO: delete points for comments on this node here. See http://drupal.org/node/1216048 } break; case 'prepare': $up_orig_uid = $node->uid; break; case 'update': - //Find the last points granted on this node inserts and ownership gains - $sql = "SELECT points, uid - FROM {userpoints_txn} - WHERE entity_id = %d AND entity_type = '%s' - AND (operation = '%s' OR operation ='%s') - ORDER BY time_stamp DESC - LIMIT 1 - "; - $last_owner = db_fetch_object(db_query($sql, $node->nid, 'node', 'insert', 'Ownership gain')); - - //Check the UID of the original to this user, if different add/substract points - if ($node->uid != $last_owner->uid && is_numeric($last_owner->uid) ) { - //Check to see if this user has already lost the points for - // Add to the new node owner - $params = array( - 'points' => $points, - 'uid' => $node->uid, - 'operation' => 'Ownership gain', - 'entity_id' => $node->nid, - 'entity_type' => 'node' - ); - userpoints_userpointsapi($params); - // subtract from the original node owner - $params = array( - 'points' => -$points, - 'uid' => $up_orig_uid, - 'operation' => 'Ownership loss', - 'entity_id' => $node->nid, - 'entity_type' => 'node' - ); - userpoints_userpointsapi($params); - } - else { - //We failed to pull a matching operation via the DB - //If the user wants to use the V2BUG we'll use it.. - //please read drupal.org/node/183520 - if (variable_get(USERPOINTS_USE_V2BUG, false)) { - if ($node->uid != $up_orig_uid) { - // Add to the new node owner - $params = array( - 'points' => $points, - 'uid' => $node->uid, - 'operation' => 'Ownership gain', - 'entity_id' => $node->nid, - 'entity_type' => 'node' - ); - userpoints_userpointsapi($params); - // subtract from the original node owner - $params = array( - 'points' => -$points, - 'uid' => $up_orig_uid, - 'operation' => 'Ownership loss', - 'entity_id' => $node->nid, - 'entity_type' => 'node' - ); - userpoints_userpointsapi($params); - } - } - } + userpoints_nc_entity_update($node->nid, 'node', $node->uid, $up_orig_uid, $node->body, $points); break; } } +/** + * Implementation of hook_comment + */ function userpoints_comment($comment, $op) { - global $user; - //static up_orig_uid, please read this thread http://drupal.org/node/183520 + + // Static $up_orig_com_uid used by v2 bugfix. See http://drupal.org/node/183520 static $up_orig_com_uid; + // Get points for a comment $points = variable_get(USERPOINTS_POST_COMMENT, 0); + switch ($op) { case 'insert': - $params = array( - 'points' => $points, - 'uid' => $user->uid, - 'operation' => 'insert', - 'entity_id' => $comment['cid'], - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + userpoints_nc_entity_insert($comment['cid'], 'comment', $comment['uid'], $points, $comment['comment']); break; + case 'delete': - $points = -$points; - $params = array( - 'points' => $points, - 'uid' => $comment->uid, - 'operation' => 'delete', - 'entity_id' => $comment->cid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + userpoints_nc_entity_delete($comment->cid, 'comment', $comment->uid); break; + case 'moderate': - $points = variable_get(USERPOINTS_MODERATE_COMMENT, 0); - $params = array( - 'points' => $points, - 'uid' => $comment->uid, - 'operation' => 'moderate', - 'entity_id' => $comment->cid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + $modpoints = variable_get(USERPOINTS_MODERATE_COMMENT, 0); + userpoints_nc_entity_moderate($comment->cid, 'comment', $comment->uid, $modpoints); break; + case 'form': $up_orig_com_uid = $comment['uid']['#value']; break; + case 'update': - //Find the last points granted on this node inserts and ownership gains + userpoints_nc_entity_update($comment['cid'], 'comment', $comment['uid'], $up_orig_com_uid, $comment['comment'], $points); + break; + } +} + +/** + * Fetches the details of the last set of points granted for an entity + * + * @param int $entity_id - $cid or $nid + * @param string $entity_type - 'comment' or 'node' + * + * @return object + */ +function userpoints_nc_get_last_granted_points($entity_id, $entity_type) { + + if ($entity_type != 'comment' && $entity_type != 'node') { + return null; + } + $sql = "SELECT points, uid FROM {userpoints_txn} WHERE entity_id = %d AND entity_type = '%s' - AND (operation = '%s' OR operation ='%s') + AND (operation = '%s' OR operation = '%s' OR operation = '%s') ORDER BY time_stamp DESC - LIMIT 1 - "; - $cid = $comment['cid']; - $new_uid = $comment['uid']; - $last_owner = db_fetch_object(db_query($sql, $cid, 'comment', 'insert', 'Ownership gain')); + LIMIT 1"; - //Check the UID of the original to this user, if different add/substract points - if ($new_uid != $last_owner->uid && is_numeric($last_owner->uid) ) { - //The owner has changed so we're removing from the - //the original owner and giving to the new owner - //Give to the original owner - $points = $last_owner->points; - $params = array( - 'points' => $points, - 'uid' => $new_uid, - 'operation' => 'Ownership gain', - 'entity_id' => $cid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + return db_fetch_object(db_query($sql, (int) $entity_id, $entity_type, 'insert', 'update', 'Ownership gain')); +} - //Take away from the original owner - $params = array( - 'points' => -$points, - 'uid' => $last_owner->uid, - 'operation' => 'Ownership loss', - 'entity_id' => $cid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); +/** + * Checks that the entity passes word length restrictions required to earn points + * + * @return boolean + */ +function userpoints_nc_check_word_length($content, $entity_type = 'comment') { + if ($entity_type == 'node') { + $minwords = variable_get(USERPOINTS_NODE_WORDS, 1); } else { - //We failed to pull a matching operation via the DB - //If the user wants to use the V2BUG we'll use it.. - //please read drupal.org/node/183520 - if (variable_get(USERPOINTS_USE_V2BUG, false)) { - if ($orig_uid != $comment['uid']) { - $params = array( - 'points' => $points, - 'uid' => $new_uid, - 'operation' => 'Ownership gain', - 'entity_id' => $cid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + $minwords = variable_get(USERPOINTS_COMMENT_WORDS, 1); + } - //Take away from the original owner - $params = array( - 'points' => -$points, - 'uid' => $comment['uid'], - 'operation' => 'Ownership loss', - 'entity_id' => $new_uid, - 'entity_type' => 'comment' - ); - userpoints_userpointsapi($params); + // Return early and avoid regex below if check is unnecessary + if ($minwords < 2) { + return TRUE; } + + $wordcount = 0; + + // Make sure there is a space between adjacent html tags. Then strip them. + $content = strip_tags(str_replace('<', ' <', $content)); + + // Eliminate any quoted text between [quote] [/quote] tags + // Regex copied from quote.module + $content = preg_replace('#\[(quote.*?)]((?>\[(?!/?quote[^[]*?])|[^[]|(?R))*)\[/quote]#is', '', $content); + + // Reduce all whitespace characters to a single space between words. + // Then split the string at each whitespace and count the words. + if (!empty($content)) { + $content = trim(preg_replace('/\s+/', ' ', $content)); + $wordcount = count(explode(' ', $content)); } + + return $wordcount >= $minwords; } - break; + +/** + * Processes points changes on insertion of a comment or node + */ +function userpoints_nc_entity_insert($entity_id, $entity_type, $uid, $points, $content) { + + if ($points != 0 && userpoints_nc_check_word_length($content, $entity_type)) { + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, $points, 'insert'); } } +/** + * Processes points changes on deletion of a comment or node + */ +function userpoints_nc_entity_delete($entity_id, $entity_type, $uid) { + + // Find the last points granted on this entity for inserts and ownership gains + $last_points = userpoints_nc_get_last_granted_points($entity_id, $entity_type); + + if ($last_points && $last_points->points > 0) { + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, -$last_points->points, 'delete'); + } +} + +/** + * Processes points changes on moderation of a comment or node + */ +function userpoints_nc_entity_moderate($entity_id, $entity_type, $uid, $points) { + + if ($points != 0) { + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, $points, 'moderate'); + } +} + +/** + * Processes points changes on update of a comment or node + */ +function userpoints_nc_entity_update($entity_id, $entity_type, $uid, $orig_uid, $content, $points) { + + // Check if updated comment/node word length qualifies for points + $wordsok = userpoints_nc_check_word_length($content, $entity_type); + + // Find the last points granted on this entity + $last_points = userpoints_nc_get_last_granted_points($entity_id, $entity_type); + + // Compare the UID of the last points recorded vs the current $uid + $ownerchanged = $last_points && $uid != $last_points->uid && is_numeric($last_points->uid); + + // Check if ownership change is needed via v2 bugfix setting: http://drupal.org/node/183520 + $v2bugfix = !$last_points && variable_get(USERPOINTS_USE_V2BUG, FALSE) && $orig_uid != $uid; + + // Record ownership change. + if ($ownerchanged || $v2bugfix) { + + // Assign points to the new owner + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, $points, 'Ownership gain'); + + // If an owner changes but there are not enough words to qualify for points + // then we have a problem. New ownership must be recorded so that + // userpoints_nc_get_last_granted_points() will work next time the comment + // is updated. But userpointsapi won't accept 0 points on a transaction. + // So instead we do another transaction to subtract the points gained by + // the change of ownership. + if (!$wordsok) { + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, -$points, 'update'); + } + + // Subtract points from the previous owner + $uid = $v2bugfix ? $orig_uid : $last_points->uid; + $points = $v2bugfix ? $points : $last_points->points; + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, -$points, 'Ownership loss'); + + } + else if ($wordsok && (!$last_points || $last_points->points < 0)) { + + // Updating entity that previously did not meet the word requirements. + // The last points record either doesn't exist, or it is negative if the + // entity was updated and shortened to below the minimum word length. + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, $points, 'update'); + + } + else if ($wordsok && $last_points && $last_points->points != $points) { + + // Updating entity that earns different points now than it did before. + // Leave original points intact. Could be exploited by users updating + // all their old posts if admin increases points values. + + } + else if (!$wordsok && $last_points) { + + // Shortened entity content to less than minimum words. Subtract last points. + _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, -$last_points->points, 'update'); + + } + +} + +/** + * Inserts a userpointsapi transaction + */ +function _userpoints_nc_insert_transaction($entity_id, $entity_type, $uid, $points, $operation) { + + $params = array( + 'points' => $points, + 'uid' => $uid, + 'operation' => $operation, + 'entity_id' => $entity_id, + 'entity_type' => $entity_type, + ); + + userpoints_userpointsapi($params); +}