? ._comment_alter_taxonomy.install
? 354340-project-issue-integration.patch
Index: comment_alter_taxonomy.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/comment_alter_taxonomy/comment_alter_taxonomy.module,v
retrieving revision 1.11
diff -u -p -r1.11 comment_alter_taxonomy.module
--- comment_alter_taxonomy.module	4 Jan 2009 22:02:31 -0000	1.11
+++ comment_alter_taxonomy.module	5 Jan 2009 01:11:59 -0000
@@ -24,17 +24,48 @@ function comment_alter_taxonomy_perm() {
 /**
  * Implementation of hook_menu().
  */
-function comment_alter_taxonomy_menu() {
+function comment_alter_taxonomy_menu($may_cache = TRUE) {
   $items = array();
 
-  $items[] = array(
-    'path' => 'admin/settings/comment_alter_taxonomy',
-    'title' => t('Comment alter taxonomy'),
-    'description' => t('Enable/disable vocabularies that users may alter from their comments.'),
-    'access' => user_access('administer site configuration'),
-    'callback' => 'drupal_get_form',
-    'callback arguments' => array('comment_alter_taxonomy_admin_settings'),
-  );
+  if ($may_cache) {
+    $items[] = array(
+      'path' => 'admin/settings/comment_alter_taxonomy',
+      'title' => t('Comment alter taxonomy'),
+      'description' => t('Enable/disable vocabularies that users may alter from their comments.'),
+      'access' => user_access('administer site configuration'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('comment_alter_taxonomy_admin_settings'),
+    );
+    if (module_exists('project_issue')) {
+      $items[] = array(
+        'path' => 'project/issues-term',
+        'title' => t('Issues for project'),
+        'callback' => '_comment_alter_taxonomy_callback',
+        'callback arguments' => array('project_issue_integration.inc', 'comment_alter_taxonomy_project_issue_page', NULL),
+        'access' => $access,
+        'type' => MENU_CALLBACK,
+      );
+    }
+  }
+  else {
+    if (module_exists('project_issue') && preg_match('@project/issues/([0-9]+)/term@', $_GET['q'], $matches)) {
+      list(, $nid) = $matches;
+
+      $access_all = user_access('access project issues');
+      $access_own = user_access('access own project issues');
+      $access_admin = user_access('administer projects');
+      $access = $access_all || $access_own || $access_admin;
+
+      $items[] = array(
+        'path' => 'project/issues/'. $nid .'/term',
+        'title' => t('Issues for project'),
+        'callback' => '_comment_alter_taxonomy_callback',
+        'callback arguments' => array('project_issue_integration.inc', 'comment_alter_taxonomy_project_issue_page', $nid),
+        'access' => $access,
+        'type' => MENU_CALLBACK,
+      );
+    }
+  }
 
   return $items;
 }
@@ -377,7 +408,7 @@ function comment_alter_taxonomy_project_
               $vocabulary = $allowed[$vid];
               $metadata["taxonomy_vid_$vid"] = array('label' => check_plain(t("$vocabulary->name")));
             }
-            $grouped_terms[$vid][] = theme('comment_alter_taxonomy_project_issue_metadata_term', $term);
+            $grouped_terms[$vid][] = theme('comment_alter_taxonomy_project_issue_metadata_term', $node, $term);
           }
         }
         foreach ($grouped_terms as $vid => $terms) {
@@ -443,7 +474,7 @@ function comment_alter_taxonomy_project_
           }
 
           // Add this term change to the $metadata array.
-          $themed_term = theme('comment_alter_taxonomy_project_issue_metadata_term', $term);
+          $themed_term = theme('comment_alter_taxonomy_project_issue_metadata_term', $node, $term);
           if (is_array($metadata["taxonomy_vid_$vid"][$old_new])) {
             // Multiple select vocabulary.
             $metadata["taxonomy_vid_$vid"][$old_new][$tid] = $themed_term;
@@ -480,9 +511,15 @@ function comment_alter_taxonomy_project_
  * @return
  *  The themed term.
  */
-function theme_comment_alter_taxonomy_project_issue_metadata_term($term) {
+function theme_comment_alter_taxonomy_project_issue_metadata_term($node, $term) {
   if (isset($term->tid)) {
-    return l($term->name, taxonomy_term_path($term));
+    if (module_exists('project_issue') && $node->type == 'project_issue') {
+      $path = 'project/issues/'. $node->pid .'/term/'. $term->tid;
+    }
+    else {
+      $path = taxonomy_term_path($term);
+    }
+    return l($term->name, $path);
   }
   else {
     // New free tagging terms won't yet have a tid in the node preview mode
@@ -690,6 +727,27 @@ function comment_alter_taxonomy_get_alte
 }
 
 /**
+ * Implementation of hook_link_alter().
+ *
+ * Remove taxonomy links on project issues, when required.
+ */
+function comment_alter_taxonomy_link_alter(&$node, &$links) {
+  if (module_exists('project_issue') && $node->type == 'project_issue') {
+    $allowed = comment_alter_taxonomy_get_alterable_vocabularies('project_issue');
+    if (empty($allowed) || empty($node->taxonomy)) {
+      return;
+    }
+    if (!empty($node->taxonomy)) {
+      foreach ($node->taxonomy as $tid => $term) {
+        if (isset($allowed[$term->vid])) {
+          unset($links['taxonomy_term_'. $term->tid]);
+        }
+      }
+    }
+  }
+}
+
+/**
  * Implementation of hook_taxonomy().
  *
  * Handle deletion of terms and vocabularies from the database.
@@ -712,3 +770,15 @@ function comment_alter_taxonomy_taxonomy
     db_query('DELETE FROM {comment_alter_taxonomy} WHERE tid = %d', $tids);
   }
 }
+
+/**
+ * Wrapper to define callbacks in include files.
+ */
+function _comment_alter_taxonomy_callback($file, $function) {
+  $args = func_get_args();
+  $file = array_shift($args);
+  $function = array_shift($args);
+
+  include_once drupal_get_path('module', 'comment_alter_taxonomy') .'/'. $file;
+  return call_user_func_array($function, $args);
+}
Index: project_issue_integration.inc
===================================================================
RCS file: project_issue_integration.inc
diff -N project_issue_integration.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ project_issue_integration.inc	5 Jan 2009 01:12:00 -0000
@@ -0,0 +1,214 @@
+<?php
+// $Id $
+
+/**
+ * @file
+ * project_issue integration code.
+ */
+
+/**
+ * Note: this code is mostly taken and adapted from issue.inc and taxonomy.module
+ * This is a somewhat ugly approach to stop a gap on d.o before upgrading to 6
+ * (and hopefully to Views...).
+ */
+
+/**
+ * Display the list of issues matching given terms.
+ */
+function comment_alter_taxonomy_project_issue_page($project_name = NULL, $str_tids, $depth = 0, $op = 'page') {
+  $project = project_project_retrieve($project_name);
+  if (isset($project->nid) && $project_nid = $project->nid) {
+    if (!node_access('view', $project)) {
+      drupal_access_denied();
+    }
+  }
+  else {
+    $project_nid = NULL;
+  }
+
+  $terms = taxonomy_terms_parse_string($str_tids);
+  if ($terms['operator'] != 'and' && $terms['operator'] != 'or') {
+    drupal_not_found();
+  }
+
+  if ($terms['tids']) {
+    $placeholders = implode(',', array_fill(0, count($terms['tids']), '%d'));
+    $result = db_query(db_rewrite_sql('SELECT t.tid, t.name FROM {term_data} t WHERE t.tid IN ('. $placeholders .')', 't', 'tid'), $terms['tids']);
+    $tids = array(); // we rebuild the $tids-array so it only contains terms the user has access to.
+    $names = array();
+    while ($term = db_fetch_object($result)) {
+      $tids[] = $term->tid;
+      $names[] = $term->name;
+    }
+
+    if ($names) {
+      if ($project_nid) {
+        $title = t("Issues for %project tagged with %title", array('%project' => $project->title, '%title' => implode(', ', $names)));
+      }
+      else {
+        $title = t("Project issues tagged with %title", array('%title' => implode(', ', $names)));
+      }
+      drupal_set_title($title);
+
+      switch ($op) {
+        case 'page':
+          $header = array();
+          if (!$project->nid) {
+            $header[] = array('data' => t('Project'), 'field' => 'p.pid');
+          }
+          $header[] = array('data' => t('Summary'), 'field' => 'n.title');
+          $header[] = array('data' => t('Status'), 'field' => 'p.sid');
+          $header[] = array('data' => t('Priority'), 'field' => 'p.priority');
+          $header[] = array('data' => t('Category'), 'field' => 'p.category');
+          if (!empty($releases)) {
+            $header[] = array('data' => t('Version'), 'field' => 'p.rid');
+          }
+          $header[] = array('data' => t('Last updated'), 'field' => 'n.changed', 'sort' => 'desc');
+          $header[] = array('data' => t('Assigned to'), 'field' => 'u.name');
+
+          $result = comment_alter_taxonomy_project_select_nodes($tids, $terms['operator'], $project_nid, $depth, TRUE);
+
+          if ($project_nid) {
+            drupal_add_feed(url('project/issues/'. $project_nid .'/term/'. $str_tids .'/'. $depth .'/feed'), 'RSS - '. $title);
+          }
+          else {
+            drupal_add_feed(url('project/issues-term/'. $str_tids .'/'. $depth .'/feed'), 'RSS - '. $title);
+          }
+
+          $uris = NULL;
+          $projects = array(0 => t('<all>')) + project_projects_select_options($uris);
+          $states = array(implode(',', array_keys(project_issue_state())) => t('<all>')) + project_issue_state();
+          $priorities = array(0 => t('<all>')) + project_issue_priority();
+
+          if (project_use_taxonomy()) {
+            $flat_projects = array();
+            foreach ($projects as $tmp) {
+              if (is_array($tmp)) {
+                $flat_projects += $tmp;
+              }
+            }
+            $projects = $flat_projects;
+          }
+
+          $rows = array();
+
+          while ($node = db_fetch_object($result)) {
+            $node = node_load($node->nid);
+            $row = array();
+            $class = "state-$node->sid";
+            if (!$project->nid) {
+              $row[] = l($projects[$node->pid], "project/issues/$node->pid");
+            }
+            if (strlen($node->title) > 50) {
+              $title = l(drupal_substr($node->title, 0, 50), "node/$node->nid", array('title' => $node->title));
+            }
+            else {
+              $title = l($node->title, "node/$node->nid");
+            }
+            $row[] = $title . theme('mark', node_mark($node->nid, $node->changed));
+            $row[] = $states[$node->sid];
+            $row[] = $priorities[$node->priority];
+            $row[] = project_issue_category($node->category, 0);
+            if (count($releases)) {
+              $row[] = $releases[$node->rid];
+            }
+            $row[] = array('data' => format_interval(time() - $node->changed, 2), 'align' => 'right');
+            $row[] = ($node->assigned) ? theme('username', user_load(array('uid' => $node->assigned))) : '';
+
+            $row = array('data' => $row, 'class' => $class);
+
+            $rows[] = $row;
+          }
+
+          if (!count($rows)) {
+            $rows[] = array(array('data' => t('No issues found.'), 'colspan'=> 8));
+          }
+
+          if ($pager = theme('pager', NULL, $issues_per_page, 0)) {
+            $rows[] = array(array('data' => $pager, 'colspan' => count($header)));
+          }
+
+          $output = '<div class="project-issue">';
+          $output .= '<div class="quick-search">';
+
+          $output .= '</div>';
+          $output .= theme('table', $header, $rows);
+
+          $output .= '</div>';
+          return $output;
+          break;
+
+        case 'feed':
+          $term = taxonomy_get_term($tids[0]);
+          $channel['link'] = url('taxonomy/term/'. $str_tids .'/'. $depth, NULL, NULL, TRUE);
+          $channel['title'] = variable_get('site_name', 'Drupal') .' - '. $title;
+          $channel['description'] = $term->description;
+
+          $result = comment_alter_taxonomy_project_select_nodes($tids, $terms['operator'], $project_nid, $depth, FALSE);
+          node_feed($result, $channel);
+          break;
+        default:
+          drupal_not_found();
+      }
+    }
+    else {
+      drupal_not_found();
+    }
+  }
+}
+
+function comment_alter_taxonomy_project_select_nodes($tids = array(), $operator = 'or', $project_nid = NULL, $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC') {
+  if (count($tids) > 0) {
+    // For each term ID, generate an array of descendant term IDs to the right depth.
+    $descendant_tids = array();
+    if ($depth === 'all') {
+      $depth = NULL;
+    }
+    foreach ($tids as $index => $tid) {
+      $term = taxonomy_get_term($tid);
+      $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
+      $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
+    }
+
+    $args = array();
+    if (isset($project_nid)) {
+      $project_join = " INNER JOIN {project_issues} pi ON pi.nid = n.nid ";
+      $project_where = " AND pi.pid = %d ";
+      $args[] = $project_nid;
+    }
+    else {
+      $project_join = "";
+      $project_where = "";
+    }
+
+    if ($operator == 'or') {
+      $args = call_user_func_array('array_merge', $descendant_tids);
+      $placeholders = implode(',', array_fill(0, count($args), '%d'));
+      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $project_join .' INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .") AND n.status = 1 AND n.type = 'project_issue' $project_where ORDER BY ". $order;
+      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $project_join .' INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .") AND n.status = 1 AND n.type = 'project_issue' " . $project_where;
+    }
+    else {
+      $joins = '';
+      $wheres = '';
+      foreach ($descendant_tids as $index => $tids) {
+        $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid';
+        $placeholders = implode(',', array_fill(0, count($tids), '%d'));
+        $wheres .= ' AND tn'. $index .'.tid IN ('. $placeholders .')';
+        $args = array_merge($args, $tids);
+      }
+      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $project_join .' '. $joins ." WHERE n.status = 1 AND n.type = 'project_issue' ". $project_where ." ". $wheres .' ORDER BY '. $order;
+      $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $project_join .' '. $joins ." WHERE n.status = 1 AND n.type = 'project_issue' ". $project_where ." ". $wheres;
+    }
+    $sql = db_rewrite_sql($sql);
+    $sql_count = db_rewrite_sql($sql_count);
+
+    if ($pager) {
+      $result = pager_query($sql, variable_get('project_issues_per_page', PROJECT_ISSUES_PER_PAGE), 0, $sql_count, $args);
+    }
+    else {
+      $result = db_query_range($sql, $args, 0, variable_get('feed_default_items', 10));
+    }
+  }
+
+  return $result;
+}
