comment.module 66.2 KB
Newer Older
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
Dries committed
4
5
/**
 * @file
Dries's avatar
   
Dries committed
6
 * Enables users to comment on published content.
Dries's avatar
Dries committed
7
8
9
10
11
12
 *
 * When enabled, the Drupal comment module creates a discussion
 * board for each Drupal node. Users can post comments to discuss
 * a forum topic, weblog post, story, collaborative book page, etc.
 */

13
/*
Dries's avatar
Dries committed
14
 * Constants to define a comment's published state
15
 */
Dries's avatar
Dries committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
define('COMMENT_PUBLISHED', 0);
define('COMMENT_NOT_PUBLISHED', 1);

/**
 * Constants to define the viewing modes for comment listings
 */
define('COMMENT_MODE_FLAT_COLLAPSED', 0);
define('COMMENT_MODE_FLAT_EXPANDED', 1);
define('COMMENT_MODE_THREADED_COLLAPSED', 2);
define('COMMENT_MODE_THREADED_EXPANDED', 3);

/**
 * Constants to define the viewing orders for comment listings
 */
define('COMMENT_ORDER_NEWEST_FIRST', 0);
define('COMMENT_ORDER_OLDEST_FIRST', 1);

/**
 * Constants to define the position of the comment controls
 */
define('COMMENT_CONTROLS_ABOVE', 0);
define('COMMENT_CONTROLS_BELOW', 1);
define('COMMENT_CONTROLS_ABOVE_BELOW', 2);
define('COMMENT_CONTROLS_HIDDEN', 3);

/**
 * Constants to define the anonymous poster contact handling
 */
define('COMMENT_ANONYMOUS_MAYNOT_CONTACT', 0);
define('COMMENT_ANONYMOUS_MAY_CONTACT', 1);
define('COMMENT_ANONYMOUS_MUST_CONTACT', 2);

/**
 * Constants to define the comment form location
 */
define('COMMENT_FORM_SEPARATE_PAGE', 0);
define('COMMENT_FORM_BELOW', 1);

/**
 * Constants to define a node's comment state
 */
define('COMMENT_NODE_DISABLED', 0);
define('COMMENT_NODE_READ_ONLY', 1);
define('COMMENT_NODE_READ_WRITE', 2);
60

61
62
63
64
65
66
/**
 * Constants to define if comment preview is optional or required
 */
define('COMMENT_PREVIEW_OPTIONAL', 0);
define('COMMENT_PREVIEW_REQUIRED', 1);

67
68
69
/**
 * Implementation of hook_help().
 */
70
function comment_help($section) {
Dries's avatar
   
Dries committed
71
  switch ($section) {
Dries's avatar
   
Dries committed
72
    case 'admin/help#comment':
73
      $output = '<p>'. t('The comment module creates a discussion board for each post. Users can post comments to discuss a forum topic, weblog post, story, collaborative book page, etc. The ability to comment is an important part of involving members in a communtiy dialogue.') .'</p>';
74
      $output .= '<p>'. t('An administrator can give comment permissions to user groups, and users can (optionally) edit their last comment, assuming no others have been posted since.  Attached to each comment board is a control panel for customizing the way that comments are displayed. Users can control the chronological ordering of posts (newest or oldest first) and the number of posts to display on each page.  Comments behave like other user submissions. Filters, smileys and HTML that work in nodes will also work with comments. The comment module provides specific features to inform site members when new comments have been posted.') .'</p>';
75
76
77
78
79
80
81
82
83
84
      $output .= t('<p>You can</p>
<ul>
<li>control access for various comment module functions through access permissions <a href="%admin-access">administer &gt;&gt; access control</a>.</li>
<li>administer comments <a href="%admin-comment-configure"> administer &gt;&gt; comments &gt;&gt; configure</a>.</li>
</ul>
', array('%admin-access' => url('admin/access'), '%admin-comment-configure' => url('admin/comment/configure')));
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="%comment">Comment page</a>.', array('%comment' => 'http://www.drupal.org/handbook/modules/comment/')) .'</p>';
      return $output;
    case 'admin/modules#description':
      return t('Allows users to comment on and discuss published content.');
Dries's avatar
   
Dries committed
85
    case 'admin/comment':
86
    case 'admin/comment/new':
87
      return t("<p>Below is a list of the latest comments posted to your site. Click on a subject to see the comment, the author's name to edit the author's user information , \"edit\" to modify the text, and \"delete\" to remove their submission.</p>");
Dries's avatar
   
Dries committed
88
    case 'admin/comment/approval':
89
      return t("<p>Below is a list of the comments posted to your site that need approval. To approve a comment, click on \"edit\" and then change its \"moderation status\" to Approved. Click on a subject to see the comment, the author's name to edit the author's user information, \"edit\" to modify the text, and \"delete\" to remove their submission.</p>");
Dries's avatar
Dries committed
90
91
    case 'admin/comment/configure':
    case 'admin/comment/configure/settings':
92
      return t("<p>Comments can be attached to any node, and their settings are below. The display comes in two types: a \"flat list\" where everything is flush to the left side, and comments come in chronological order, and a \"threaded list\" where replies to other comments are placed immediately below and slightly indented, forming an outline. They also come in two styles: \"expanded\", where you see both the title and the contents, and \"collapsed\" where you only see the title. Preview comment forces a user to look at their comment by clicking on a \"Preview\" button before they can actually add the comment.</p>");
93
   }
Dries's avatar
   
Dries committed
94
95
}

Dries's avatar
   
Dries committed
96
97
98
/**
 * Implementation of hook_menu().
 */
Dries's avatar
   
Dries committed
99
function comment_menu($may_cache) {
Dries's avatar
   
Dries committed
100
101
  $items = array();

Dries's avatar
   
Dries committed
102
103
104
105
106
107
108
109
110
111
112
113
  if ($may_cache) {
    $access = user_access('administer comments');
    $items[] = array('path' => 'admin/comment', 'title' => t('comments'),
      'callback' => 'comment_admin_overview', 'access' => $access);

    // Tabs:
    $items[] = array('path' => 'admin/comment/list', 'title' => t('list'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/comment/configure', 'title' => t('configure'),
      'callback' => 'comment_configure', 'access' => $access, 'type' => MENU_LOCAL_TASK);

    // Subtabs:
114
    $items[] = array('path' => 'admin/comment/list/new', 'title' => t('published comments'),
Dries's avatar
   
Dries committed
115
116
117
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/comment/list/approval', 'title' => t('approval queue'),
      'callback' => 'comment_admin_overview', 'access' => $access,
118
      'callback arguments' => array('approval'),
Dries's avatar
   
Dries committed
119
120
121
122
123
124
      'type' => MENU_LOCAL_TASK);

    $items[] = array('path' => 'admin/comment/configure/settings', 'title' => t('settings'),
      'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);

    $access = user_access('post comments');
125
    $items[] = array('path' => 'comment/edit', 'title' => t('edit comment'),
Dries's avatar
   
Dries committed
126
      'callback' => 'comment_edit', 'access' => $access, 'type' => MENU_CALLBACK);
127
128
    $items[] = array('path' => 'comment/delete', 'title' => t('delete comment'),
      'callback' => 'comment_delete', 'access' => $access, 'type' => MENU_CALLBACK);
Dries's avatar
   
Dries committed
129
  }
Dries's avatar
   
Dries committed
130
131
  else {
    if (arg(0) == 'comment' && arg(1) == 'reply' && is_numeric(arg(2))) {
132
      $node = node_load(arg(2));
Dries's avatar
   
Dries committed
133
134
135
136
137
138
139
140
141
142
      if ($node->nid) {
        $items[] = array('path' => 'comment/reply', 'title' => t('reply to comment'),
          'callback' => 'comment_reply', 'access' => node_access('view', $node), 'type' => MENU_CALLBACK);
      }
    }
    if ((arg(0) == 'node') && is_numeric(arg(1)) && is_numeric(arg(2))) {
      $items[] = array('path' => ('node/'. arg(1) .'/'. arg(2)), 'title' => t('view'),
        'callback' => 'node_page',
        'type' => MENU_CALLBACK);
    }
Dries's avatar
   
Dries committed
143
  }
Dries's avatar
   
Dries committed
144
145
146
147
148
149
150
151

  return $items;
}

/**
 * Implementation of hook_perm().
 */
function comment_perm() {
152
  return array('access comments', 'post comments', 'administer comments', 'post comments without approval');
Dries's avatar
   
Dries committed
153
154
155
156
157
158
159
160
161
162
163
164
}

/**
 * Implementation of hook_block().
 *
 * Generates a block with the most recent comments.
 */
function comment_block($op = 'list', $delta = 0) {
  if ($op == 'list') {
    $blocks[0]['info'] = t('Recent comments');
    return $blocks;
  }
165
  else if ($op == 'view' && user_access('access comments')) {
Dries's avatar
   
Dries committed
166
    $block['subject'] = t('Recent comments');
167
    $block['content'] = theme('comment_block');
Dries's avatar
   
Dries committed
168
169
170
171
    return $block;
  }
}

172
173
174
175
176
177
178
179
180
function theme_comment_block() {
  $result = db_query_range(db_rewrite_sql('SELECT c.nid, c.* FROM {comments} c INNER JOIN {node} n ON n.nid = c.nid WHERE n.status = 1 AND c.status = %d ORDER BY c.timestamp DESC', 'c'), COMMENT_PUBLISHED, 0, 10);
  $items = array();
  while ($comment = db_fetch_object($result)) {
    $items[] = l($comment->subject, 'node/'. $comment->nid, NULL, NULL, 'comment-'. $comment->cid) .'<br />'. t('%time ago', array('%time' => format_interval(time() - $comment->timestamp)));
  }
  return theme('item_list', $items);
}

Dries's avatar
   
Dries committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
 * Implementation of hook_link().
 */
function comment_link($type, $node = 0, $main = 0) {
  $links = array();

  if ($type == 'node' && $node->comment) {

    if ($main) {
      // Main page: display the number of comments that have been posted.

      if (user_access('access comments')) {
        $all = comment_num_all($node->nid);
        $new = comment_num_new($node->nid);

        if ($all) {
          $links[] = l(format_plural($all, '1 comment', '%count comments'), "node/$node->nid", array('title' => t('Jump to the first comment of this posting.')), NULL, 'comment');

          if ($new) {
            $links[] = l(format_plural($new, '1 new comment', '%count new comments'), "node/$node->nid", array('title' => t('Jump to the first new comment of this posting.')), NULL, 'new');
          }
        }
        else {
Dries's avatar
Dries committed
204
          if ($node->comment == COMMENT_NODE_READ_WRITE) {
Dries's avatar
   
Dries committed
205
206
207
208
            if (user_access('post comments')) {
              $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Add a new comment to this page.')));
            }
            else {
209
              $links[] = theme('comment_post_forbidden', $node->nid);
Dries's avatar
   
Dries committed
210
211
212
213
214
215
216
217
218
            }
          }
        }
      }
    }
    else {
      // Node page: add a "post comment" link if the user is allowed to
      // post comments, if this node is not read-only, and if the comment form isn't already shown

219
      if ($node->comment == COMMENT_NODE_READ_WRITE) {
Dries's avatar
   
Dries committed
220
        if (user_access('post comments')) {
221
222
223
          if (variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_SEPARATE_PAGE) {
            $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Share your thoughts and opinions related to this posting.')), NULL, 'comment');
          }
Dries's avatar
   
Dries committed
224
225
        }
        else {
226
          $links[] = theme('comment_post_forbidden', $node->nid);
Dries's avatar
   
Dries committed
227
228
229
230
231
232
233
234
235
236
237
238
        }
      }
    }
  }

  if ($type == 'comment') {
    $links = comment_links($node, $main);
  }

  return $links;
}

239
function comment_form_alter($form_id, &$form) {
240
241
242
243
  if (isset($form['type'])) {
    if ($form['type']['#value'] .'_node_settings' == $form_id) {
      $form['workflow']['comment_'. $form['type']['#value']] = array('#type' => 'radios', '#title' => t('Default comment setting'), '#default_value' => variable_get('comment_'. $form['type']['#value'], COMMENT_NODE_READ_WRITE), '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')), '#description' => t('Users with the <em>administer comments</em> permission will be able to override this setting.'));
    }
244
    if ($form['type']['#value'] .'_node_form' == $form_id) {
245
      $node = $form['#node'];
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
      if (user_access('administer comments')) {
        $form['user_comments'] = array(
          '#type' => 'fieldset',
          '#title' => t('User comments'),
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
          '#weight' => 30,
        );
        $form['user_comments']['comment'] = array(
          '#type' => 'radios',
          '#parents' => array('comment'),
          '#default_value' => $node->comment,
          '#options' => array(t('Disabled'), t('Read only'), t('Read/Write')),
        );
      }
      else {
        $form['user_comments']['comment'] = array(
          '#type' => 'value',
          '#value' => $node->comment,
        );
      }
267
    }
268
269
270
  }
}

Dries's avatar
   
Dries committed
271
272
/**
 * Implementation of hook_nodeapi().
Dries's avatar
   
Dries committed
273
 *
Dries's avatar
   
Dries committed
274
275
276
277
278
 */
function comment_nodeapi(&$node, $op, $arg = 0) {
  switch ($op) {
    case 'fields':
      return array('comment');
279

Dries's avatar
   
Dries committed
280
    case 'load':
281
      return db_fetch_array(db_query("SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = %d", $node->nid));
282
283
284
285
      break;

    case 'prepare':
      if (!isset($node->comment)) {
Dries's avatar
Dries committed
286
        $node->comment = variable_get("comment_$node->type", COMMENT_NODE_READ_WRITE);
Dries's avatar
   
Dries committed
287
288
      }
      break;
289

Dries's avatar
   
Dries committed
290
    case 'insert':
291
      db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->created, $node->uid);
Dries's avatar
   
Dries committed
292
      break;
293

Dries's avatar
   
Dries committed
294
    case 'delete':
Dries's avatar
   
Dries committed
295
296
      db_query('DELETE FROM {comments} WHERE nid = %d', $node->nid);
      db_query('DELETE FROM {node_comment_statistics} WHERE nid = %d', $node->nid);
Dries's avatar
   
Dries committed
297
      break;
298

Dries's avatar
Dries committed
299
300
    case 'update index':
      $text = '';
301
      $comments = db_query('SELECT subject, comment, format FROM {comments} WHERE nid = %d AND status = %d', $node->nid, COMMENT_PUBLISHED);
Dries's avatar
Dries committed
302
      while ($comment = db_fetch_object($comments)) {
303
        $text .= '<h2>'. check_plain($comment->subject) .'</h2>'. check_markup($comment->comment, $comment->format, FALSE);
Dries's avatar
Dries committed
304
305
      }
      return $text;
306

Dries's avatar
Dries committed
307
308
309
    case 'search result':
      $comments = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $node->nid));
      return format_plural($comments, '1 comment', '%count comments');
310

Steven Wittens's avatar
- Typo    
Steven Wittens committed
311
    case 'rss item':
Steven Wittens's avatar
Steven Wittens committed
312
      return array(array('key' => 'comments', 'value' => url('node/'. $node->nid, NULL, 'comment', TRUE)));
Dries's avatar
   
Dries committed
313
314
315
316
317
318
319
320
321
322
323
  }
}

/**
 * Implementation of hook_user().
 *
 * Provides signature customization for the user's comments.
 */
function comment_user($type, $edit, &$user, $category = NULL) {
  if ($type == 'form' && $category == 'account') {
    // when user tries to edit his own data
324
325
326
327
328
329
330
331
332
333
    $form['comment_settings'] = array(
      '#type' => 'fieldset',
      '#title' => t('Comment settings'),
      '#collapsible' => TRUE,
      '#weight' => 4);
    $form['comment_settings']['signature'] = array(
      '#type' => 'textarea',
      '#title' => t('Signature'),
      '#default_value' => $edit['signature'],
      '#description' => t('Your signature will be publicly displayed at the end of your comments.'));
334
335

    return $form;
Dries's avatar
   
Dries committed
336
337
338
  }
}

339
/**
Dries's avatar
   
Dries committed
340
 * Menu callback; presents the comment settings page.
341
 */
Dries's avatar
   
Dries committed
342
function comment_configure() {
343
344
  $form['viewing_options'] = array(
    '#type' => 'fieldset',
345
    '#title' => t('Viewing options'),
346
347
348
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
Dries's avatar
   
Dries committed
349

Dries's avatar
Dries committed
350
351
352
353
354
  $form['viewing_options']['comment_default_mode'] = array(
    '#type' => 'radios',
    '#title' => t('Default display mode'),
    '#default_value' => variable_get('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED),
    '#options' => _comment_get_modes(),
355
    '#description' => t('The default view for comments. Expanded views display the body of the comment. Threaded views keep replies together.'),
Dries's avatar
Dries committed
356
  );
357

Dries's avatar
Dries committed
358
359
360
  $form['viewing_options']['comment_default_order'] = array(
    '#type' => 'radios',
    '#title' => t('Default display order'),
361
    '#default_value' => variable_get('comment_default_order', COMMENT_ORDER_NEWEST_FIRST),
Dries's avatar
Dries committed
362
    '#options' => _comment_get_orders(),
363
    '#description' => t('The default sorting for new users and anonymous users while viewing comments. These users may change their view using the comment control panel. For registered users, this change is remembered as a persistent user preference.'),
Dries's avatar
Dries committed
364
  );
Dries's avatar
   
Dries committed
365

366
  $form['viewing_options']['comment_default_per_page'] = array(
367
368
369
370
    '#type' => 'select',
    '#title' => t('Default comments per page'),
    '#default_value' => variable_get('comment_default_per_page', 50),
    '#options' => _comment_per_page(),
371
    '#description' => t('Default number of comments for each page: more comments are distributed in several pages.'),
372
373
  );

Dries's avatar
Dries committed
374
375
376
377
378
379
380
381
382
  $form['viewing_options']['comment_controls'] = array(
    '#type' => 'radios',
    '#title' => t('Comment controls'),
    '#default_value' => variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN),
    '#options' => array(
      t('Display above the comments'),
      t('Display below the comments'),
      t('Display above and below the comments'),
      t('Do not display')),
383
    '#description' => t('Position of the comment controls box.  The comment controls let the user change the default display mode and display order of comments.'),
Dries's avatar
Dries committed
384
  );
385

386
387
  $form['posting_settings'] = array(
    '#type' => 'fieldset',
388
    '#title' => t('Posting settings'),
389
390
391
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
392

Dries's avatar
Dries committed
393
394
  $form['posting_settings']['comment_anonymous'] = array(
    '#type' => 'radios',
395
    '#title' => t('Anonymous commenting'),
Dries's avatar
Dries committed
396
397
398
399
400
    '#default_value' => variable_get('comment_anonymous', COMMENT_ANONYMOUS_MAYNOT_CONTACT),
    '#options' => array(
      COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'),
      COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
      COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information')),
401
    '#description' => t('This option is enabled when anonymous users have permission to post comments on the <a href="%url">permissions page</a>.', array('%url' => url('admin/access'))),
Dries's avatar
Dries committed
402
  );
403
404
405
  if (!user_access('post comments', user_load(array('uid' => 0)))) {
    $form['posting_settings']['comment_anonymous']['#attributes'] = array('disabled' => 'disabled');
  }
406
407

  $form['posting_settings']['comment_subject_field'] = array(
408
409
410
411
    '#type' => 'radios',
    '#title' => t('Comment subject field'),
    '#default_value' => variable_get('comment_subject_field', 1),
    '#options' => array(t('Disabled'), t('Enabled')),
412
    '#description' => t('Can users provide a unique subject for their comments?'),
413
414
  );

415
416
417
418
419
420
  $form['posting_settings']['comment_preview'] = array(
    '#type' => 'radios',
    '#title' => t('Preview comment'),
    '#default_value' => variable_get('comment_preview', COMMENT_PREVIEW_REQUIRED),
    '#options' => array(t('Optional'), t('Required')),
  );
421

Dries's avatar
Dries committed
422
423
424
425
  $form['posting_settings']['comment_form_location'] = array(
    '#type' => 'radios',
    '#title' => t('Location of comment submission form'),
    '#default_value' => variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE),
426
    '#options' => array(t('Display on separate page'), t('Display below post or comments')),
Dries's avatar
Dries committed
427
  );
428
429

  return system_settings_form('comment_settings_form', $form);
Dries's avatar
   
Dries committed
430
431
}

432
433
434
435
436
437
438
439
440
441
/**
 * This is *not* a hook_access() implementation. This function is called
 * to determine whether the current user has access to a particular comment.
 *
 * Authenticated users can edit their comments as long they have not been
 * replied to. This prevents people from changing or revising their
 * statements based on the replies their posts got. Furthermore, users
 * can't reply to their own comments and are encouraged instead to extend
 * their original comment.
 */
Dries's avatar
   
Dries committed
442
function comment_access($op, $comment) {
Dries's avatar
   
Dries committed
443
444
  global $user;

445
  if ($op == 'edit') {
446
    return ($user->uid && $user->uid == $comment->uid && comment_num_replies($comment->cid) == 0) || user_access('administer comments');
Dries's avatar
   
Dries committed
447
448
  }
}
449

Dries's avatar
   
Dries committed
450
function comment_node_url() {
Dries's avatar
Dries committed
451
  return arg(0) .'/'. arg(1);
Dries's avatar
   
Dries committed
452
}
Dries's avatar
   
Dries committed
453

Dries's avatar
   
Dries committed
454
455
456
function comment_edit($cid) {
  global $user;

457
  $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d', $cid));
Dries's avatar
   
Dries committed
458
  $comment = drupal_unpack($comment);
459
  $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
460
  if (comment_access('edit', $comment)) {
461
    return comment_form((array)$comment);
462
463
464
  }
  else {
    drupal_access_denied();
Dries's avatar
   
Dries committed
465
466
467
  }
}

Dries's avatar
Dries committed
468
function comment_reply($nid, $pid = NULL) {
469
  // set the breadcrumb trail
470
  $node = node_load($nid);
471
  menu_set_location(array(array('path' => "node/$nid", 'title' => $node->title), array('path' => "comment/reply/$nid")));
Dries's avatar
   
Dries committed
472

473
  $op = isset($_POST['op']) ? $_POST['op'] : '';
Dries's avatar
   
Dries committed
474

475
  $output = '';
Dries's avatar
   
Dries committed
476

Dries's avatar
Dries committed
477
478
479
  // or are we merely showing the form?
  if (user_access('access comments')) {

480
481
482
483
484
485
486
    if ($op == t('Preview comment')) {
      if (user_access('post comments')) {
        $output .= comment_form(array('pid' => $pid, 'nid' => $nid), NULL);
      }
      else {
        drupal_set_message(t('You are not authorized to post comments.'), 'error');
      }
Dries's avatar
   
Dries committed
487
488
    }
    else {
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
      // if this is a reply to another comment, show that comment first
      // else, we'll just show the user the node they're commenting on.
      if ($pid) {
        $comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $pid, COMMENT_PUBLISHED));
        $comment = drupal_unpack($comment);
        $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
        $output .= theme('comment_view', $comment);
      }
      else if (user_access('access content')) {
        $output .= node_view($node);
        $pid = 0;
      }

      // should we show the reply box?
      if (node_comment_mode($nid) != COMMENT_NODE_READ_WRITE) {
        drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
      }
      else if (user_access('post comments')) {
        $output .= comment_form(array('pid' => $pid, 'nid' => $nid), t('Reply'));
      }
      else {
        drupal_set_message(t('You are not authorized to post comments.'), 'error');
      }
Dries's avatar
   
Dries committed
512
    }
Kjartan's avatar
Kjartan committed
513
514
  }
  else {
515
    drupal_set_message(t('You are not authorized to view comments.'), 'error');
Dries's avatar
   
Dries committed
516
  }
Dries's avatar
   
Dries committed
517

Dries's avatar
   
Dries committed
518
  return $output;
Dries's avatar
   
Dries committed
519
520
}

521
522
523
524
525
526
527
528
529
530
531
/**
 * Accepts a submission of new or changed comment content.
 *
 * @param $edit
 *   A comment array.
 *
 * @return
 *   If the comment is successfully saved the comment ID is returned.  If the comment
 *   is not saved, FALSE is returned.
 */
function comment_save($edit) {
Dries's avatar
   
Dries committed
532
  global $user;
533
  if (user_access('post comments') && (user_access('administer coments') || node_comment_mode($edit['nid']) == COMMENT_NODE_READ_WRITE)) {
Dries's avatar
   
Dries committed
534
    if (!form_get_errors()) {
535
536
      // Check for duplicate comments.  Note that we have to use the
      // validated/filtered data to perform such check.
537
      $duplicate = db_result(db_query("SELECT COUNT(cid) FROM {comments} WHERE pid = %d AND nid = %d AND subject = '%s' AND comment = '%s'", $edit['pid'], $edit['nid'], $edit['subject'], $edit['comment']), 0);
Dries's avatar
   
Dries committed
538
      if ($duplicate != 0) {
539
        watchdog('content', t('Comment: duplicate %subject.', array('%subject' => theme('placeholder', $edit['subject']))), WATCHDOG_WARNING);
Dries's avatar
   
Dries committed
540
      }
Dries's avatar
   
Dries committed
541

542
      if ($edit['cid']) {
543
        // Update the comment in the database.
544
        db_query("UPDATE {comments} SET status = '%s', timestamp = %d, subject = '%s', comment = '%s', format = '%s', uid = %d, name = '%s', mail = '%s', homepage = '%s' WHERE cid = %d", $edit['status'], $edit['timestamp'], $edit['subject'], $edit['comment'], $edit['format'], $edit['uid'], $edit['name'], $edit['mail'], $edit['homepage'], $edit['cid']);
Dries's avatar
   
Dries committed
545

Dries's avatar
   
Dries committed
546
547
        _comment_update_node_statistics($edit['nid']);

548
        // Allow modules to respond to the updating of a comment.
549
550
        comment_invoke_comment($edit, 'update');

Dries's avatar
   
Dries committed
551

Dries's avatar
Dries committed
552
        // Add an entry to the watchdog log.
553
        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']));
Dries's avatar
   
Dries committed
554
555
      }
      else {
556
        // Add the comment to database.
557
        $status = user_access('post comments without approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED;
558
        $roles = variable_get('comment_roles', array());
Dries's avatar
   
Dries committed
559
560
561
562
563
564
        $score = 0;

        foreach (array_intersect(array_keys($roles), array_keys($user->roles)) as $rid) {
          $score = max($roles[$rid], $score);
        }

Dries's avatar
   
Dries committed
565
566
        $users = serialize(array(0 => $score));

567
568
        // Here we are building the thread field.  See the comment
        // in comment_render().
569
        if ($edit['pid'] == 0) {
570
571
          // This is a comment with no parent comment (depth 0): we start
          // by retrieving the maximum thread level.
572
          $max = db_result(db_query('SELECT MAX(thread) FROM {comments} WHERE nid = %d', $edit['nid']));
Dries's avatar
   
Dries committed
573

574
575
          // Strip the "/" from the end of the thread.
          $max = rtrim($max, '/');
Dries's avatar
   
Dries committed
576

577
578
579
580
581
          // Next, we increase this value by one.  Note that we can't
          // use 1, 2, 3, ... 9, 10, 11 because we order by string and
          // 10 would be right after 1.  We use 1, 2, 3, ..., 9, 91,
          // 92, 93, ... instead.  Ugly but fast.
          $decimals = (string) substr($max, 0, strlen($max) - 1);
Dries's avatar
   
Dries committed
582
583
584
585
586
587
588
589
590
          $units = substr($max, -1, 1);
          if ($units) {
            $units++;
          }
          else {
            $units = 1;
          }

          if ($units == 10) {
591
            $units = '90';
Dries's avatar
   
Dries committed
592
593
          }

594
          // Finally, build the thread field for this new comment.
595
          $thread = $decimals . $units .'/';
Dries's avatar
   
Dries committed
596
597
        }
        else {
598
599
          // This is comment with a parent comment: we increase
          // the part of the thread value at the proper depth.
Dries's avatar
   
Dries committed
600
601

          // Get the parent comment:
602
          $parent = _comment_load($edit['pid']);
Dries's avatar
   
Dries committed
603

604
          // Strip the "/" from the end of the parent thread.
605
          $parent->thread = (string) rtrim((string) $parent->thread, '/');
Dries's avatar
   
Dries committed
606

607
          // Get the max value in _this_ thread.
Dries's avatar
   
Dries committed
608
          $max = db_result(db_query("SELECT MAX(thread) FROM {comments} WHERE thread LIKE '%s.%%' AND nid = %d", $parent->thread, $edit['nid']));
Dries's avatar
   
Dries committed
609

610
611
          if ($max == '') {
            // First child of this parent.
612
            $thread = $parent->thread .'.1/';
Dries's avatar
   
Dries committed
613
614
          }
          else {
615
616
            // Strip the "/" at the end of the thread.
            $max = rtrim($max, '/');
Dries's avatar
   
Dries committed
617

618
619
620
            // We need to get the value at the correct depth.
            $parts = explode('.', $max);
            $parent_depth = count(explode('.', $parent->thread));
Dries's avatar
   
Dries committed
621
622
            $last = $parts[$parent_depth];

623
624
625
626
            // Next, we increase this value by one.  Note that we can't
            // use 1, 2, 3, ... 9, 10, 11 because we order by string and
            // 10 would be right after 1.  We use 1, 2, 3, ..., 9, 91,
            // 92, 93, ... instead.  Ugly but fast.
Dries's avatar
   
Dries committed
627
628
629
630
            $decimals = (string)substr($last, 0, strlen($last) - 1);
            $units = substr($last, -1, 1);
            $units++;
            if ($units == 10) {
631
              $units = '90';
Dries's avatar
   
Dries committed
632
633
            }

634
            // Finally, build the thread field for this new comment.
635
            $thread = $parent->thread .'.'. $decimals . $units .'/';
Dries's avatar
   
Dries committed
636
637
638
          }
        }

639
        $edit['cid'] = db_next_id('{comments}_cid');
Dries's avatar
   
Dries committed
640
641
642
643
644
645
        $edit['timestamp'] = time();

        if ($edit['uid'] = $user->uid) {
          $edit['name'] = $user->name;
        }

646
        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']);
Dries's avatar
   
Dries committed
647
648

        _comment_update_node_statistics($edit['nid']);
Dries's avatar
   
Dries committed
649

650
        // Tell the other modules a new comment has been submitted.
651
        comment_invoke_comment($edit, 'insert');
Dries's avatar
   
Dries committed
652

653
        // Add an entry to the watchdog log.
654
        watchdog('content', t('Comment: added %subject.', array('%subject' => theme('placeholder', $edit['subject']))), WATCHDOG_NOTICE, l(t('view'), 'node/'. $edit['nid'], NULL, NULL, 'comment-'. $edit['cid']));
Dries's avatar
   
Dries committed
655
      }
Dries's avatar
   
Dries committed
656

657
      // Clear the cache so an anonymous user can see his comment being added.
Dries's avatar
   
Dries committed
658
      cache_clear_all();
Dries's avatar
   
Dries committed
659

Dries's avatar
   
Dries committed
660
      // Explain the approval queue if necessary, and then
Dries's avatar
   
Dries committed
661
      // redirect the user to the node he's commenting on.
662
      if ($status == COMMENT_NOT_PUBLISHED) {
Dries's avatar
   
Dries committed
663
        drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.'));
Dries's avatar
   
Dries committed
664
      }
665
      return $edit['cid'];
Dries's avatar
   
Dries committed
666
667
    }
    else {
668
      return FALSE;
Dries's avatar
   
Dries committed
669
670
    }
  }
Dries's avatar
   
Dries committed
671
  else {
672
    $txt = t('Comment: unauthorized comment submitted or comment submitted to a closed node %subject.', array('%subject' => theme('placeholder', $edit['subject'])));
673
674
675
    watchdog('content', $txt, WATCHDOG_WARNING);
    drupal_set_message($txt, 'error');
    return FALSE;
Dries's avatar
   
Dries committed
676
677
678
679
  }
}

function comment_links($comment, $return = 1) {
Dries's avatar
   
Dries committed
680
  global $user;
Dries's avatar
   
Dries committed
681

Dries's avatar
   
Dries committed
682
  $links = array();
Dries's avatar
   
Dries committed
683

684
  // If we are viewing just this comment, we link back to the node.
Dries's avatar
   
Dries committed
685
  if ($return) {
686
    $links[] = l(t('parent'), comment_node_url(), NULL, NULL, "comment-$comment->cid");
Dries's avatar
   
Dries committed
687
  }
Dries's avatar
   
Dries committed
688

689
  if (node_comment_mode($comment->nid) == COMMENT_NODE_READ_WRITE) {
690
    if (user_access('administer comments') && user_access('post comments')) {
691
692
      $links[] = l(t('delete'), "comment/delete/$comment->cid");
      $links[] = l(t('edit'), "comment/edit/$comment->cid");
Dries's avatar
   
Dries committed
693
      $links[] = l(t('reply'), "comment/reply/$comment->nid/$comment->cid");
694
    }
695
696
    else if (user_access('post comments')) {
      if (comment_access('edit', $comment)) {
Dries's avatar
   
Dries committed
697
        $links[] = l(t('edit'), "comment/edit/$comment->cid");
Dries's avatar
   
Dries committed
698
      }
Dries's avatar
   
Dries committed
699
      $links[] = l(t('reply'), "comment/reply/$comment->nid/$comment->cid");
Dries's avatar
   
Dries committed
700
701
    }
    else {
702
      $links[] = theme('comment_post_forbidden', $comment->nid);
Dries's avatar
   
Dries committed
703
    }
Dries's avatar
   
Dries committed
704
  }
Dries's avatar
   
Dries committed
705

Dries's avatar
   
Dries committed
706
  return $links;
Dries's avatar
   
Dries committed
707
708
}

Dries's avatar
   
Dries committed
709
function comment_render($node, $cid = 0) {
Dries's avatar
   
Dries committed
710
711
  global $user;

712
713
714
715
  $mode = $_GET['mode'];
  $order = $_GET['order'];
  $comments_per_page = $_GET['comments_per_page'];
  $comment_page = $_GET['comment_page'];
Dries's avatar
   
Dries committed
716

717
  $output = '';
Dries's avatar
   
Dries committed
718

719
720
  if (user_access('access comments')) {
    // Pre-process variables.
Dries's avatar
   
Dries committed
721
    $nid = $node->nid;
Dries's avatar
   
Dries committed
722
723
    if (empty($nid)) {
      $nid = 0;
Dries's avatar
   
Dries committed
724
725
726
    }

    if (empty($mode)) {
Dries's avatar
Dries committed
727
      $mode = $user->mode ? $user->mode : ($_SESSION['comment_mode'] ? $_SESSION['comment_mode'] : variable_get('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED));
Dries's avatar
   
Dries committed
728
729
730
    }

    if (empty($order)) {
Dries's avatar
Dries committed
731
      $order = $user->sort ? $user->sort : ($_SESSION['comment_sort'] ? $_SESSION['comment_sort'] : variable_get('comment_default_order', COMMENT_ORDER_NEWEST_FIRST));
Dries's avatar
   
Dries committed
732
733
    }

Dries's avatar
   
Dries committed
734
    if (empty($comments_per_page)) {
735
      $comments_per_page = $user->comments_per_page ? $user->comments_per_page : ($_SESSION['comment_comments_per_page'] ? $_SESSION['comment_comments_per_page'] : variable_get('comment_default_per_page', '50'));
Dries's avatar
   
Dries committed
736
    }
Dries's avatar
   
Dries committed
737

Dries's avatar
   
Dries committed
738
    $output .= "<a id=\"comment\"></a>\n";
Dries's avatar
   
Dries committed
739

Kjartan's avatar
Kjartan committed
740
    if ($cid) {
741
      // Single comment view.
742
      $result = db_query('SELECT c.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 FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, u.picture, c.homepage, u.uid, u.name, u.picture, u.data, c.score, c.users', $cid, COMMENT_PUBLISHED);
Dries's avatar
   
Dries committed
743

Dries's avatar
   
Dries committed
744
      if ($comment = db_fetch_object($result)) {
745
        $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
746
        $output .= theme('comment_view', $comment, module_invoke_all('link', 'comment', $comment, 1));
Dries's avatar
   
Dries committed
747
      }
Dries's avatar
   
Dries committed
748
    }
Dries's avatar
   
Dries committed
749
    else {
750
      // Multiple comment view
751
      $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 c.status = %d";
Dries's avatar
   
Dries committed
752

753
      $query .= ' GROUP BY c.cid, c.pid, c.nid, c.subject, c.comment, c.format, c.timestamp, c.name, c.mail, u.picture, c.homepage, u.uid, u.name, u.picture, u.data, c.score, c.users, c.thread';
Dries's avatar
   
Dries committed
754

Dries's avatar
   
Dries committed
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
      /*
      ** We want to use the standard pager, but threads would need every
      ** comment to build the thread structure, so we need to store some
      ** extra info.
      **
      ** We use a "thread" field to store this extra info. The basic idea
      ** is to store a value and to order by that value. The "thread" field
      ** keeps this data in a way which is easy to update and convenient
      ** to use.
      **
      ** A "thread" value starts at "1". If we add a child (A) to this
      ** comment, we assign it a "thread" = "1.1". A child of (A) will have
      ** "1.1.1". Next brother of (A) will get "1.2". Next brother of the
      ** parent of (A) will get "2" and so on.
      **
      ** First of all note that the thread field stores the depth of the
      ** comment: depth 0 will be "X", depth 1 "X.X", depth 2 "X.X.X", etc.
      **
      ** Now to get the ordering right, consider this example:
      **
      ** 1
      ** 1.1
      ** 1.1.1
      ** 1.2
      ** 2
      **
      ** If we "ORDER BY thread ASC" we get the above result, and this is
      ** the natural order sorted by time.  However, if we "ORDER BY thread
      ** DESC" we get:
      **
      ** 2
      ** 1.2
      ** 1.1.1
      ** 1.1
      ** 1
      **
      ** Clearly, this is not a natural way to see a thread, and users
      ** will get confused. The natural order to show a thread by time
      ** desc would be:
      **
      ** 2
      ** 1
      ** 1.2
      ** 1.1
      ** 1.1.1
      **
      ** which is what we already did before the standard pager patch. To
      ** achieve this we simply add a "/" at the end of each "thread" value.
      ** This way out thread fields will look like depicted below:
      **
      ** 1/
      ** 1.1/
      ** 1.1.1/
      ** 1.2/
      ** 2/
      **
      ** we add "/" since this char is, in ASCII, higher than every number,
      ** so if now we "ORDER BY thread DESC" we get the correct order.  Try
      ** it, it works ;).  However this would spoil the "ORDER BY thread ASC"
      ** Here, we do not need to consider the trailing "/" so we use a
      ** substring only.
      */
Dries's avatar
   
Dries committed
817

Dries's avatar
Dries committed
818
819
      if ($order == COMMENT_ORDER_NEWEST_FIRST) {
        if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
820
          $query .= ' ORDER BY c.timestamp DESC';
Dries's avatar
   
Dries committed
821
822
        }
        else {
823
          $query .= ' ORDER BY c.thread DESC';
Dries's avatar
   
Dries committed
824
        }
Dries's avatar
   
Dries committed
825
      }
Dries's avatar
Dries committed
826
827
      else if ($order == COMMENT_ORDER_OLDEST_FIRST) {
        if ($mode == COMMENT_MODE_FLAT_COLLAPSED || $mode == COMMENT_MODE_FLAT_EXPANDED) {
828
          $query .= ' ORDER BY c.timestamp';
Dries's avatar
   
Dries committed
829
830
831
832
833
834
835
836
837
        }
        else {

          /*
          ** See comment above.  Analysis learns that this doesn't cost
          ** too much.  It scales much much better than having the whole
          ** comment structure.
          */

838
          $query .= ' ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))';
Dries's avatar
   
Dries committed
839
        }
Dries's avatar
   
Dries committed
840
841
      }

842
843
      // Start a form, for use with comment control.
      $result = pager_query($query, $comments_per_page, 0, "SELECT COUNT(*) FROM {comments} WHERE nid = %d AND status = %d", $nid, COMMENT_PUBLISHED);
Dries's avatar
Dries committed
844
      if (db_num_rows($result) && (variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE || variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE_BELOW)) {
845
        $output .= comment_controls($mode, $order, $comments_per_page);
Dries's avatar
   
Dries committed
846
      }
Dries's avatar
   
Dries committed
847

Dries's avatar
   
Dries committed
848
      while ($comment = db_fetch_object($result)) {
Dries's avatar
   
Dries committed
849
        $comment = drupal_unpack($comment);
850
        $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
851
        $comment->depth = count(explode('.', $comment->thread)) - 1;
Dries's avatar
   
Dries committed
852

Dries's avatar
Dries committed
853
        if ($mode == COMMENT_MODE_FLAT_COLLAPSED) {
854
          $output .= theme('comment_flat_collapsed', $comment);
Dries's avatar
   
Dries committed
855
        }
Dries's avatar
Dries committed
856
        else if ($mode == COMMENT_MODE_FLAT_EXPANDED) {
857
          $output .= theme('comment_flat_expanded', $comment);
Dries's avatar
   
Dries committed
858
        }
Dries's avatar
Dries committed
859
        else if ($mode == COMMENT_MODE_THREADED_COLLAPSED) {
860
          $output .= theme('comment_thread_collapsed', $comment);
Dries's avatar
   
Dries committed
861
        }
Dries's avatar
Dries committed
862
        else if ($mode == COMMENT_MODE_THREADED_EXPANDED) {
863
          $output .= theme('comment_thread_expanded', $comment);
Dries's avatar
   
Dries committed
864
        }
Dries's avatar
   
Dries committed
865
      }
Dries's avatar
   
Dries committed
866

867
868
      // Use the standard pager; $pager_total is the number of returned rows,
      // is global and defined in pager.inc.
869
      $output .= theme('pager', NULL, $comments_per_page, 0, array('comments_per_page' => $comments_per_page));
Dries's avatar
   
Dries committed
870

Dries's avatar
Dries committed
871
      if (db_num_rows($result) && (variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_BELOW || variable_get('comment_controls', COMMENT_CONTROLS_HIDDEN) == COMMENT_CONTROLS_ABOVE_BELOW)) {
872
        $output .= comment_controls($mode, $order, $comments_per_page);
Dries's avatar
   
Dries committed
873
874
875
876
      }
    }

    // If enabled, show new comment form.
Dries's avatar
Dries committed
877
    if (user_access('post comments') && node_comment_mode($nid) == COMMENT_NODE_READ_WRITE && (variable_get('comment_form_location', COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_BELOW)) {
878
      $output .= comment_form(array('nid' => $nid), t('Post new comment'));
Dries's avatar
   
Dries committed
879
880
881
    }
  }
  return $output;
Dries's avatar
   
Dries committed
882
883
}

Dries's avatar
 
Dries committed
884

Dries's avatar
   
Dries committed
885
886
887
/**
 * Menu callback; delete a comment.
 */
Dries's avatar
Dries committed
888
function comment_delete($cid) {
Dries's avatar
   
Dries committed
889
  $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));
890
  $comment->name = $comment->uid ? $comment->registered_name : $comment->name;
891

Dries's avatar
Dries committed
892
  $output = '';
893

Dries's avatar
   
Dries committed
894
  // We'll only delete if the user has confirmed the
Dries's avatar
Dries committed
895
  // deletion using the form in our else clause below.
896
  if ($comment->cid && $_POST['edit']['confirm']) {
Dries's avatar
   
Dries committed
897
    drupal_set_message(t('The comment and all its replies have been deleted.'));
898

Dries's avatar
Dries committed
899
900
    // Delete comment and its replies.
    _comment_delete_thread($comment);
Dries's avatar
   
Dries committed
901

Dries's avatar
   
Dries committed
902
903
    _comment_update_node_statistics($comment->nid);

904
    // Clear the cache so an anonymous user sees that his comment was deleted.
Dries's avatar
Dries committed
905
    cache_clear_all();
Dries's avatar
   
Dries committed
906

907
908
    drupal_goto("node/$comment->nid");
  }
Dries's avatar
Dries committed
909
  else if ($comment->cid) {
910
911
    $output = confirm_form('comment_confirm_delete',
                    array(),
912
                    t('Are you sure you want to delete the comment %title?', array('%title' => theme('placeholder', $comment->subject))),
913
914
                    'node/'. $comment->nid,
                    t('Any replies to this comment will be lost. This action cannot be undone.'),
915
916
                    t('Delete'),
                    t('Cancel'));
Dries's avatar
   
Dries committed
917
918
  }
  else {
Dries's avatar
   
Dries committed
919
    drupal_set_message(t('The comment no longer exists.'));
Dries's avatar
   
Dries committed
920
  }
Dries's avatar
Dries committed
921

Dries's avatar
   
Dries committed
922
  return $output;
Dries's avatar
   
Dries committed
923
924
}

925
926
927
928
929
930
931
/**
 * Comment operations.  We offer different update operations depending on
 * which comment administration page we're on.
 */
function comment_operations($action = NULL) {
  if ($action == 'publish') {
    $operations = array(
932
      'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
933
934
935
936
937
      'delete' => array(t('Delete the selected comments'), '')
    );
  }
  else if ($action == 'unpublish') {
    $operations = array(
938
      'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
939
940
941
942
943
      'delete' => array(t('Delete the selected comments'), '')
    );
  }
  else {
    $operations = array(
944
945
      'publish' => array(t('Publish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_PUBLISHED .' WHERE cid = %d'),
      'unpublish' => array(t('Unpublish the selected comments'), 'UPDATE {comments} SET status = '. COMMENT_NOT_PUBLISHED .' WHERE cid = %d'),
946
947
948
949
950
951
      'delete' => array(t('Delete the selected comments'), '')
    );
  }
  return $operations;
}

Dries's avatar
   
Dries committed
952
953
954
955
/**
 * Menu callback; present an administrative comment listing.
 */
function comment_admin_overview($type = 'new') {
956
957
958
959
960
961
962
963
964
965
966
  global $form_values;
  $edit = $_POST['edit'];

  if ($edit['operation'] == 'delete') {
    return comment_multiple_delete_confirm();
  }

  // build an 'Update options' form
  $form['options'] = array(
    '#type' => 'fieldset', '#title' => t('Update options'),
    '#prefix' => '<div class="container-inline">', '#suffix' => '</div>'
Dries's avatar
   
Dries committed
967
  );
968
969
970
971
972
973
  $options = array();
  foreach (comment_operations(arg(3) == 'approval' ? 'publish' : 'unpublish') as $key => $value) {
    $options[$key] = $value[0];
  }
  $form['options']['operation'] = array('#type' => 'select', '#options' => $options, '#default_value' => 'publish');
  $form['options']['submit'] = array('#type' => 'submit', '#value' => t('Update'));
Dries's avatar
   
Dries committed
974

975
  // load the comments that we want to display
976
  $status = ($type == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED;
977
978
979
980
981
982
983
984
  $form['header'] = array('#type' => 'value', '#value' => array(
    NULL,
    array('data' => t('Subject'), 'field' => 'subject'),
    array('data' => t('Author'), 'field' => 'name'),
    array('data' => t('Time'), 'field' => 'timestamp', 'sort' => 'desc'),
    array('data' => t('Operations'))
  ));
  $result = pager_query('SELECT c.subject, c.nid, c.cid, c.comment, c.timestamp, c.status, c.name, c.homepage, u.name AS registered_name, u.uid FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.status = %d'. tablesort_sql($form['header']['#value']), 50, 0, NULL, $status);
Dries's avatar
   
Dries committed
985

986
987
  // build a table listing the appropriate comments
  $destination = drupal_get_destination();
Dries's avatar
   
Dries committed
988
  while ($comment = db_fetch_object($result)) {