| 1 |
<?php
|
| 2 |
// $Id: comment_mover.module,v 1.21 2006/12/08 21:37:04 heine Exp $
|
| 3 |
|
| 4 |
define ('COMMENT_MOVER_NODE_TO_COMMENT', 1);
|
| 5 |
define ('COMMENT_MOVER_COMMENT_TO_NODE', 2);
|
| 6 |
define ('COMMENT_MOVER_COMMENT_TO_COMMENT', 3);
|
| 7 |
define ('COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD', 4);
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Implementation of hook_help
|
| 11 |
*/
|
| 12 |
function comment_mover_help($section) {
|
| 13 |
switch ($section) {
|
| 14 |
case 'admin/help#comment_mover':
|
| 15 |
$output = '<p>'. t('Comment mover enables you to move comments and nodes around by pruning and grafting. Pruning and grafting are similar to cut and paste but operate on branches, not on single comments. If you prune and graft a comment thread, the entire thread will be moved, not just the pruned comment.') .'</p>';
|
| 16 |
$output .= '<p>'. t('Basic use is simple; it starts by pruning a node or comment via the link prune. The pruned node/comment now appears in the Graft block. The graft block shows the title and author of the pruned content and always allows you to cancel the action. You can now navigate through your site and choose one of two options: grafting or conversion.') .'</p>';
|
| 17 |
$output .= '<p>'. t('Grafting is a simple matter: simply click the graft link on the content (comment or node) you want the pruned object to reside under. All childcomments will be moved together with the pruned node or comment') .'</p>';
|
| 18 |
|
| 19 |
$output .= '<p>'. t('If you just pruned a comment and enabled story and page under "Enable promotion to the following node types" on the <a href="@url">comment mover settings page</a>, the graft block also shows you story and page in the selection of node types to which the
|
| 20 |
comment can be converted. When you then, for example, select story and click convert, a story submission form will appear with prefilled fields. Edit if necessary, then click submit. A new story node will be created. All children of the original comment will be moved to the new node.', array('@url' => url('admin/settings/comment_mover'))) .'</p>';
|
| 21 |
$output .= '<p>'. t('When you move a comment to another node or convert it to a node, the original comment will contain a link pointing to the comments new location. When you move a node to become a comment on another node, the original node will contain a redirect to the new location.') .'</p>';
|
| 22 |
return $output;
|
| 23 |
}
|
| 24 |
}
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Implementation of hook_menu
|
| 28 |
*/
|
| 29 |
function comment_mover_menu($may_cache) {
|
| 30 |
$items = array();
|
| 31 |
|
| 32 |
$access = user_access('administer comments');
|
| 33 |
if ($may_cache) {
|
| 34 |
$items[] = array('path' => 'comment/cancel', 'title' => t('cancel pruning'),
|
| 35 |
'access' => $access,
|
| 36 |
'callback' => 'comment_mover_cancel',
|
| 37 |
'type' => MENU_CALLBACK);
|
| 38 |
$items[] = array('path' => 'admin/settings/comment_mover',
|
| 39 |
'title' => t('Comment mover'),
|
| 40 |
'description' => t('Configure comment mover to operate on specific content types.'),
|
| 41 |
'callback' => 'drupal_get_form',
|
| 42 |
'callback arguments' => 'comment_mover_settings',
|
| 43 |
'access' => user_access('administer site configuration'),
|
| 44 |
);
|
| 45 |
}
|
| 46 |
else {
|
| 47 |
$items[] = array('path' => 'comment/promote', 'title' => t('Promote comment'),
|
| 48 |
'callback' => 'comment_mover_promote', 'access' => $access,
|
| 49 |
'type' => MENU_CALLBACK);
|
| 50 |
|
| 51 |
$items[] = array('path' => 'comment/graft', 'title' => t('Prune comment'),
|
| 52 |
'callback' => 'comment_mover_graft', 'access' => $access,
|
| 53 |
'callback arguments' => array(arg(2), arg(3)),
|
| 54 |
'type' => MENU_CALLBACK);
|
| 55 |
|
| 56 |
$items[] = array('path' => 'comment/prune', 'title' => t('Prune comment'),
|
| 57 |
'callback' => 'comment_mover_prune', 'access' => $access,
|
| 58 |
'callback arguments' => array(arg(2), arg(3)),
|
| 59 |
'type' => MENU_CALLBACK);
|
| 60 |
}
|
| 61 |
|
| 62 |
return $items;
|
| 63 |
}
|
| 64 |
|
| 65 |
/**
|
| 66 |
* Implementation of hook_link
|
| 67 |
*/
|
| 68 |
function comment_mover_link($type, $object = 0, $teaser = FALSE) {
|
| 69 |
$links = array();
|
| 70 |
|
| 71 |
if ($type == 'comment' && user_access('administer comments')) {
|
| 72 |
$prune = comment_mover_pruning();
|
| 73 |
if ($prune) {
|
| 74 |
// Display graft link when
|
| 75 |
if (comment_mover_allows_grafting('comment', $object) && // grafting is allowed on the node type
|
| 76 |
$prune->cid != $object->cid && // comment is not the pruned comment
|
| 77 |
!($prune->nid == $object->nid && $prune->cid == 0) && // comment is not a child of the pruned node
|
| 78 |
!in_array($object->cid, comment_mover_get_children($prune->cid))) { // comment is not a child of the pruned comment
|
| 79 |
|
| 80 |
$links['comment_mover_comment_graft'] = array(
|
| 81 |
'title' => t('graft'),
|
| 82 |
'href' => "comment/graft/{$object->nid}/{$object->cid}",
|
| 83 |
);
|
| 84 |
}
|
| 85 |
}
|
| 86 |
else if (comment_mover_allows_pruning('comment', $object)) {
|
| 87 |
$links['comment_mover_comment_prune'] = array(
|
| 88 |
'title' => t('prune'),
|
| 89 |
'href' => "comment/prune/{$object->nid}/{$object->cid}",
|
| 90 |
);
|
| 91 |
}
|
| 92 |
}
|
| 93 |
else if ($type == 'node' && !$teaser && user_access('administer comments')) {
|
| 94 |
$prune = comment_mover_pruning();
|
| 95 |
if ($prune) {
|
| 96 |
// Display graft link when
|
| 97 |
if (comment_mover_allows_grafting('node', $object) && // grafting on node_type is set
|
| 98 |
!($prune->nid == $object->nid && $prune->cid == 0) && // node is not the pruned node
|
| 99 |
!($prune->nid == $object->nid && $prune->pid == 0)) { // node is not the direct parent of pruned comment
|
| 100 |
$links['comment_mover_node_graft'] = array(
|
| 101 |
'title' => t('Graft'),
|
| 102 |
'href' => "comment/graft/{$object->nid}",
|
| 103 |
);
|
| 104 |
}
|
| 105 |
}
|
| 106 |
else if (node_access('update', $object) && user_access('administer comments') && comment_mover_allows_pruning('node', $object)) {
|
| 107 |
$links['comment_mover_node_prune'] = array(
|
| 108 |
'title' => t('Prune'),
|
| 109 |
'href' => "comment/prune/{$object->nid}",
|
| 110 |
'query' => drupal_get_destination(),
|
| 111 |
);
|
| 112 |
}
|
| 113 |
}
|
| 114 |
return $links;
|
| 115 |
}
|
| 116 |
|
| 117 |
|
| 118 |
/**
|
| 119 |
* Displays node type select in block
|
| 120 |
*
|
| 121 |
*/
|
| 122 |
function comment_mover_promote_form() {
|
| 123 |
$form = array();
|
| 124 |
$options = array();
|
| 125 |
foreach (node_get_types() as $node_type) {
|
| 126 |
$type = $node_type->type;
|
| 127 |
$name = $node_type->name;
|
| 128 |
if (node_access('create', $type) && variable_get("commentmover_promotion_$type", FALSE)) {
|
| 129 |
$options[$type] = $name;
|
| 130 |
}
|
| 131 |
}
|
| 132 |
if (!empty($options)) {
|
| 133 |
$form['type'] = array(
|
| 134 |
'#type' => 'select',
|
| 135 |
'#title' => t('Convert to'),
|
| 136 |
'#default_value' => 'forum',
|
| 137 |
'#options' => $options,
|
| 138 |
);
|
| 139 |
$form['submit'] = array('#type' => 'submit', '#value' => t('Convert'));
|
| 140 |
}
|
| 141 |
return $form;
|
| 142 |
}
|
| 143 |
|
| 144 |
function comment_mover_promote_form_submit($form_id, $form_values) {
|
| 145 |
return "comment/promote/{$form_values['type']}" ;
|
| 146 |
}
|
| 147 |
|
| 148 |
|
| 149 |
/**
|
| 150 |
* Menu callback, directs to a node submission form of $type.
|
| 151 |
*/
|
| 152 |
function comment_mover_promote($type) {
|
| 153 |
global $user;
|
| 154 |
if (array_key_exists($type, node_get_types()) && node_access('create', $type) && variable_get("commentmover_promotion_$type", FALSE)) {
|
| 155 |
$prune = comment_mover_pruning();
|
| 156 |
if ($prune->nid && $prune->cid && user_access('administer comments') && comment_mover_allows_pruning('comment', $prune)) {
|
| 157 |
$comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data, n.title AS node_title FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid INNER JOIN {node} n ON c.nid = n.nid WHERE c.cid = %d AND c.status = 0', $prune->cid));
|
| 158 |
$comment = drupal_unpack($comment);
|
| 159 |
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
|
| 160 |
$node = array(
|
| 161 |
'uid' => $comment->uid,
|
| 162 |
'name' => $comment->uid ? $comment->name : '',
|
| 163 |
'type' => $type,
|
| 164 |
'body' => $comment->comment,
|
| 165 |
'title' => $comment->subject,
|
| 166 |
'created' => $comment->timestamp,
|
| 167 |
'comment_mover' => TRUE,
|
| 168 |
);
|
| 169 |
|
| 170 |
// Set name & warn the user when converting an anonymous comment to a blog post.
|
| 171 |
if ($type == 'blog' && $comment->uid == 0) {
|
| 172 |
$node['name'] = $user->name;
|
| 173 |
drupal_set_message(t('Author has been set to %username.', array('%username' => theme('username', $user))));
|
| 174 |
}
|
| 175 |
|
| 176 |
//$output = node_form($node);
|
| 177 |
$output = drupal_get_form($type .'_node_form', $node);
|
| 178 |
drupal_set_title(t('Submit %name', array('%name' => node_get_types('name', $node))));
|
| 179 |
return $output;
|
| 180 |
}
|
| 181 |
}
|
| 182 |
}
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Modify the node submission form to enable comment mover to do it's job in hook_nodeapi.
|
| 186 |
*/
|
| 187 |
function comment_mover_form_alter($form_id, &$form) {
|
| 188 |
if ($form['#id'] == 'node-form' && isset($form['#node']->comment_mover)) {
|
| 189 |
$form['comment_mover'] = array('#type' =>'value', '#value' => TRUE);
|
| 190 |
// Correct the data field; node_form_array only sets the date if the node already has a nid.
|
| 191 |
if (user_access('administer nodes')) {
|
| 192 |
$form['author']['date']['#default_value'] = $form['#node']->date;
|
| 193 |
}
|
| 194 |
}
|
| 195 |
}
|
| 196 |
|
| 197 |
function comment_mover_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
|
| 198 |
if ($op == 'insert' && $node->comment_mover == TRUE) {
|
| 199 |
$prune = comment_mover_pruning();
|
| 200 |
$comment = db_fetch_array(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data, n.title AS node_title FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid INNER JOIN {node} n ON c.nid = n.nid WHERE c.cid = %d AND c.status = 0', $prune->cid));
|
| 201 |
$comment['comment_mover'] = COMMENT_MOVER_COMMENT_TO_NODE;
|
| 202 |
$comment['new_nid'] = $node->nid;
|
| 203 |
comment_mover_move($comment);
|
| 204 |
comment_mover_unset();
|
| 205 |
}
|
| 206 |
}
|
| 207 |
|
| 208 |
/**
|
| 209 |
* Post the comments, children and updates the statistcis of both nodes.
|
| 210 |
*
|
| 211 |
*/
|
| 212 |
function comment_mover_comment_post($edit) {
|
| 213 |
global $user;
|
| 214 |
|
| 215 |
if (user_access('administer comments') && node_comment_mode($edit['nid']) == 2) {
|
| 216 |
if ($edit['cid'] && !$edit['comment_mover_multiple']) {
|
| 217 |
$thread = comment_mover_build_thread($edit);
|
| 218 |
|
| 219 |
db_query("UPDATE {comments} SET subject = '%s', comment = '%s', pid = %d, format = '%s', thread = '%s' WHERE cid = %d", $edit['subject'], $edit['comment'], $edit['pid'], $edit['format'], $thread, $edit['cid']);
|
| 220 |
|
| 221 |
_comment_update_node_statistics($edit['nid']);
|
| 222 |
|
| 223 |
// Allow modules to respond to the updating of a comment.
|
| 224 |
module_invoke_all('comment', 'update', $edit);
|
| 225 |
|
| 226 |
// Add an entry to the watchdog log.
|
| 227 |
watchdog('content', t('Comment: updated %subject.', array('%subject' => theme('placeholder', $edit['subject']))), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], NULL, NULL, 'comment-'. $edit['cid']));
|
| 228 |
}
|
| 229 |
else if ($edit['cid'] && $edit['comment_mover_multiple']) {
|
| 230 |
$thread = comment_mover_build_thread($edit);
|
| 231 |
|
| 232 |
db_query("UPDATE {comments} SET pid = %d, nid = %d, thread = '%s' WHERE cid = %d", $edit['pid'], $edit['nid'], $thread, $edit['cid']);
|
| 233 |
|
| 234 |
_comment_update_node_statistics($edit['nid']);
|
| 235 |
_comment_update_node_statistics($edit['old_nid']);
|
| 236 |
watchdog('content', t('Comment: moved %subject.', array('%subject' => theme('placeholder', $edit['subject']))), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], NULL, NULL, 'comment-'. $edit['cid']));
|
| 237 |
}
|
| 238 |
else {
|
| 239 |
// Add the comment to database.
|
| 240 |
$status = 0;
|
| 241 |
$roles = variable_get('comment_roles', array());
|
| 242 |
$score = 0;
|
| 243 |
|
| 244 |
foreach (array_intersect(array_keys($roles), array_keys($user->roles)) as $rid) {
|
| 245 |
$score = max($roles[$rid], $score);
|
| 246 |
}
|
| 247 |
|
| 248 |
$users = serialize(array(0 => $score));
|
| 249 |
|
| 250 |
$edit['cid'] = db_next_id('{comments}_cid');
|
| 251 |
$edit['timestamp'] = isset($edit['timestamp']) ? $edit['timestamp'] : time();
|
| 252 |
|
| 253 |
if ($edit['uid'] == $user->uid) {
|
| 254 |
$edit['name'] = $user->name;
|
| 255 |
}
|
| 256 |
else {
|
| 257 |
$account = user_load(array('uid' => $edit['uid']));
|
| 258 |
$edit['name'] = $account->name;
|
| 259 |
}
|
| 260 |
|
| 261 |
$thread = comment_mover_build_thread($edit);
|
| 262 |
|
| 263 |
db_query("INSERT INTO {comments} (cid, nid, pid, uid, subject, comment, format, hostname, timestamp, status, score, users, thread, name, mail, homepage) VALUES (%d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s')", $edit['cid'], $edit['nid'], $edit['pid'], $edit['uid'], $edit['subject'], $edit['comment'], $edit['format'], $_SERVER['REMOTE_ADDR'], $edit['timestamp'], $status, $score, $users, $thread, $edit['name'], $edit['mail'], $edit['homepage']);
|
| 264 |
|
| 265 |
_comment_update_node_statistics($edit['nid']);
|
| 266 |
|
| 267 |
// Tell the other modules a new comment has been submitted.
|
| 268 |
module_invoke_all('comment', 'insert', $edit);
|
| 269 |
|
| 270 |
// Add an entry to the watchdog log.
|
| 271 |
watchdog('content', t('Comment: added %subject.', array('%subject' => '<em>'. $edit['subject'] .'</em>')), l(t('view'), 'node/'. $edit['nid'], NULL, NULL, 'comment-'. $edit['cid']));
|
| 272 |
}
|
| 273 |
|
| 274 |
// Clear the cache so an anonymous user can see his comment being added.
|
| 275 |
cache_clear_all();
|
| 276 |
|
| 277 |
return $edit;
|
| 278 |
}
|
| 279 |
}
|
| 280 |
|
| 281 |
|
| 282 |
/**
|
| 283 |
* Returns a flat array of child cids
|
| 284 |
*
|
| 285 |
* @param array $cid
|
| 286 |
* @return bool
|
| 287 |
*
|
| 288 |
*/
|
| 289 |
function comment_mover_get_children($cid) {
|
| 290 |
static $childlist;
|
| 291 |
if (!isset($childlist)) {
|
| 292 |
$childlist = array();
|
| 293 |
$comment = comment_mover_load_comment($cid);
|
| 294 |
$thread = comment_mover_get_thread((array)$comment);
|
| 295 |
foreach ($thread as $depth => $children) {
|
| 296 |
foreach ($children as $child) {
|
| 297 |
$childlist[] = $child['cid'];
|
| 298 |
}
|
| 299 |
}
|
| 300 |
}
|
| 301 |
return $childlist;
|
| 302 |
}
|
| 303 |
|
| 304 |
/**
|
| 305 |
* Determines whether $cid is among comments in $thread
|
| 306 |
*/
|
| 307 |
function comment_mover_target_is_child($cid, $thread) {
|
| 308 |
if ($cid) {
|
| 309 |
// Check whether the intended target is a child of the object
|
| 310 |
foreach ($thread as $depth => $children) {
|
| 311 |
foreach ($children as $child) {
|
| 312 |
if ($child['cid'] == $cid) {
|
| 313 |
return TRUE;
|
| 314 |
}
|
| 315 |
}
|
| 316 |
}
|
| 317 |
}
|
| 318 |
return FALSE;
|
| 319 |
}
|
| 320 |
|
| 321 |
/**
|
| 322 |
* Make a copy of a comment or node and save node/ comment with new body.
|
| 323 |
* Move children of node or comment along.
|
| 324 |
*
|
| 325 |
* $object (array) the comment or node
|
| 326 |
* $pid (integer) parent id, default 0
|
| 327 |
* $nid (integer) node id, needed in case pid = 0
|
| 328 |
*/
|
| 329 |
function comment_mover_move($object, $pid = 0, $nid = 0) {
|
| 330 |
|
| 331 |
switch ($object['comment_mover']) {
|
| 332 |
case COMMENT_MOVER_COMMENT_TO_COMMENT:
|
| 333 |
case COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD:
|
| 334 |
$comment = $object;
|
| 335 |
$comment['pid'] = $pid;
|
| 336 |
if ($object['comment_mover'] == COMMENT_MOVER_COMMENT_TO_COMMENT) {
|
| 337 |
unset($comment['cid']);
|
| 338 |
}
|
| 339 |
break;
|
| 340 |
case COMMENT_MOVER_COMMENT_TO_NODE:
|
| 341 |
$new_nid = $object['new_nid'];
|
| 342 |
$comment = $object;
|
| 343 |
$comment['comment'] = t('This comment has been moved <a href="@url">here</a>.', array('@url' => url('node/'. $new_nid, NULL, NULL, TRUE)));
|
| 344 |
break;
|
| 345 |
case COMMENT_MOVER_NODE_TO_COMMENT:
|
| 346 |
$comment = $object;
|
| 347 |
$comment['comment'] = $object['body'];
|
| 348 |
$comment['subject'] = $object['title'];
|
| 349 |
$comment['status'] = 0;
|
| 350 |
break;
|
| 351 |
}
|
| 352 |
|
| 353 |
$comment['nid'] = $nid ? $nid : $object['nid'];
|
| 354 |
|
| 355 |
$thread = comment_mover_get_thread($object);
|
| 356 |
|
| 357 |
if ($comment['comment_mover'] == COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD && comment_mover_target_is_child($pid, $thread)) {
|
| 358 |
drupal_set_message(t('comment cannot be grafted on one of its children'));
|
| 359 |
return 0;
|
| 360 |
}
|
| 361 |
|
| 362 |
$new_comment = comment_mover_comment_post($comment);
|
| 363 |
foreach ($thread as $depth => $comments) {
|
| 364 |
foreach ($comments as $c) {
|
| 365 |
$c['old_nid'] = $c['nid'];
|
| 366 |
$c['nid'] = isset($new_nid) ? $new_nid : $new_comment['nid'];
|
| 367 |
$c['pid'] = ($depth == 1) ? (isset($new_nid) ? 0 : $new_comment['cid']) : $c['pid'];
|
| 368 |
$c['comment_mover_multiple'] = 1;
|
| 369 |
comment_mover_comment_post($c);
|
| 370 |
}
|
| 371 |
}
|
| 372 |
|
| 373 |
switch ($object['comment_mover']) {
|
| 374 |
case COMMENT_MOVER_COMMENT_TO_COMMENT:
|
| 375 |
// If we moved the comment to another node, add a redirector.
|
| 376 |
$object['comment'] = t('This comment has been moved <a href="%url">here</a>.', array('%url' => url('node/'. $nid, NULL, 'comment-'. $new_comment['cid'], TRUE)));
|
| 377 |
comment_mover_comment_post($object);
|
| 378 |
break;
|
| 379 |
case COMMENT_MOVER_NODE_TO_COMMENT:
|
| 380 |
$object['format'] = 2;
|
| 381 |
$object['body'] = "<?php\ndrupal_goto('node/". $comment['nid'] ."', NULL, 'comment-". $new_comment['cid'] ."')\n?>";
|
| 382 |
// for some reason this is needed.
|
| 383 |
unset($object['0']);
|
| 384 |
$object = (object) $object;
|
| 385 |
node_save($object);
|
| 386 |
}
|
| 387 |
if (module_exists('oglist')) {
|
| 388 |
switch ($object['comment_mover']) {
|
| 389 |
case COMMENT_MOVER_NODE_TO_COMMENT:
|
| 390 |
db_query('UPDATE {og2list_msgid} SET nid = %d, cid = %d WHERE nid = %d AND cid = 0', $new_comment['nid'], $new_comment['cid'], $object['nid']);
|
| 391 |
break;
|
| 392 |
case COMMENT_MOVER_COMMENT_TO_NODE:
|
| 393 |
db_query('UPDATE {og2list_msgid} SET nid = %d, cid = 0 WHERE nid = %d AND cid = %d', $nid, $object['new_nid'], $object['cid']);
|
| 394 |
break;
|
| 395 |
case COMMENT_MOVER_COMMENT_TO_COMMENT:
|
| 396 |
db_query('UPDATE {og2list_msgid} SET nid = %d, cid = %d WHERE nid = %d AND cid = %d', $new_comment['nid'], $new_comment['cid'], $object['nid'], $object['cid']);
|
| 397 |
break;
|
| 398 |
case COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD:
|
| 399 |
// Nothing to do
|
| 400 |
break;
|
| 401 |
}
|
| 402 |
}
|
| 403 |
|
| 404 |
return $new_nid ? $new_nid : $new_comment['cid'];
|
| 405 |
}
|
| 406 |
|
| 407 |
/**
|
| 408 |
* Buids a thread for comments
|
| 409 |
*
|
| 410 |
* @TODO change for 4.7
|
| 411 |
*/
|
| 412 |
function comment_mover_build_thread($edit) {
|
| 413 |
// Here we are building the thread field. See the comment
|
| 414 |
// in comment_render().
|
| 415 |
if ($edit['pid'] == 0) {
|
| 416 |
// This is a comment with no parent comment (depth 0): we start
|
| 417 |
// by retrieving the maximum thread level.
|
| 418 |
$max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
|
| 419 |
|
| 420 |
// Strip the "/" from the end of the thread.
|
| 421 |
$max = rtrim($max, '/');
|
| 422 |
|
| 423 |
if(!$max) {
|
| 424 |
$thread = int2vancode(0) . '/';
|
| 425 |
} else {
|
| 426 |
$thread = int2vancode(vancode2int($max)+1) . '/';
|
| 427 |
}
|
| 428 |
}
|
| 429 |
else {
|
| 430 |
// This is comment with a parent comment: we increase
|
| 431 |
// the part of the thread value at the proper depth.
|
| 432 |
|
| 433 |
// Get the parent comment:
|
| 434 |
$parent = db_fetch_object(db_query('SELECT * FROM {comments} WHERE cid = %d', $edit['pid']));
|
| 435 |
|
| 436 |
// Strip the "/" from the end of the parent thread.
|
| 437 |
$parent->thread = (string) rtrim((string) $parent->thread, '/');
|
| 438 |
|
| 439 |
// Get the max value in _this_ thread.
|
| 440 |
$max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid']));
|
| 441 |
|
| 442 |
if ($max == '') {
|
| 443 |
// First child of this parent.
|
| 444 |
$thread = $parent->thread .'.00/';
|
| 445 |
}
|
| 446 |
else {
|
| 447 |
// Strip the "/" at the end of the thread.
|
| 448 |
$max = rtrim($max, '/');
|
| 449 |
|
| 450 |
// We need to get the value at the correct depth.
|
| 451 |
$parts = explode('.', $max);
|
| 452 |
$parent_depth = count(explode('.', $parent->thread));
|
| 453 |
$last = $parts[$parent_depth];
|
| 454 |
|
| 455 |
$thread = $parent->thread .'.'. int2vancode(vancode2int($last) + 1) .'/';
|
| 456 |
}
|
| 457 |
}
|
| 458 |
|
| 459 |
return $thread;
|
| 460 |
}
|
| 461 |
|
| 462 |
/**
|
| 463 |
* Get a all children of a given comment (recursivly)
|
| 464 |
* or all comments if a node
|
| 465 |
*/
|
| 466 |
function comment_mover_get_thread($parent) {
|
| 467 |
if (isset($parent['cid'])) {
|
| 468 |
$query = "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name , c.mail, c.homepage, u.uid, u.name AS registered_name, u.picture, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d AND SUBSTRING(c.thread, 1, LENGTH('%s')) = '%s' AND c.cid != %d AND c.status = 0 ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))";
|
| 469 |
|
| 470 |
$depth = substr_count($parent['thread'], '.');
|
| 471 |
$thread = substr($parent['thread'], 0, strlen($parent['thread']) - 1);
|
| 472 |
$result = db_query($query, $parent['nid'], $thread, $thread, $parent['cid']);
|
| 473 |
}
|
| 474 |
else {
|
| 475 |
$query = "SELECT c.cid as cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name , c.mail, c.homepage, u.uid, u.name AS registered_name, u.picture, u.data, c.score, c.users, c.thread FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))";
|
| 476 |
$result = db_query($query, $parent['nid']);
|
| 477 |
$depth = - 1;
|
| 478 |
}
|
| 479 |
|
| 480 |
$thread = array();
|
| 481 |
while ($comment = db_fetch_array($result)) {
|
| 482 |
$child_depth = substr_count($comment['thread'], '.') - $depth;
|
| 483 |
$thread[$child_depth][] = $comment;
|
| 484 |
}
|
| 485 |
|
| 486 |
return $thread;
|
| 487 |
}
|
| 488 |
|
| 489 |
/**
|
| 490 |
* Setup the session variable to hold the nid or cid to be pruned
|
| 491 |
*
|
| 492 |
* @param $nid
|
| 493 |
* The node id
|
| 494 |
* @param $cid
|
| 495 |
* The comment id, if empty nid is the nid to be pruned
|
| 496 |
*
|
| 497 |
*/
|
| 498 |
function comment_mover_prune($nid, $cid = 0) {
|
| 499 |
if (comment_mover_pruning()) {
|
| 500 |
// Already in pruning a post.
|
| 501 |
drupal_goto();
|
| 502 |
}
|
| 503 |
if (is_numeric($cid) && is_numeric($nid)) {
|
| 504 |
// Pruning a comment.
|
| 505 |
$comment = comment_mover_load_comment($cid);
|
| 506 |
if (comment_mover_allows_pruning('comment', $comment)) {
|
| 507 |
$_SESSION['comment_mover']['cid'] = $cid;
|
| 508 |
$_SESSION['comment_mover']['nid'] = $comment->nid;
|
| 509 |
$_SESSION['comment_mover']['pid'] = $comment->pid;
|
| 510 |
drupal_goto('node/'. $nid);
|
| 511 |
}
|
| 512 |
}
|
| 513 |
else if (is_numeric($nid)) {
|
| 514 |
// Pruning a node.
|
| 515 |
$node = node_load($nid);
|
| 516 |
if (comment_mover_allows_pruning('node', $node)) {
|
| 517 |
$_SESSION['comment_mover']['cid'] = 0;
|
| 518 |
$_SESSION['comment_mover']['nid'] = $nid;
|
| 519 |
$_SESSION['comment_mover']['pid'] = 0;
|
| 520 |
drupal_goto('node/'. $nid);
|
| 521 |
}
|
| 522 |
}
|
| 523 |
else {
|
| 524 |
drupal_set_message(t('Unable to prune the post'));
|
| 525 |
drupal_goto();
|
| 526 |
}
|
| 527 |
}
|
| 528 |
|
| 529 |
function comment_mover_graft($nid, $cid = 0) {
|
| 530 |
return drupal_get_form('confirm_comment_mover_graft', $nid, $cid);
|
| 531 |
}
|
| 532 |
|
| 533 |
|
| 534 |
function confirm_comment_mover_graft($nid, $cid) {
|
| 535 |
$form['nid'] = array('#type' => 'value', '#value' => $nid);
|
| 536 |
$form['cid'] = array('#type' => 'value', '#value' => $cid);
|
| 537 |
return confirm_form($form, t('Are you sure you want to move this post here?'), 'node/'. $nid);
|
| 538 |
}
|
| 539 |
|
| 540 |
|
| 541 |
/*
|
| 542 |
* The grafting part, wrapper for comment_mover_move
|
| 543 |
*
|
| 544 |
* @param $nid
|
| 545 |
* The nid where the comment should go
|
| 546 |
* @param $cid
|
| 547 |
* The cid that shoud become the parent of the pruned comment (in $_SESSION)
|
| 548 |
* If 0, the $nid should be the direct parent
|
| 549 |
*/
|
| 550 |
function confirm_comment_mover_graft_submit($form_id, $form_values) {
|
| 551 |
$nid = $form_values['nid'];
|
| 552 |
$cid = $form_values['cid'];
|
| 553 |
$prune = comment_mover_pruning();
|
| 554 |
|
| 555 |
// Load node to check whether the target node allows grafting.
|
| 556 |
if (is_numeric($nid)) {
|
| 557 |
$target_node = node_load($nid);
|
| 558 |
}
|
| 559 |
|
| 560 |
if (isset($target_node) && comment_mover_allows_grafting('node', $target_node)) {
|
| 561 |
if ($prune->cid && user_access('administer comments') && comment_mover_allows_pruning('comment', $prune)) {
|
| 562 |
// We're moving a comment
|
| 563 |
$comment = db_fetch_array(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data, n.title AS node_title FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid INNER JOIN {node} n ON c.nid = n.nid WHERE c.cid = %d AND c.status = 0', $prune->cid));
|
| 564 |
if ($prune->nid == $nid) {
|
| 565 |
// Moving to the same thread
|
| 566 |
$comment['comment_mover'] = COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD;
|
| 567 |
$new_cid = comment_mover_move($comment, $cid, $nid);
|
| 568 |
if ($new_cid) {
|
| 569 |
comment_mover_unset();
|
| 570 |
drupal_goto('node/'. $nid);
|
| 571 |
}
|
| 572 |
drupal_goto('node/'. $nid, NULL, 'comment-'. $new_cid);
|
| 573 |
}
|
| 574 |
else {
|
| 575 |
// Moving to another node
|
| 576 |
// First step (move to node)
|
| 577 |
$comment['comment_mover'] = COMMENT_MOVER_COMMENT_TO_COMMENT;
|
| 578 |
$new_cid = comment_mover_move($comment, 0, $nid);
|
| 579 |
// Second step (move to position) if indeed a cid was given
|
| 580 |
if ($cid) {
|
| 581 |
$comment = db_fetch_array(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data, n.title AS node_title FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid INNER JOIN {node} n ON c.nid = n.nid WHERE c.cid = %d AND c.status = 0', $new_cid));
|
| 582 |
$comment['comment_mover'] = COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD;
|
| 583 |
$new_cid = comment_mover_move($comment, $cid, $nid);
|
| 584 |
}
|
| 585 |
comment_mover_unset();
|
| 586 |
drupal_goto('node/'. $nid, NULL, 'comment-'. $new_cid);
|
| 587 |
}
|
| 588 |
}
|
| 589 |
else if ($prune->nid && user_access('administer comments')) {
|
| 590 |
// We're moving a node here
|
| 591 |
// First step - move to node as comment
|
| 592 |
$old_node = node_load($prune->nid);
|
| 593 |
if (node_access('update', $old_node) && comment_mover_allows_pruning('node', $old_node)) {
|
| 594 |
$old_node->comment_mover = COMMENT_MOVER_NODE_TO_COMMENT;
|
| 595 |
$new_cid = comment_mover_move((array) $old_node, 0, $nid);
|
| 596 |
// Second step - move to position - if indeed a cid was given
|
| 597 |
if ($cid) {
|
| 598 |
$comment = db_fetch_array(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data, n.title AS node_title FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid INNER JOIN {node} n ON c.nid = n.nid WHERE c.cid = %d AND c.status = 0', $new_cid));
|
| 599 |
$comment['comment_mover'] = COMMENT_MOVER_COMMENT_TO_COMMENT_SAME_THREAD;
|
| 600 |
$new_cid = comment_mover_move($comment, $cid, $nid);
|
| 601 |
}
|
| 602 |
}
|
| 603 |
comment_mover_unset();
|
| 604 |
drupal_goto('node/'. $nid, NULL, 'comment-'. $new_cid);
|
| 605 |
}
|
| 606 |
}
|
| 607 |
|
| 608 |
drupal_set_message(t('Unable to move the post'));
|
| 609 |
drupal_goto();
|
| 610 |
}
|
| 611 |
|
| 612 |
|
| 613 |
function comment_mover_load_comment($cid) {
|
| 614 |
$comment = db_fetch_object(db_query('SELECT c.*, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', $cid));
|
| 615 |
$comment = drupal_unpack($comment);
|
| 616 |
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
|
| 617 |
return $comment;
|
| 618 |
}
|
| 619 |
|
| 620 |
function comment_mover_cancel() {
|
| 621 |
comment_mover_unset();
|
| 622 |
drupal_goto();
|
| 623 |
}
|
| 624 |
|
| 625 |
function comment_mover_unset() {
|
| 626 |
unset($_SESSION['comment_mover']['cid']);
|
| 627 |
unset($_SESSION['comment_mover']['nid']);
|
| 628 |
unset($_SESSION['comment_mover']['pid']);
|
| 629 |
unset($_SESSION['comment_mover']);
|
| 630 |
}
|
| 631 |
|
| 632 |
/**
|
| 633 |
* Returns false when not in 'pruning' mode or an object with cid, pid and nid when pruning
|
| 634 |
*
|
| 635 |
* obj->nid the nid
|
| 636 |
* obj->cid the comment being moved, if 0, obj->nid is moved
|
| 637 |
* obj->pid the comment 'level, used in hook_link
|
| 638 |
*/
|
| 639 |
function comment_mover_pruning() {
|
| 640 |
if (isset($_SESSION['comment_mover'])) {
|
| 641 |
$obj = '';
|
| 642 |
$obj->cid = isset($_SESSION['comment_mover']['cid']) ? $_SESSION['comment_mover']['cid'] : FALSE;
|
| 643 |
$obj->nid = isset($_SESSION['comment_mover']['nid']) ? $_SESSION['comment_mover']['nid'] : FALSE;
|
| 644 |
$obj->pid = isset($_SESSION['comment_mover']['pid']) ? $_SESSION['comment_mover']['pid'] : FALSE;
|
| 645 |
return $obj;
|
| 646 |
}
|
| 647 |
return FALSE;
|
| 648 |
}
|
| 649 |
|
| 650 |
/**
|
| 651 |
* Implementation of hook_block; the clipboard
|
| 652 |
*
|
| 653 |
*/
|
| 654 |
function comment_mover_block($op = 'list', $delta = 0, $edit = array()) {
|
| 655 |
$block = array();
|
| 656 |
switch ($op) {
|
| 657 |
|
| 658 |
case 'list':
|
| 659 |
$blocks = array();
|
| 660 |
$block[0]= array('info' => t('Comment mover clipboard'));
|
| 661 |
break;
|
| 662 |
|
| 663 |
case 'view':
|
| 664 |
if ($delta == 0) {
|
| 665 |
$block['subject'] = t('Graft');
|
| 666 |
$block['content'] = '';
|
| 667 |
$prune = comment_mover_pruning();
|
| 668 |
if ($prune) {
|
| 669 |
if ($prune->cid) {
|
| 670 |
$comment = comment_mover_load_comment($prune->cid);
|
| 671 |
$block['content'] = theme('comment_mover_block', 'comment', $comment);
|
| 672 |
}
|
| 673 |
else {
|
| 674 |
$node = node_load($prune->nid);
|
| 675 |
$block['content'] = theme('comment_mover_block', 'node', $node);
|
| 676 |
}
|
| 677 |
}
|
| 678 |
}
|
| 679 |
break;
|
| 680 |
}
|
| 681 |
return $block;
|
| 682 |
}
|
| 683 |
|
| 684 |
/**
|
| 685 |
* Theme comment mover block
|
| 686 |
*
|
| 687 |
* @param $op
|
| 688 |
* indicates the type of $object. Possible values, comment, node.
|
| 689 |
* @param $object
|
| 690 |
* the node or comment object
|
| 691 |
*
|
| 692 |
* @return the content of the block
|
| 693 |
*/
|
| 694 |
function theme_comment_mover_block($op, $object) {
|
| 695 |
$content = '';
|
| 696 |
if ($op == 'comment') {
|
| 697 |
$content = '<h3>'. check_plain($object->subject) .'</h3>';
|
| 698 |
$content .= t('By !author @date', array('!author' => theme('username', $object), '@date' => format_date($object->timestamp, 'small')));
|
| 699 |
$items[] = l(t('cancel'), 'comment/cancel', NULL, drupal_get_destination());
|
| 700 |
$content .= drupal_get_form('comment_mover_promote_form');
|
| 701 |
$content .= theme('item_list', $items);
|
| 702 |
}
|
| 703 |
else {
|
| 704 |
$content = '<h3>'. check_plain($object->title) .'</h3>';
|
| 705 |
$content .= t('By !author @date', array('!author' => theme('username', $object), '@date' => format_date($object->created, 'small')));
|
| 706 |
$items[] = l(t('cancel'), 'comment/cancel', NULL, drupal_get_destination());
|
| 707 |
$content .= theme('item_list', $items);
|
| 708 |
}
|
| 709 |
return $content;
|
| 710 |
}
|
| 711 |
|
| 712 |
/**
|
| 713 |
* Checks the settings whether the particular node type allows pruning of the node / or comments of the node
|
| 714 |
*
|
| 715 |
* @param $op
|
| 716 |
* determines the type of $object [node, comment]
|
| 717 |
* @param $object
|
| 718 |
* the node / nid or comment object
|
| 719 |
*/
|
| 720 |
function comment_mover_allows_pruning($op, $object) {
|
| 721 |
if ($op == 'node') {
|
| 722 |
return variable_get("commentmover_node_{$object->type}", FALSE);
|
| 723 |
}
|
| 724 |
else if ($op == 'comment') {
|
| 725 |
$node = node_load($object->nid);
|
| 726 |
return (variable_get("commentmover_prune_{$node->type}", FALSE) && $node->comment == 2);
|
| 727 |
}
|
| 728 |
}
|
| 729 |
|
| 730 |
/**
|
| 731 |
* Checks the settings whether the node / comment allows grafting (depends on the type of the node/parent node)
|
| 732 |
*
|
| 733 |
* @param $op
|
| 734 |
* determines the type of $object [node, comment]
|
| 735 |
* @param $object
|
| 736 |
* the node or comment object
|
| 737 |
*/
|
| 738 |
function comment_mover_allows_grafting($op, $object) {
|
| 739 |
if ($op == 'node') {
|
| 740 |
return variable_get("commentmover_graft_{$object->type}", FALSE);
|
| 741 |
}
|
| 742 |
else if ($op == 'comment') {
|
| 743 |
$node = node_load($object->nid);
|
| 744 |
return (variable_get("commentmover_graft_{$node->type}", FALSE) && $node->comment == 2);
|
| 745 |
}
|
| 746 |
}
|
| 747 |
|
| 748 |
|
| 749 |
//TODO: Rework hook_settings to the new Drupal 5 settings and 'admin/settings' hook_menu entry.
|
| 750 |
/**
|
| 751 |
* Implements hook settings
|
| 752 |
*
|
| 753 |
* - What node types can be pruned
|
| 754 |
* - What node types allow pruning (note: this refers to comments on the node)
|
| 755 |
* - What node types allow grafting
|
| 756 |
*/
|
| 757 |
function comment_mover_settings() {
|
| 758 |
|
| 759 |
$form = array();
|
| 760 |
|
| 761 |
// Create the fieldsets holding the checkboxes
|
| 762 |
$form['allow_node_pruning'] = array(
|
| 763 |
'#type' => 'fieldset',
|
| 764 |
'#title' => t('Enable pruning of the following node types'),
|
| 765 |
'#weight' => -8,
|
| 766 |
'#collapsible' => TRUE,
|
| 767 |
'#collapsed' => TRUE,
|
| 768 |
'#description' => t("Define the node types that can be pruned. Note that pruning doesn't make sense for certain node types (poll, for example)."),
|
| 769 |
);
|
| 770 |
|
| 771 |
$form['allow_pruning'] = array(
|
| 772 |
'#type' => 'fieldset',
|
| 773 |
'#title' => t('Enable pruning of comments on the following node types'),
|
| 774 |
'#weight' => -5,
|
| 775 |
'#collapsible' => TRUE,
|
| 776 |
'#collapsed' => TRUE,
|
| 777 |
'#description' => t('Allow comments on these node types to be pruned and moved to other nodes or be promoted to a node.'),
|
| 778 |
);
|
| 779 |
|
| 780 |
$form['allow_grafting'] = array(
|
| 781 |
'#type' => 'fieldset',
|
| 782 |
'#title' => t('Enable grafting on the following node types'),
|
| 783 |
'#weight' => -2,
|
| 784 |
'#collapsible' => TRUE,
|
| 785 |
'#collapsed' => TRUE,
|
| 786 |
'#description' => t('These node types allow grafting of pruned nodes and comments.'),
|
| 787 |
);
|
| 788 |
|
| 789 |
$form['allow_promotion'] = array(
|
| 790 |
'#type' => 'fieldset',
|
| 791 |
'#title' => t('Enable promotion to the following node types'),
|
| 792 |
'#weight' => -2,
|
| 793 |
'#collapsible' => TRUE,
|
| 794 |
'#collapsed' => TRUE,
|
| 795 |
'#description' => t("Comments can be promoted to these nodetypes. Note that this doesn't make sense for certain node types (poll, for example)."),
|
| 796 |
);
|
| 797 |
|
| 798 |
// Generate the node type specific checkboxes per fieldset
|
| 799 |
foreach (node_get_types('types') as $node_type) {
|
| 800 |
$name = $node_type->name;
|
| 801 |
$type = $node_type->type;
|
| 802 |
$form['allow_node_pruning']["commentmover_node_$type"] = array(
|
| 803 |
'#type' => 'checkbox',
|
| 804 |
'#title' => check_plain($name),
|
| 805 |
'#default_value' => variable_get("commentmover_node_$type", FALSE),
|
| 806 |
);
|
| 807 |
$form['allow_pruning']["commentmover_prune_$type"] = array(
|
| 808 |
'#type' => 'checkbox',
|
| 809 |
'#title' => check_plain($name),
|
| 810 |
'#default_value' => variable_get("commentmover_prune_$type", FALSE),
|
| 811 |
);
|
| 812 |
$form['allow_grafting']["commentmover_graft_$type"] = array(
|
| 813 |
'#type' => 'checkbox',
|
| 814 |
'#title' => check_plain($name),
|
| 815 |
'#default_value' => variable_get("commentmover_graft_$type", FALSE),
|
| 816 |
);
|
| 817 |
$form['allow_promotion']["commentmover_promotion_$type"] = array(
|
| 818 |
'#type' => 'checkbox',
|
| 819 |
'#title' => check_plain($name),
|
| 820 |
'#default_value' => variable_get("commentmover_promotion_$type", FALSE),
|
| 821 |
);
|
| 822 |
}
|
| 823 |
|
| 824 |
return system_settings_form($form);
|
| 825 |
}
|
| 826 |
|
| 827 |
/**
|
| 828 |
* Respond to node type changes by updating associated settings.
|
| 829 |
*/
|
| 830 |
function comment_mover_node_type($op, $info) {
|
| 831 |
switch ($op){
|
| 832 |
case 'delete':
|
| 833 |
variable_del('commentmover_promotion_'. $info->type);
|
| 834 |
variable_del('commentmover_graft_'. $info->type);
|
| 835 |
variable_del('commentmover_prune_'. $info->type);
|
| 836 |
variable_del('commentmover_node_'. $info->type);
|
| 837 |
break;
|
| 838 |
case 'update':
|
| 839 |
if (!empty($info->old_type) && $info->old_type != $info->type) {
|
| 840 |
variable_set('commentmover_promotion_'. $info->type, variable_get('commentmover_promotion_'. $info->old_type, FALSE));
|
| 841 |
variable_del('commentmover_promotion_'. $info->old_type);
|
| 842 |
|
| 843 |
variable_set('commentmover_graft_'. $info->type, variable_get('commentmover_graft_'. $info->old_type, FALSE));
|
| 844 |
variable_del('commentmover_graft_'. $info->old_type);
|
| 845 |
|
| 846 |
variable_set('commentmover_prune_'. $info->type, variable_get('commentmover_prune_'. $info->old_type, FALSE));
|
| 847 |
variable_del('commentmover_prune_'. $info->old_type);
|
| 848 |
|
| 849 |
variable_set('commentmover_node_'. $info->type, variable_get('commentmover_node_'. $info->old_type, FALSE));
|
| 850 |
variable_del('commentmover_node_'. $info->old_type);
|
| 851 |
|
| 852 |
}
|
| 853 |
break;
|
| 854 |
}
|
| 855 |
}
|