diff --git a/includes/comment.inc b/includes/comment.inc index 84d46ae..b7cbf64 100644 --- a/includes/comment.inc +++ b/includes/comment.inc @@ -571,18 +571,156 @@ function project_issue_update_by_comment($comment_data, $op) { // Update the issue data to reflect the new final states. db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, sid = %d, priority_weight = %d WHERE nid = %d", $comment_data->pid, $comment_data->category, $comment_data->component, $comment_data->priority, $comment_data->rid, $comment_data->assigned, $comment_data->sid, $priority_weight, $comment_data->nid); - // Update the issue title. - $node = node_load($comment_data->nid, NULL, TRUE); // Don't use cached since we changed data above. - $node->title = $comment_data->title; - - // This also updates the changed date of the issue. - node_save($node); + // Update the issue title, in case it changed. + // Don't use cached since we changed data above. + $node = node_load($comment_data->nid, NULL, TRUE); + // @todo Check whether we *always* have to save a new revision. Unpublishing/ + // deleting comments might unconditionally revert the issue node revision. + if ($node->title !== $comment_data->title) { + $node->title = $comment_data->title; + + // Saving the node will potentially create a new node revision, if enabled. + // Node module's node_save() and _node_save_revision() would set the node + // revision author to the current user (the one who wrote an issue comment), + // change the node revision created/changed date as well as other node + // revision properties. + // However, for this node update, only the title of the issue node should be + // changed and saved as a new revision (so the change may be reverted). All + // other properties of the previous node revision should be left unchanged, + // since the comment author did not edit the node, she only wrote a comment. + // Therefore, we need to replace the behavior of the private + // _node_save_revision() helper function; which forces us to also replace + // node_save() to call it. + _project_issue_node_save($node); + + // Clear the static node_load() cache. + node_load(NULL, NULL, TRUE); + } // Return the object of comment data we used to update the issue. return $comment_data; } /** + * Save a node object into the database. + * + * @see project_issue_update_by_comment() + * @see _project_issue_node_save_revision() + * @see node_save() + */ +function _project_issue_node_save(&$node) { + // Let modules modify the node before it is saved to the database. + node_invoke_nodeapi($node, 'presave'); + global $user; + + // Insert a new node. + $node->is_new = empty($node->nid); + + if ($node->is_new || !empty($node->revision)) { + // When inserting a node, $node->log must be set because + // {node_revisions}.log does not (and cannot) have a default + // value. If the user does not have permission to create + // revisions, however, the form will not contain an element for + // log so $node->log will be unset at this point. + if (!isset($node->log)) { + $node->log = ''; + } + } + elseif (empty($node->log)) { + // When updating a node, however, avoid clobbering an existing + // log entry with an empty one. + unset($node->log); + } + + // For the same reasons, make sure we have $node->teaser and + // $node->body set. + if (!isset($node->teaser)) { + $node->teaser = ''; + } + if (!isset($node->body)) { + $node->body = ''; + } + + // Save the old revision if needed. + if (!$node->is_new && !empty($node->revision) && $node->vid) { + $node->old_vid = $node->vid; + } + + $time = time(); + if (empty($node->created)) { + $node->created = $time; + } + // The changed timestamp is always updated for bookkeeping purposes (revisions, searching, ...) + $node->changed = $time; + + $node->timestamp = $time; + $node->format = isset($node->format) ? $node->format : FILTER_FORMAT_DEFAULT; + + // Generate the node table query and the node_revisions table query. + if ($node->is_new) { + _project_issue_node_save_revision($node, $user->uid); + drupal_write_record('node', $node); + db_query('UPDATE {node_revisions} SET nid = %d WHERE vid = %d', $node->nid, $node->vid); + $op = 'insert'; + } + else { + drupal_write_record('node', $node, 'nid'); + if (!empty($node->revision)) { + _project_issue_node_save_revision($node, $user->uid); + db_query('UPDATE {node} SET vid = %d WHERE nid = %d', $node->vid, $node->nid); + } + else { + _project_issue_node_save_revision($node, $user->uid, 'vid'); + } + $op = 'update'; + } + + // Call the node specific callback (if any). + node_invoke($node, $op); + node_invoke_nodeapi($node, $op); + + // Update the node access table for this node. + node_access_acquire_grants($node); + + // Clear the page and block caches. + cache_clear_all(); +} + +/** + * Helper function to save a revision with the uid of the current user. + * + * Node is taken by reference, because drupal_write_record() updates the + * $node with the revision id, and we need to pass that back to the caller. + * + * @see project_issue_update_by_comment() + * @see _project_issue_node_save() + * @see _node_save_revision() + */ +function _project_issue_node_save_revision(&$node, $uid, $update = NULL) { + // This implementation of _node_save_revision() is only invoked when posting + // a comment, so there must be an existing node revision. If there is none + // for any reason, then something else went completely wrong. + if (empty($node->vid)) { + return; + } + // Only update title and uid. + $existing = db_fetch_object(db_query("SELECT * FROM {node_revisions} WHERE vid = %d", array($node->vid))); + // Set the node revision title. + $existing->title = $node->title; + // Set the node revision author to the comment author. + $existing->uid = $uid; + // Insert a new revision or update the existing one. + if (isset($update)) { + drupal_write_record('node_revisions', $existing, $update); + } + else { + drupal_write_record('node_revisions', $existing); + } + // Assign the potentially new revision id. + $node->vid = $existing->vid; +} + +/** * Adjusts the filepath of issue followups so files are saved to * the correct issues directory. *