Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simplefeed/README.txt,v
retrieving revision 1.18.2.24
diff -u -F^f -r1.18.2.24 README.txt
--- README.txt	26 Sep 2008 04:20:04 -0000	1.18.2.24
+++ README.txt	27 Sep 2008 01:35:57 -0000
@@ -48,6 +48,7 @@
 - optional views support
 - optional token support
 - optionally verify feeds before adding to database
+- optional stats collecting module for per-feed stats and global stats on feed usage
 
 
 
@@ -108,6 +109,7 @@
 
 3.x, 2008-xx-xx
 ----------------------
+- #314087 - new feed stats
 - #297991 - move refresh/empty links to local tasks instead of links
 - #301290 - improved performance with feeds throwing errors, new option to verify feeds at input
 - #307686 - fix Feedburner feeds and improve performance of feed checking
Index: simplefeed.css
===================================================================
RCS file: simplefeed.css
diff -N simplefeed.css
--- simplefeed.css	3 Oct 2007 21:19:05 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,15 +0,0 @@
-/* $Id: simplefeed.css,v 1.3 2007/10/03 21:19:05 m3avrck Exp $ */
-ul.simplefeed, ul.simplefeed-item {
-margin:0;
-padding:0.3em;
-border:1px solid #ccc;
-background:#eee;
-}
-
-ul.simplefeed li, ul.simplefeed-item li {
-display: inline;
-list-style-type: none;
-background:none;
-margin:0;
-padding:0 2em 0 0;
-}
\ No newline at end of file
Index: simplefeed.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simplefeed/simplefeed.module,v
retrieving revision 1.44.2.15
diff -u -F^f -r1.44.2.15 simplefeed.module
--- simplefeed.module	26 Sep 2008 04:10:40 -0000	1.44.2.15
+++ simplefeed.module	27 Sep 2008 01:35:57 -0000
@@ -43,25 +43,29 @@ function simplefeed_menu($may_cache) {
 
   else {
     if (arg(0) == 'node' && is_numeric(arg(1)) && user_access('administer feeds')) {
-      $items[] = array(
-        'path' => 'node/'. arg(1) .'/refresh',
-        'title' => t('Refresh feed'),
-        'callback' => 'simplefeed_feed_refresh',
-        'callback arguments' => array(arg(1)),
-        'access' => user_access('administer feeds'),
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 2,
-      );
-
-      $items[] = array(
-        'path' => 'node/'. arg(1) . '/empty',
-        'title' => t('Empty feed'),
-        'callback' => 'simplefeed_feed_empty',
-        'callback arguments' => array(arg(1)),
-        'access' => user_access('administer feeds'),
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 3,        
-      );
+      // since you are viewing a node this is already cached
+      $node = node_load(arg(1));
+      if ($node->type == 'feed') {
+        $items[] = array(
+          'path' => 'node/'. arg(1) .'/refresh',
+          'title' => t('Refresh feed'),
+          'callback' => 'simplefeed_feed_refresh',
+          'callback arguments' => array(arg(1)),
+          'access' => user_access('administer feeds'),
+          'type' => MENU_LOCAL_TASK,
+          'weight' => 2,
+        );
+
+        $items[] = array(
+          'path' => 'node/'. arg(1) . '/empty',
+          'title' => t('Empty feed'),
+          'callback' => 'simplefeed_feed_empty',
+          'callback arguments' => array(arg(1)),
+          'access' => user_access('administer feeds'),
+          'type' => MENU_LOCAL_TASK,
+          'weight' => 3,
+        );
+      }
     }
   }
 
@@ -195,19 +199,19 @@ function simplefeed_validate($node) {
     if ($duplicate != '' && $duplicate != $node->nid) {
       form_set_error('url', t('The URL entered already exists. Please try a different URL.'));
     }
-    
+
     if (variable_get('simplefeed_check_url', 1)) {
       include_once './'. drupal_get_path('module', 'simplefeed') .'/simplepie.inc';
-      
+
       // init simplepie and have it see if it can find a feed
       $feed = new SimplePie();
       $feed->enable_cache(FALSE);
       $feed->set_timeout(15);
-      
+
       // prevent SimplePie from using all of it's data santization since we use Drupal's input formats to handle this
       $feed->set_stupidly_fast(TRUE);
       $feed->set_feed_url($node->url);
-  
+
       // feed hasn't been added yet, so use a very low time setting
       // FeedBurner requires this
       header("If-Modified-Since:" . 1);
@@ -287,58 +291,6 @@ function simplefeed_nodeapi(&$node, $op,
 
 
 /**
- * Implementation of hook_view().
- */
-function simplefeed_view($node, $teaser = FALSE, $page = FALSE) {
-  $node = node_prepare($node, $teaser);
-
-  $node->content['simplefeed']['#theme'] = 'simplefeed_node_view';
-  $node->content['simplefeed']['#weight'] = 2;
-  $node->content['simplefeed']['url'] = array(
-    '#value' => check_url($node->url),
-    '#weight' => 1,
-  );
-
-  // since only administrators can edit when a feed expires, only admins can see what this value is
-  if (user_access('administer feeds')) {
-    $node->content['simplefeed']['expires'] = array(
-      '#value' => format_interval($node->expires),
-    );
-    $node->content['simplefeed']['refresh'] = array(
-      '#value' => format_interval($node->refresh),
-    );
-    $node->content['simplefeed']['checked'] = array(
-      '#value' => $node->checked > 0 ? format_interval(time() - $node->checked) . t(' ago') : t('Never'),
-    );
-  }
-
-  return $node;
-}
-
-
-/**
- * Theme the display of a feed node.
- */
-function theme_simplefeed_node_view($values) {
-  // needs to be a space so default values aren't outputed
-  $output = ' ';
-
-  // since only administrators can edit when a feed expires, only admins can see what this value is
-  if (user_access('administer feeds')) {
-    drupal_add_css(drupal_get_path('module', 'simplefeed') .'/simplefeed.css');
-
-    $output .= '<ul class="simplefeed">';
-    $output .= '<li><strong>Expires:</strong> '. $values['expires']['#value'] .'</li>';
-    $output .= '<li><strong>Refresh:</strong> '. $values['refresh']['#value'] .'</li>';
-    $output .= '<li><strong>Checked:</strong> '. $values['checked']['#value'] .'</li>';
-    $output .= '</ul>';
-  }
-
-  return $output;
-}
-
-
-/**
  * Implementation of hook_link().
  */
 function simplefeed_link($type, $node = NULL, $teaser = FALSE) {
@@ -432,7 +384,7 @@ function simplefeed_admin_settings() {
     '#options' => $throttle,
     '#default_value' => variable_get('simplefeed_cron_throttle', 50),
   );
-  
+
   $form['simplefeed_check_url'] = array(
     '#type' => 'select',
     '#title' => t('Verify feed before adding to database'),
@@ -559,9 +511,15 @@ function simplefeed_feed_process($nid) {
     // finished processing this feed so we can mark it checked
     db_query("UPDATE {simplefeed_feed} SET checked = %d, hash = '%s', error = 0 WHERE vid = %d", time(), $hash, $process_feed->vid);
   }
-  else if (isset($feed->error)) {
-    watchdog('simplefeed', t('The feed %feed could not be processed due to the following error: %error', array('%feed' => $process_feed->title, '%error' => $feed->error)), WATCHDOG_ERROR, l('view', 'node/'. $process_feed->nid));
+  else if (isset($feed->error)) {    
     db_query("UPDATE {simplefeed_feed} SET error = 1 WHERE vid = %d", $process_feed->vid);
+
+    if (module_exists('simplefeed_stats')) {
+      simplefeed_stats_feed_fail($process_feed, $feed->error);
+    }
+    else {
+      watchdog('simplefeed', t('The feed %feed could not be processed due to the following error: %error', array('%feed' => $process_feed->title, '%error' => $feed->error)), WATCHDOG_ERROR, l('view', 'node/'. $process_feed->nid));
+    }
   }
   else {
     watchdog('simplefeed', 'You shouldn\'t be here. Something has gone terribly wrong.');
@@ -579,6 +537,11 @@ function simplefeed_feed_empty($nid) {
       node_delete($node->nid);
     }
     db_query("UPDATE {simplefeed_feed} SET hash = NULL WHERE nid = %d", $nid);
+
+    if (module_exists('simplefeed_stats')) {
+      simplefeed_stats_feed_empty($nid);
+    }
+
     drupal_set_message(t('Feed emptied.'));
     drupal_goto('node/'. $nid);
   }
Index: simplefeed_item.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simplefeed/simplefeed_item.module,v
retrieving revision 1.51.2.15
diff -u -F^f -r1.51.2.15 simplefeed_item.module
--- simplefeed_item.module	2 Jul 2008 20:09:51 -0000	1.51.2.15
+++ simplefeed_item.module	27 Sep 2008 01:35:57 -0000
@@ -229,51 +229,6 @@ function simplefeed_item_nodeapi(&$node,
 
 
 /**
- * Implementation of hook_view().
- */
-function simplefeed_item_view($node, $teaser = FALSE, $page = FALSE) {
-  $node = node_prepare($node, $teaser);
-
-  $node->content['simplefeed_item']['#theme'] = 'simplefeed_item_node_view';
-  $node->content['simplefeed_item']['#weight'] = 2;
-  $node->content['simplefeed_item']['url'] = array(
-    '#value' => check_url($node->url),
-    '#weight' => 1,
-  );
-
-  // since only administrators can edit when a feed item expires, only admins can see what this value is
-  if (user_access('administer feeds')) {
-    $node->content['simplefeed_item']['expires'] = array(
-      '#value' => format_interval($node->expires),
-      '#weight' => 2,
-    );
-  }
-
-  return $node;
-}
-
-
-/**
- * Theme the display of a feed node.
- */
-function theme_simplefeed_item_node_view($values) {
-  // needs to be a space so default values aren't outputed
-  $output = ' ';
-
-  // since only administrators can edit when a feed item expires, only admins can see what this value is
-  if (user_access('administer feeds')) {
-    drupal_add_css(drupal_get_path('module', 'simplefeed') .'/simplefeed.css');
-
-    $output = '<ul class="simplefeed-item">';
-    $output .= '<li><strong>Expires:</strong> '. $values['expires']['#value'] .'</li>';
-    $output .= '</ul>';
-  }
-
-  return $output;
-}
-
-
-/**
  * Implementation of hook_link().
  */
 function simplefeed_item_link($type, $node = NULL, $teaser = FALSE) {
@@ -320,7 +275,7 @@ function simplefeed_item_feed_expire() {
   // and switch back to current user at the end
   $current_user = $user;
   $user = user_load(array('uid' => 1));
-  
+
   // delete all expired feed items, ignore $vid since we expire *every* feed item in one call, not specific ones
   // note if a feed item has multiple revisions, any revision's expiration can trigger deletion of the entire node
   $items = db_query('SELECT n.nid FROM {node} n JOIN {simplefeed_feed_item} s ON n.vid = s.vid WHERE s.expires <> 0 AND s.expires <= (%d - n.created)', time());
@@ -337,7 +292,7 @@ function simplefeed_item_feed_expire() {
       db_query('OPTIMIZE TABLE {simplefeed_feed_item}');
     }
   }
-  
+
   $user = $current_user;
 }
 
@@ -353,6 +308,7 @@ function simplefeed_item_feed_expire() {
 function simplefeed_item_feed_parse($process_feed, $feed) {
   // loop through all of the items in the feed, faster than foreach
   $max = $feed->get_item_quantity();
+  $count = 0;
 
   for ($i = 0; $i < $max; $i++) {
     $item = $feed->get_item($i);
@@ -455,6 +411,7 @@ function simplefeed_item_feed_parse($pro
       $values['fid'] = $process_feed->nid;
       $values['taxonomy'] = $item->taxonomy;
 
+      $count++;
       // create a new feed-item node, adding in all of the other node defaults
       drupal_execute('feed_item_node_form', $values, $node);
     }
@@ -462,4 +419,7 @@ function simplefeed_item_feed_parse($pro
     // we unset $item each time to prevent any pass by reference memory leaks that PHP encounters with objects in foreach loops
     unset($item);
   }
+  if (module_exists('simplefeed_stats')) {
+     simplefeed_stats_updated_feed($count, $process_feed);
+  }
 }
Index: simplefeed_stats.info
===================================================================
RCS file: simplefeed_stats.info
diff -N simplefeed_stats.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ simplefeed_stats.info	27 Sep 2008 01:35:57 -0000
@@ -0,0 +1,5 @@
+; $Id: $
+name = SimpleFeed Statistics
+description = Collects statistics about Simplefeed usage.
+package = SimpleFeed
+dependencies = simplefeed
Index: simplefeed_stats.install
===================================================================
RCS file: simplefeed_stats.install
diff -N simplefeed_stats.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ simplefeed_stats.install	27 Sep 2008 01:35:57 -0000
@@ -0,0 +1,42 @@
+<?php
+// $Id: $
+
+/**
+ * Implementation of hook_install().
+ */
+function simplefeed_stats_install() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE {simplefeed_feed_stats} (
+        sid int unsigned NOT NULL,
+        fid int unsigned NOT NULL,
+        new_nodes int unsigned NOT NULL DEFAULT 0,
+        msg TEXT,
+        timestamp int unsigned NOT NULL,
+        PRIMARY KEY (sid),
+        KEY fid (fid)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
+      break;
+    case 'pgsql':
+      db_query("CREATE TABLE {simplefeed_feed_stats} (
+        sid int_unsigned NOT NULL,
+        fid int_unsigned NOT NULL,
+        num_nodes int_unsigned NOT NULL,
+        msg text,
+        timestamp int_unsigned NOT NULL default '0',
+        PRIMARY KEY (sid)
+      )");
+      db_query("CREATE INDEX {simplefeed_feed_stats}_fid_idx ON {simplefeed_feed_stats} (fid)");      
+      break;
+  }
+
+  drupal_set_message(t('SimpleFeed Statistics successfully installed.'));
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function simplefeed_stats_uninstall() {
+  db_query('DROP TABLE {simplefeed_feed_stats}');
+}
Index: simplefeed_stats.module
===================================================================
RCS file: simplefeed_stats.module
diff -N simplefeed_stats.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ simplefeed_stats.module	27 Sep 2008 01:35:57 -0000
@@ -0,0 +1,196 @@
+<?php
+// $Id: $
+
+/**
+ * @file
+ * Produces stats about simple feed and provides an admin interface
+ */
+
+/**
+ * Implentation of hook_menu
+ */
+function simplefeed_stats_menu($may_cache) {
+  global $user;
+
+  if ($may_cache) {
+     $items[] = array(
+      'path' => 'admin/content/simplefeed',
+      'title' => t('Feeds'),
+      'description' => t('View statistics about Simplefeed processing'),
+      'callback' => 'simplefeed_stats_admin',
+      'access' => user_access('administer feeds'),
+    );
+
+    return $items;
+  }
+  else {
+    if (arg(0) == 'node' && is_numeric(arg(1))) {
+      // since you are viewing a node this is already cached
+      $node = node_load(arg(1));
+      if ($node->type == 'feed') {
+        $items[] = array(
+          'path' => 'node/'. arg(1) . '/log',
+          'title' => t('Feed log'),
+          'callback' => 'simplefeed_stats_log',
+          'callback arguments' => array(arg(1)),
+          'access' => user_access('view simplefeed logs') || (user_access('view own simplefeed logs') && $user->uid == $node->uid),
+          'type' => MENU_LOCAL_TASK,
+          'weight' => 4
+        );
+      }
+    }
+    return $items;
+  }
+}
+
+function simplefeed_stats_perm() {
+  return array('view simplefeed logs', 'view own simplefeed logs');
+}
+
+/**
+ * Page callback for the status page of simplefeed
+ */
+function simplefeed_stats_admin() {
+  $header = array(
+    array(
+      'data' => t('Title'),
+      'sort' => 'ASC',
+      'field' => 'title',
+    ),
+    array(
+      'data' => t('Last Refresh'),
+      'sort' => 'DESC',
+      'field' => 'timestamp',
+    ),
+    array(
+      'data' => t('Number of Posts'),
+      'field' => 'number',
+    ),
+    array(
+      'data' => t('Average Posts per Update'),
+      'field' => 'average',
+    ),
+    array(
+      'data' => t('Errors'),
+      'field' => 'error',
+    ),    
+    t('Actions'),
+   );
+
+   $sql = "SELECT n.nid, n.title, s.timestamp, count(DISTINCT(i.vid)) as number, count(DISTINCT(i.vid)) / count(DISTINCT(s.sid)) as average, f.error FROM {node} n JOIN {simplefeed_feed} f ON n.nid = f.nid JOIN {simplefeed_feed_stats} s ON s.fid = n.nid LEFT JOIN {simplefeed_feed_item} i ON i.fid = s.fid GROUP BY s.fid";
+   $count_sql = "SELECT count(s.nid) FROM {simplefeed_feed} s";
+   $results = pager_query($sql . tablesort_sql($header), 15, 0, $count_sql);
+
+   while ($feed_array = db_fetch_array($results)) {
+     $nid = $feed_array['nid'];
+     unset($feed_array['nid']);
+
+     $actions_column = theme('item_list', array(
+       l('Empty', 'node/' . $nid . '/empty'),
+       l('Refresh', 'node/' . $nid . '/refresh'),
+       l('View Log', 'node/' . $nid . '/log'),
+      )
+     );
+
+     $feed_array['timestamp'] = format_date($feed_array['timestamp'], 'small');
+     $feed_array['title'] = l($feed_array['title'], 'node/' . $nid);
+     $feed_array['average'] = round($feed_array['average'], 2);
+     $feed_array['actions'] = $actions_column;
+     $rows[] = $feed_array;
+   }
+
+   if (count($rows) > 0) {
+     $output = theme('table', $header, $rows);
+     $output .= theme('pager', NULL, 15);
+   }
+   else {
+     $output .= t('Cron needs to run first to collect feed stats.');
+   }
+
+   return $output;
+}
+
+/**
+ * recieves the number of simplefeed_items created by a given feed
+ * and adds to the db table
+ *
+ * @param $count
+ * number of nodes created
+ *
+ * @param $feed_node
+ * the feed node
+ */
+function simplefeed_stats_updated_feed($count, $feed_node) {
+  // update the table add in the count msg et al to the table
+  // php5 use $_REQUEST['time'] instead of time()
+  // insert even if no nodes were added
+  db_query("INSERT INTO {simplefeed_feed_stats} (sid, fid, new_nodes, timestamp, msg) VALUES (%d, %d, %d, %d, '%s')", db_next_id('{simplefeed_sid}'), $feed_node->nid, $count, time(), 'Success');
+}
+
+/**
+ * Recieves the error msg when a feed fails and logs it
+ *
+ * @param $feed_node
+ * the feed node that failed
+ *
+ * @param error_msg
+ * error message recieve when it failed
+ */
+function simplefeed_stats_feed_fail($feed_node, $error_msg) {
+  db_query("INSERT INTO {simplefeed_feed_stats} (sid, fid, msg, timestamp) VALUES (%d, %d, '%s', %d)", db_next_id('{simplefeed_sid}'), $feed_node->nid, $error_msg, time());
+}
+
+/**
+ * Recieves a nid that was just emptied
+ *
+ * @param $fid
+ * fid that was just emptied
+ */
+function simplefeed_stats_feed_empty($fid) {
+  db_query("INSERT INTO {simplefeed_feed_stats} (sid, fid, msg, timestamp) VALUES (%d, %d, '%s', %d)", db_next_id('{simplefeed_sid}'), $fid, 'Feed was emptied', time());
+}
+
+/**
+ * Displays the log of the feed
+ *
+ * @param $nid
+ * nid of the feed node
+ */
+function simplefeed_stats_log($nid) {
+  $output = '';
+  drupal_set_title('Feed log');
+
+  // need a check to make sure the node is a feed ?
+  $header = array(
+    array(
+      'data' => t('Date'),
+      'field' => 'timestamp',
+      'sort' => 'DESC',
+    ),
+    array(
+      'data' => t('New Posts'),
+      'field' => 'new_nodes',
+    ),
+    t('Message'),
+  );
+
+  $sql = "SELECT timestamp, new_nodes, msg FROM {simplefeed_feed_stats} WHERE fid = %d";
+  $count_sql = "SELECT COUNT(sid) FROM {simplefeed_feed_stats} WHERE fid = %d";
+  $log_result = pager_query($sql . tablesort_sql($header), 15, 0, $count_sql, $nid);
+  while ($log_object = db_fetch_object($log_result)) {
+    $rows[] = array(
+      date('n/j/Y g:i a', $log_object->timestamp),
+      $log_object->new_nodes,
+      t($log_object->msg),
+    );
+  }
+
+  if (count($rows) > 0) {
+    $output .= theme('table', $header, $rows) . theme('pager', NULL, 15);
+  }
+  else {
+    $output .= t('Stats for this feed will appear after it has been processed.');
+  }
+
+  return $output;
+}
