? log_modr8_1.diff
? log_modr8_10.diff
? log_modr8_11.diff
? log_modr8_12.diff
? log_modr8_2.diff
? log_modr8_3.diff
? log_modr8_4.diff
? log_modr8_5.diff
? log_modr8_6.diff
? log_modr8_7.diff
? log_modr8_8.diff
? log_modr8_9.diff
Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/modr8/README.txt,v
retrieving revision 1.3
diff -u -p -r1.3 README.txt
--- README.txt	25 Dec 2006 23:29:58 -0000	1.3
+++ README.txt	15 Jan 2007 00:26:30 -0000
@@ -5,21 +5,37 @@ Modr8 module for Drupal 5.x.
 The moderation of content was removed from core in 5.x.  This module adds back 
 that capability and also prevents posts that are in moderation from showing
 up in lists, on the /node page, etc., unless the user is the node's author or
-unless the user has the "adminiser nodes" or "moderate content" permission.
-This is NOT an access control module, however, so (as with Drupal 4.7), posts
+unless the user has the "administer nodes" or "moderate content" permission.
+This is NOT an access control module, however, so (as with Drupal 4.7.x), posts
 that are in moderation can still be viewed if a user knows the path (URL)
-corresponding to that post.
+corresponding to that post. 
 
 This module provides an admin interface for managing content in moderation, 
 and an optional block to show how many posts are in moderation and the titles
-of recently added posts.
+of recently added posts. 
 
 The admin interface allows a user with the "moderate content" permission to 
 preview content in moderation, as well as approve or delete each moderated post, 
 and (optionally) to send an e-mail to the author informing him/her of the choice.
+*Important note:* the 5.x version will not show unpublished nodes in the 
+moderation queue listing (unlike the 4.7 version). Posts to be moderated should
+generally be set to be published so that users without the "administer  nodes" 
+permission can also effectively work as moderators.
 
 Visit the settings page to customize the e-mail messages and set other defaults.
 
+As of version 5.x-2.0, modr8 also includes a moderation log to record the
+actions of moderators on items in the moderation queue.  This may be especially
+helpful if you are using the feature to send a note by e-mail even when taking
+"no action" on a post.  Then, other moderators can see the note, and whether
+the post's author has responded to the suggested changes.  This log may also be
+useful if you want to know which moderator approved or deleted a post, and if
+they provided any specific rationale in their e-mail note.  The data for this
+log is saved in the table named {modr8_log}. Note that if you have an access
+control module enabled, events in the moderation log for nodes that have been
+deleted may only be visible to users with the "administer nodes" permission, but
+not to users with just the "moderate content" permission.
+
 This module was originally written for Drupal 4.7.x by Jeff Robbins 
 (jjeff@drupal).  Upgrade to 5.x and 5.x maintenance by Peter Wolanin 
 (pwolanin@drupal) with help from Angela Byron (webchick@drupal).
Index: modr8.install
===================================================================
RCS file: modr8.install
diff -N modr8.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modr8.install	15 Jan 2007 00:26:30 -0000
@@ -0,0 +1,95 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_install().
+ */
+function modr8_install() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE {modr8_log} (
+        modid int NOT NULL auto_increment,
+        nid int unsigned NOT NULL default '0',
+        uid int NOT NULL default '0',
+        author_uid int NOT NULL default '0',
+        action varchar(16) NOT NULL default '',
+        title varchar(128) NOT NULL default '',
+        message longtext NOT NULL,
+        teaser longtext NOT NULL,
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (modid),
+        KEY nid_time (nid, mpdid),
+        KEY action (action)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+      break;
+    case 'pgsql':
+      db_query("CREATE TABLE {modr8_log} (
+        modid serial,
+        nid int_unsigned NOT NULL default '0',
+        uid int NOT NULL default '0',
+        author_uid int NOT NULL default '0',
+        action varchar(16) NOT NULL default '',
+        title varchar(128) NOT NULL default '',
+        message text NOT NULL,
+        teaser text NOT NULL,
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (modid)
+      )");
+      db_query("CREATE INDEX {modr8_log}_nid_time ON {modr8_log} (nid, modid)");
+      db_query("CREATE INDEX {modr8_log}_act_idx ON {modr8_log} (action)");
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function modr8_uninstall() {
+  db_query('DROP TABLE {modr8_log}');
+}
+
+
+/**
+ * Update table definitions.
+ */
+function modr8_update_1000() {
+  $ret = array();
+
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("CREATE TABLE {modr8_log} (
+        modid int NOT NULL auto_increment,
+        nid int unsigned NOT NULL default '0',
+        uid int NOT NULL default '0',
+        author_uid int NOT NULL default '0',
+        action varchar(16) NOT NULL default '',
+        title varchar(128) NOT NULL default '',
+        message longtext NOT NULL,
+        teaser longtext NOT NULL,
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (modid),
+        KEY nid_time (nid, modid),
+        KEY action (action)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+      break;
+    case 'pgsql':
+      $ret[] = update_sql("CREATE TABLE {modr8_log} (
+        modid serial,
+        nid int_unsigned NOT NULL default '0',
+        uid int NOT NULL default '0',
+        author_uid int NOT NULL default '0',
+        action varchar(16) NOT NULL default '',
+        title varchar(128) NOT NULL default '',
+        message text NOT NULL,
+        teaser text NOT NULL,
+        timestamp int NOT NULL default '0',
+        PRIMARY KEY (modid)
+      )");
+      $ret[] = update_sql("CREATE INDEX {modr8_log}_nid_time ON {modr8_log} (nid, modid)");
+      $ret[] = update_sql("CREATE INDEX {modr8_log}_act_idx ON {modr8_log} (action)");
+      break;
+  }
+  return $ret;
+}
Index: modr8.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/modr8/modr8.module,v
retrieving revision 1.11
diff -u -p -r1.11 modr8.module
--- modr8.module	7 Jan 2007 17:39:45 -0000	1.11
+++ modr8.module	15 Jan 2007 00:26:31 -0000
@@ -33,12 +33,30 @@ function modr8_menu($may_cache) {
       'callback' => 'modr8_page',
     );
     $items[] = array(
-       'path' => 'admin/settings/modr8',
-       'title' => t('Modr8 settings'),
-       'description' => t('Configure content moderation.'),
-       'callback' => 'modr8_settings',
-       'access' => user_access('administer site configuration'), 
-      );
+      'path' => 'admin/logs/modr8',
+      'title' => t('Content moderation log'),
+      'description' => t('Show log of all actions on moderated content.'),
+      'access' => user_access('moderate content'),
+      'callback' => 'modr8_log_view',
+    );    
+    $items[] = array(
+      'path' => 'admin/settings/modr8',
+      'title' => t('Modr8 settings'),
+      'description' => t('Configure content moderation.'),
+      'callback' => 'modr8_settings',
+      'access' => user_access('administer site configuration'), 
+    );
+  }
+  elseif (arg(0) == 'node' && is_numeric($nid = arg(1))) {  
+    $items[] = array(
+      'path' => 'node/'. $nid .'/modr8', 
+      'title' => t('Moderation log'),
+      'callback' => 'modr8_log_view',
+      'callback arguments' => array('node', $nid),
+      'access' => user_access('moderate content') && db_result(db_query("SELECT COUNT(*) FROM {modr8_log} ml WHERE ml.nid = %d", $nid)),
+      'weight' => 10,
+      'type' => MENU_LOCAL_TASK
+    );
   }
 
   return $items;
@@ -52,6 +70,36 @@ function modr8_perm() {
 }
 
 /**
+ * menu callback for moderation log.
+ */
+function modr8_log_view($op = '', $id = 0) {  
+  
+  require_once drupal_get_path('module', 'modr8'). '/modr8_admin.inc';
+  
+  switch ($op) {
+    case '':
+      return modr8_log_overview();
+    case 'event':
+      if (is_numeric($id)) {
+        drupal_set_title(t('Moderation log event'));
+        return modr8_log_event($id);
+      }
+      break;
+    case 'node':
+      if (is_numeric($id)) {
+        $node = node_load($id);
+         if ($node->nid) {
+           drupal_set_title(check_plain($node->title));
+         }
+         return modr8_log_overview($id);
+      }
+      break;
+  }
+  drupal_not_found();
+}
+
+
+/**
  * menu callback for settings form.
  */
 function modr8_settings() {  
@@ -142,12 +190,14 @@ function modr8_page() {
   $count_sql = db_rewrite_sql('SELECT COUNT(*) FROM {node} n WHERE n.status = 1 AND n.moderate = 1');
   $page_sql = db_rewrite_sql('SELECT n.nid FROM {node} n WHERE n.status = 1 AND n.moderate = 1 ORDER BY n.changed DESC');
   $result = pager_query($page_sql, variable_get('modr8_nodes_per_page', 10), 0, $count_sql);
+  
+  $output = '<p>'. l(t('Show log of all actions on moderated content.'), 'admin/logs/modr8') .'</p>';
   if (db_num_rows($result)) {
-    $output = drupal_get_form('modr8_form', $result);
+    $output .= drupal_get_form('modr8_form', $result);
     $output .= theme('pager');
   }
   else {
-    $output = '<p>'. t('@items in moderation', array('@items' => format_plural(0, '1 post', '@count posts'))). '</p>';
+    $output .= '<p>'. t('@items in moderation', array('@items' => format_plural(0, '1 post', '@count posts'))). '</p>';
   }
   return $output;
 }
@@ -180,6 +230,17 @@ function modr8_db_rewrite_sql($query, $p
 } 
 
 /**
+ * Implementation of hook_cron()
+ *
+ *.Remove expired moderation log events.
+ */
+function modr8_cron() {
+  if ($log_clear = variable_get('modr8_log_clear', 0)) {
+    db_query('DELETE FROM {modr8_log} WHERE timestamp < %d', time() - $log_clear);
+  }
+} 
+
+/**
  * Implementation of hook_block().
  */
 function modr8_block($op = 'list', $delta = 0) {
Index: modr8_admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/modr8/modr8_admin.inc,v
retrieving revision 1.7
diff -u -p -r1.7 modr8_admin.inc
--- modr8_admin.inc	6 Jan 2007 18:10:08 -0000	1.7
+++ modr8_admin.inc	15 Jan 2007 00:26:31 -0000
@@ -20,6 +20,15 @@ function modr8_settings_form() {  
     '#options' => drupal_map_assoc(array(5, 10, 15, 20, 25, 50, 75, 100, 150, 200)),
     '#default_value' => variable_get('modr8_nodes_per_page', 10),
   );
+  $period = drupal_map_assoc(array(86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 7257600), 'format_interval');
+  $period[0] = t('Never');
+  $form['modr8_log_clear'] = array(
+    '#type' => 'select',
+    '#title' => t('Discard log entries older than'),
+    '#default_value' => variable_get('modr8_log_clear', 0),
+    '#options' => $period,
+    '#description' => t('The time log entries should be kept. Older entries will be automatically discarded. Requires crontab.')
+  );
   $form['text'] = array(
     '#type' => 'fieldset',
     '#title' => t('E-mail'),
@@ -126,8 +135,12 @@ function modr8_form($result = NULL) {
       );
     }
     $form[$node->nid]['preview'] = array(
-      '#type' => 'markup',
-      '#value' => $teaser
+      '#type' => 'value',
+      '#value' => $teaser,
+    );
+    $form[$node->nid]['author_uid'] = array(
+      '#type' => 'value',
+      '#value' => $node->uid,
     );
     $form[$node->nid]['title'] = array(
       '#type' => 'value',
@@ -166,8 +179,13 @@ function theme_modr8_form(&$form) {
         'data' => drupal_render($form[$key]['ops']) . $note_field,
         'style' => 'vertical-align:top;'
       );
+      $preview = $form[$key]['preview']['#value'];
+      if (db_result(db_query("SELECT COUNT(*) FROM {modr8_log} WHERE nid = %d", $key))) {
+        $preview .= '<div><em>'. l(t('See all moderation log events for this post'), 'node/'. $key .'/modr8/', array() , NULL, NULL, FALSE, TRUE) .'</em></div>';
+        // TODO: theme function?
+      }
       $row[] = array(
-        'data' => drupal_render($form[$key]['preview']),
+        'data' => $preview,
         'style' => 'vertical-align:top;',
       );
       $rows[] = $row;
@@ -184,30 +202,41 @@ function theme_modr8_form(&$form) {
  */
 function modr8_form_submit($form_id, $form_values) {
   foreach ($form_values as $nid => $values) {
+    $message = '';   
     switch ($values['ops']) {
       case 'approve':
         if(variable_get('modr8_send_approve', FALSE)){
-          modr8_usermail('approve', $nid, $values);
+          $message = modr8_usermail('approve', $nid, $values);
         }
         db_query('UPDATE {node} SET moderate = 0 WHERE nid = %d', $nid);
         drupal_set_message(t('The %type with title %title has been approved.', array('%title' => $values['title'], '%type' => $values['type'])));
         cache_clear_all();
+        modr8_log_action('approve', $nid, $values, $message);
         break;
       case 'delete':
         if(variable_get('modr8_send_deny', FALSE)){
-          modr8_usermail('deny', $nid, $values);
+          $message = modr8_usermail('deny', $nid, $values);
         }
         node_delete($nid);
         // drupal does its own message
+        modr8_log_action('delete', $nid, $values, $message);
         break;
       case 'nada':
         if(variable_get('modr8_send_noact', FALSE) && !empty($values['note'])){
-          modr8_usermail('nada', $nid, $values);
+          $message = modr8_usermail('nada', $nid, $values);
+          modr8_log_action('nada', $nid, $values, $message);
         }    
     }
   }
 }
 
+function modr8_log_action($op, $nid, $values, $message) {
+  global $user;
+  $actions = array('approve' => 'Approve','delete' => 'Delete','nada' => 'No action');
+  
+  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()); 
+}
+
 function modr8_usermail($op, $nid, $values){
   $node = node_load($nid);
   
@@ -254,14 +283,18 @@ function modr8_usermail($op, $nid, $valu
     // send the email
     if (drupal_mail('modr8_usermail',$account->mail, $subject, $message, $site_mail)) {
       drupal_set_message(t('%type message was sent to %username', array('%type' => $optype, '%username' => $account->name)));
+      $message = filter_filter('process', 2, -1, check_plain($message)); // Return sanitized e-mail with HTML breaks added.
     }
     else {
-      drupal_set_message(t('There was a problem sending the %type message to %username', array('%type' => $optype, '%username' => $account->name)), 'error');
+      $message = t('There was a problem sending the %type message to %username', array('%type' => $optype, '%username' => $account->name));
+      drupal_set_message($message, 'error');
     }
   }
   else {
-    drupal_set_message(t('An error occurred when trying to load this content.')); // this probably won't ever get called
+    $message = t('An error occurred when trying to load this content.');
+    drupal_set_message($message); // this probably won't ever get called
   }
+  return $message;
 }
 
 function theme_modr8_note($note){
@@ -324,3 +357,69 @@ Regards,
 The %site team');
 }
 
+
+function modr8_log_overview($nid = 0) {
+
+  $header = array(
+    array('data' => t('Action'), ),
+    array('data' => t('Date'), 'field' => 'ml.modid', 'sort' => 'desc'),
+    array('data' => t('Author'),),
+    array('data' => t('Title (view event)'),),
+  );
+  $tablesort = tablesort_sql($header);
+
+  $count_sql = "SELECT COUNT(*) FROM {modr8_log} ml";  
+  $pager_sql = "SELECT ml.modid, ml.action, ml.title, ml.timestamp, u.name, u.uid FROM {modr8_log} ml LEFT JOIN {users} u ON u.uid = ml.author_uid";
+  if ($nid) {
+    $count_sql .= " WHERE ml.nid = %d";
+    $pager_sql .= " WHERE ml.nid = %d";
+  }
+  $count_sql = db_rewrite_sql($count_sql, 'ml');
+  $pager_sql = db_rewrite_sql($pager_sql, 'ml');
+  $result = pager_query($pager_sql . $tablesort, 50, 0, $count_sql, $nid);
+  
+  $rows = array();
+  
+  while ($event = db_fetch_object($result)) {
+    $rows[] = array(t($event->action),  format_date($event->timestamp, 'small'), theme('username', $event), 
+    l(truncate_utf8($event->title, 50, TRUE, TRUE), 'admin/logs/modr8/event/'. $event->modid, array(), NULL, NULL, FALSE, TRUE)
+    );
+  }
+  
+  
+  if (!$rows) {
+    $rows[] = array(array('data' => t('No log messages available.'), 'colspan' => 4));
+  }
+
+  $output .= theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 50, 0);
+
+  return $output;
+}
+
+function modr8_log_event($modid) {
+  
+  if (is_numeric($modid)) {
+    $sql = db_rewrite_sql("SELECT ml.*, u.name FROM {modr8_log} ml LEFT JOIN {users} u ON u.uid = ml.uid WHERE ml.modid = %d", 'ml');
+    $event = db_fetch_object(db_query($sql, $modid));
+    if ($event) {
+      $event->author = db_fetch_object(db_query("SELECT u.name, u.uid from {users} u WHERE u.uid = %d", $event->author_uid));
+      return theme('moderation_event', $event);
+    }
+  }
+  
+  drupal_not_found();
+}
+
+function theme_moderation_event($event) {
+  //drupal_set_message(print_r($event, TRUE));
+  $rows[] = array(array('data' => l(t('See all moderation log events for this post'), 'node/'. $event->nid .'/modr8/', array(), NULL, NULL, FALSE, TRUE), '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;');
+  
+  return theme('table', NULL, $rows);
+}
