? usage
Index: release/project-release-serve-history.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/release/project-release-serve-history.php,v
retrieving revision 1.3
diff -u -r1.3 project-release-serve-history.php
--- release/project-release-serve-history.php	18 Jul 2007 06:16:19 -0000	1.3
+++ release/project-release-serve-history.php	18 Jul 2007 20:08:57 -0000
@@ -78,11 +78,25 @@
 
 /**
  * @todo: Record usage statistics?
+ */
 if (isset($_GET['sitekey'])) {
-  if (isset($_GET['version'])) {
+  include_once './includes/bootstrap.inc';
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);
+  
+  $site_key = $_GET['sitekey'];
+  $project_version = isset($_GET['version']) ? $_GET['version'] : '';
+  
+  // Compute a time stamp for the begining of the day.
+  $time_parts = getdate();
+  $timestamp = mktime(0, 0, 0, $time_parts['mon'], $time_parts['mday'], $time_parts['year']);
+
+  if (db_num_rows(db_query("SELECT * FROM {project_usage_day} WHERE project_uri = '%s' AND timestamp = %d AND site_key = '%s'", $project_name, $timestamp, $site_key))) { 
+    db_query("UPDATE {project_usage_day} SET api_version = '%s', project_version = '%s', pid = 0, nid = 0 WHERE project_uri = '%s' AND timestamp = %d AND site_key = '%s'", $api_version, $project_version, $project_name, $timestamp, $site_key);
+  }
+  else {
+    db_query("INSERT INTO {project_usage_day} (project_uri, timestamp, site_key, api_version, project_version) VALUES ('%s', %d, '%s', '%s', '%s')", $project_name, $timestamp, $site_key, $api_version, $project_version);
   }
 }
-*/
 
 
 /**
--- usage/project_usage.info
+++ usage/project_usage.info
@@ -0,0 +1,5 @@
+; $Id$
+name = Project usage
+description = "Provides data about installed usage of projects (requires update_status.module clients connecting to this site)."
+package = Project
+dependencies = project project_release

--- usage/project_usage.install
+++ usage/project_usage.install
@@ -0,0 +1,84 @@
+<?php
+// $Id$
+// $Name$
+
+function project_usage_install() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE IF NOT EXISTS {project_usage_day} (
+          project_uri varchar(50) NOT NULL default '',          
+          timestamp int unsigned NOT NULL default '0',
+          site_key varchar(32) NOT NULL default '',
+          api_version varchar(32) NOT NULL default '',
+          project_version varchar(255) NOT NULL default '',
+          pid int unsigned NOT NULL default '0',
+          nid int unsigned NOT NULL default '0',
+          PRIMARY KEY (project_uri, timestamp, site_key),
+          KEY (pid),
+          KEY (nid),
+          KEY (api_version)
+        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+      db_query("CREATE TABLE IF NOT EXISTS {project_usage_week_project} (
+          nid int unsigned NOT NULL default '0',
+          timestamp int unsigned NOT NULL default '0',
+          count int unsigned NOT NULL default '0',
+          PRIMARY KEY (nid, timestamp)
+        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+      db_query("CREATE TABLE IF NOT EXISTS {project_usage_week_release} (
+          nid int unsigned NOT NULL default '0',
+          timestamp int unsigned NOT NULL default '0',
+          count int unsigned NOT NULL default '0',
+          PRIMARY KEY (nid, timestamp)
+        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+      
+//      
+//      db_query("CREATE TABLE IF NOT EXISTS {project_usage_week} (
+//          site_key varchar(32) NOT NULL default '',
+//          timestamp int unsigned NOT NULL default '0',
+//          pid int unsigned NOT NULL default '0',
+//          version_tid int unsigned NOT NULL default '0',
+//          version_major int unsigned NOT NULL default '0',
+//          PRIMARY KEY (site_key, pid),
+//          KEY (pid),
+//          KEY (version_tid),
+//          KEY (version_major)
+//        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+//      db_query("CREATE TABLE IF NOT EXISTS {project_usage_count} (
+//          pid int unsigned NOT NULL default '0',
+//          version_tid int unsigned NOT NULL default '0',
+//          version_major int unsigned NOT NULL default '0',
+//          count int unsigned NOT NULL default '0',
+//          PRIMARY KEY (pid),
+//          KEY (version_tid),
+//          KEY (version_major)
+//        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+//      db_query("CREATE TABLE IF NOT EXISTS {project_usage_count_history} (
+//          pid int unsigned NOT NULL default '0',
+//          year int unsigned NOT NULL default '0',
+//          month int unsigned NOT NULL default '0',
+//          version_tid int unsigned NOT NULL default '0',
+//          version_major int unsigned NOT NULL default '0',
+//          count int unsigned NOT NULL default '0',
+//          PRIMARY KEY (pid, year, month),
+//          KEY (version_tid),
+//          KEY (version_major)
+//        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+      break;
+  }
+}
+
+function project_usage_uninstall() {
+  $tables = array(
+    'project_usage_day',
+    'project_usage_week_project',
+    'project_usage_week_release',
+  );
+  foreach ($tables as $table) {
+    if (db_table_exists($table)) {
+      db_query("DROP TABLE {$table}");
+    }
+  }
+  variable_del('project_usage_last_daily');
+  variable_del('project_usage_last_weekly');
+}

--- usage/project_usage.module
+++ usage/project_usage.module
@@ -0,0 +1,86 @@
+<?php
+// $Id$
+// $Name$
+
+/**
+ * @file
+ *
+ * This module provides logging of the XML-RPC queries that are sent by the
+ * update_status.module (contrib in 5.x) and update.module (core in 6.x) to
+ * the project_release.module on updates.drupal.org. The 
+ * release/project-release-serve-history.php script calls this module to store
+ * the data to the tables defined by this module. 
+ * 
+ * This data is then used to compute live usage statistics about all projects 
+ * hosted on drupal.org. In theory, another site could setup
+ * update_status.module-style checking to their own project.module-based
+ * XML-RPC server, in which case, they might want to enable this module.
+ * Otherwise, sites should just leave this disabled.
+ */
+
+
+/**
+ * Implementation of hook_cron().
+ * 
+ * Call the daily an weekly processing tasks as needed.
+ */
+function project_usage_cron() {
+  $cur_time = time();
+
+  // Figure out if it's been 24 hours since our last daily processing.
+#  if (variable_get('project_usage_last_daily', 0) <= ($cur_time - (60 * 60 * 24))) {
+    project_usage_process_day();
+#    variable_set('project_usage_last_daily', $cur_time);
+#  }
+
+  // Figure out if we've processed the last weeks data.
+#  $week = date('Y.W', $cur_time);
+#  if (variable_get('project_usage_last_weekly', 0) <= $week) {
+    project_usage_process_week();
+#    variable_set('project_usage_last_weekly', $week);
+#  }
+}
+
+/**
+ * Clean up today's data.
+ */
+function project_usage_process_day() {
+  watchdog('project_usage', t('Starting to process daily usage data.'));
+
+  // Set any missing pid and nids.
+  $query = db_query("SELECT DISTINCT project_uri, project_version, api_version FROM {project_usage_day} WHERE pid = 0 OR nid = 0");
+  while ($row = db_fetch_object($query)) {
+    $release = db_fetch_object(db_query("SELECT prn.pid, prn.nid FROM project_projects pp INNER JOIN project_release_nodes prn ON pp.nid = prn.pid WHERE pp.uri = '%s' AND prn.version = '%s'", $row->project_uri, $row->project_version));
+    if ($release) {
+      db_query("UPDATE {project_usage_day} SET pid = %d, nid = %d WHERE project_uri = '%s' AND project_version = '%s'", $release->pid, $release->nid, $row->project_uri, $row->project_version);
+    }
+  }
+
+  // Remove records older than a year.
+  // TODO: make this a setting. 
+  $since = time() - (60 * 60 * 24 * 356); 
+  db_query("DELETE FROM {project_usage_day} WHERE timestamp < %d", $since);
+  
+  watchdog('project_usage', t('Completed daily usage data processing.'));
+
+}
+
+/**
+ * Compute the weekly summaries for the previous week.
+ */
+function project_usage_process_week($timestamp) {
+  watchdog('project_usage', t('Starting to process weekly usage data.'));
+
+  // Compute the begining and end of last week
+  $parts = getdate(1185433200);
+  $week_start = mktime(0, 0, 0, $parts['mon'], $parts['mday'] - $parts['wday'] - 7, $parts['year']);
+  $week_end = mktime(0, 0, 0, $parts['mon'], $parts['mday'] - $parts['wday'], $parts['year']);
+  
+  db_queryd("DELETE FROM {project_usage_week_project} WHERE timestamp = %d", $week_start);
+  db_queryd("INSERT INTO {project_usage_week_project} (nid, timestamp, count) SELECT pid, %d, COUNT(pid) FROM project_usage_day WHERE pid <> 0 AND timestamp BETWEEN %d AND %d GROUP BY pid", $week_start, $week_start, $week_end);
+
+  db_queryd("DELETE FROM {project_usage_week_release} WHERE timestamp = %d", $week_start);
+  db_queryd("INSERT INTO {project_usage_week_release} (nid, timestamp, count) SELECT nid, %d, COUNT(nid) FROM project_usage_day WHERE nid <> 0 AND timestamp BETWEEN %d AND %d GROUP BY nid", $week_start, $week_start, $week_end);
+  
+  watchdog('project_usage', t('Completed weekly usage data processing.'));
+}

