? response-form-319073-5x-8.patch
? response-form-319073-6.patch
Index: modr8.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/modr8/modr8.module,v
retrieving revision 1.5.2.15
diff -u -p -r1.5.2.15 modr8.module
--- modr8.module	9 Apr 2008 02:05:35 -0000	1.5.2.15
+++ modr8.module	21 Oct 2008 15:30:33 -0000
@@ -57,6 +57,16 @@ function modr8_menu($may_cache) {
       'weight' => 10,
       'type' => MENU_LOCAL_TASK
     );
+    if (arg(2) == 'log' && arg(3) == 'response' && ($token = arg(4)) && ($node = node_load($nid))) {
+      $items[] = array(
+        'path' => 'node/'. $nid .'/log/response/'. $token,
+        'title' => 'Moderation response',
+        'callback' => 'modr8_response_page',
+        'callback arguments' => array($node),
+        'access' => modr8_response_access($node, $token),
+        'type' => MENU_CALLBACK,
+      );
+    }
   }
 
   return $items;
@@ -70,6 +80,44 @@ function modr8_perm() {
 }
 
 /**
+ * Access callback.
+ */
+function modr8_response_access($node, $token) {
+
+  return ($token == modr8_response_token($node->nid, $node->uid));
+}
+
+/**
+ * Generate a token for responding to a node in moderation.
+ *
+ * Calculates a HMAC-MD5 according to RFC2104 (http://www.ietf.org/rfc/rfc2104.txt).
+ */
+function modr8_response_token($nid, $uid) {
+  $key = md5(drupal_get_private_key() .'modr8token');
+
+  return bin2hex(
+    pack("H*", md5((str_pad($key, 64, chr(0x00)) ^ (str_repeat(chr(0x5c), 64))) .
+    pack("H*", md5((str_pad($key, 64, chr(0x00)) ^ (str_repeat(chr(0x36), 64))) .
+    $nid .':'. $key .':'. $uid))))
+  );
+}
+
+/**
+ * Menu callback; the moderation response page.
+ */
+function modr8_response_page($node) {
+  if ($node->moderate) {
+    drupal_set_title(t('Submit response regarding %title', array('%title' => $node->title)));
+    require_once drupal_get_path('module', 'modr8'). '/modr8_admin.inc';
+    return drupal_get_form('modr8_response_form', $node);
+  }
+  else {
+    drupal_set_title(t('The moderator already approved %title', array('%title' => $node->title)));
+    return '<p>'. t('This post has already been approved by the moderator. No response is needed.') .'</p>';
+  }
+}
+
+/**
  * menu callback for moderation log.
  */
 function modr8_log_view($op = '', $id = 0) {
@@ -98,7 +146,6 @@ function modr8_log_view($op = '', $id = 
   drupal_not_found();
 }
 
-
 /**
  * menu callback for settings form.
  */
Index: modr8_admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/modr8/modr8_admin.inc,v
retrieving revision 1.2.2.17
diff -u -p -r1.2.2.17 modr8_admin.inc
--- modr8_admin.inc	14 Apr 2008 23:58:13 -0000	1.2.2.17
+++ modr8_admin.inc	21 Oct 2008 15:30:33 -0000
@@ -271,7 +271,7 @@ function modr8_form_submit($form_id, $fo
 
 function modr8_log_action($op, $nid, $values, $message) {
   global $user;
-  $actions = array('approve' => 'Approve','delete' => 'Delete','nada' => 'No action');
+  $actions = array('approve' => 'Approve', 'delete' => 'Delete', 'nada' => 'No action', 'response' => 'Response');
 
   db_query("INSERT INTO {modr8_log} (nid, uid, author_uid, action, title, message, teaser, timestamp) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', %d)", $nid, $user->uid, $values['author_uid'], $actions[$op], $values['title'], $message, $values['preview'], time());
 
@@ -366,6 +366,7 @@ function modr8_replacements(){
     '%author_url' => 'url("user/". $account->uid, NULL, NULL, TRUE)',
     '%site' => 'variable_get("site_name", "Drupal")',
     '%note' => '$note',
+    '%response_url' => 'url("node/". $node->nid ."/log/response/". modr8_response_token($node->nid, $account->uid), NULL, NULL, TRUE)',
   );
 }
 
@@ -397,6 +398,8 @@ function modr8_noact_default() {
 
 %note
 
+To respond to the moderator, you can visit %response_url
+
 You can visit %node_url to view it yourself, but is is not yet visible to other site visitors.
 
 Regards,
@@ -404,11 +407,68 @@ The %site team');
 }
 
 
+/**
+ * The moderation response form.
+ */
+function modr8_response_form($node) {
+  $form = array();
+  $form['title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Response title'),
+    '#required' => TRUE,
+    '#maxlength' => 80,
+    '#weight' => -5,
+  );
+  $form['body'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Message to the moderator'),
+    '#description' => t('Please respond to the moderation messsage you received and provide additional information as appropriate to help the moderator.'),
+    '#rows' => 20,
+    '#required' => TRUE,
+  );
+  $form['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Submit'),
+    '#weight' => 5,
+  );
+  // This flag can be used by modr8, or other modules to change the teaser specifically
+  // for when it's being shown in the moderation list.
+  $node->modr8_form_teaser = TRUE;
+  $teaser = node_view($node, TRUE, FALSE, FALSE);
+  $form['preview'] = array(
+    '#type' => 'value',
+    '#value' => $teaser,
+  );
+  $form['author_uid'] = array(
+    '#type' => 'value',
+    '#value' => $node->uid,
+  );
+  $form['nid'] = array(
+    '#type' => 'value',
+    '#value' => $node->nid,
+  );
+
+  return $form;
+}
+
+/**
+ * Form submit handler - log author response.
+ *
+ * @see.modr8_response_form().
+ */
+function modr8_response_form_submit($form_id, $form_values) {
+  $form_values['title'] = check_plain($form_values['title']);
+  $message = filter_xss(nl2br($form_values['body']), array('br'));
+  modr8_log_action('response', $form_values['nid'], $form_values, $message);
+  drupal_set_message(t('Your response has been logged.'));
+  return 'node/'. $form_values['nid'];
+}
+
 function modr8_log_overview($nid = 0) {
 
   $header = array(
     array('data' => t('Action'), ),
-    array('data' => t('Moderator'), 'field' => 'u.name'),
+    array('data' => t('User'), 'field' => 'u.name'),
     array('data' => t('Date'), 'field' => 'ml.modid', 'sort' => 'desc'),
     array('data' => t('Title (view event)'),),
   );
@@ -461,10 +521,18 @@ function theme_moderation_event($event) 
   $rows[] = array(array('data' => l(t('Overview of all moderation log events for this post'), 'node/'. $event->nid .'/modr8/'), 'colspan' => 2));
   $rows[] = array(t('Action:'), t($event->action));
   $rows[] = array(t('Date:'), format_date($event->timestamp, 'small'));
-  $rows[] = array(t('Moderator:'), theme('username', $event));
-  $rows[] = array('data' => array(t('E-mail message:'), $event->message), 'style' => 'vertical-align:top;');
-  $rows[] = array(t('Author:'), theme('username', $event->author));
-  $rows[] = array('data' => array(t('Teaser (as reviewed):'), $event->teaser), 'style' => 'vertical-align:top;');
+  if ($event->action == 'Response') {
+    $rows[] = array(t('Author:'), theme('username', $event));
+    $rows[] = array(t('Response title:'), $event->title);
+    $rows[] = array('data' => array(t('Response message:'), $event->message), 'style' => 'vertical-align:top;');
+    $rows[] = array('data' => array(t('Teaser (as of response):'), $event->teaser), 'style' => 'vertical-align:top;');
+  }
+  else {
+    $rows[] = array(t('Moderator:'), theme('username', $event));
+    $rows[] = array('data' => array(t('E-mail message:'), $event->message), 'style' => 'vertical-align:top;');
+    $rows[] = array(t('Author:'), theme('username', $event->author));
+    $rows[] = array('data' => array(t('Teaser (as reviewed):'), $event->teaser), 'style' => 'vertical-align:top;');
+  }
 
   return theme('table', NULL, $rows);
 }
