Index: community_tags.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/community_tags.install,v
retrieving revision 1.9
diff -u -p -r1.9 community_tags.install
--- community_tags.install	18 Jul 2008 03:32:55 -0000	1.9
+++ community_tags.install	18 Oct 2010 16:55:32 -0000
@@ -12,7 +12,7 @@
 function community_tags_install() {
   // Install schema
   drupal_install_schema('community_tags');
-  
+
   // Drop module weight so we act after taxonomy.
   $weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'taxonomy'"));
   db_query("UPDATE {system} SET weight = %d WHERE name = 'community_tags'", $weight + 1);
Index: community_tags.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/community_tags/community_tags.module,v
retrieving revision 1.37.2.11
diff -u -p -r1.37.2.11 community_tags.module
--- community_tags.module	14 May 2010 05:00:10 -0000	1.37.2.11
+++ community_tags.module	18 Oct 2010 16:55:33 -0000
@@ -35,7 +35,7 @@ function community_tags_theme() {
     ),
     'community_tags' => array(
       'arguments' => array('tags' => NULL),
-    ),    
+    ),
   );
 }
 
@@ -59,9 +59,9 @@ function community_tags_menu() {
     'page arguments' => array(2),
     'access callback' => '_community_tags_menu_access',
     'type' => MENU_CALLBACK,
-    'file' => 'community_tags.ajax.inc',  
+    'file' => 'community_tags.ajax.inc',
   );
-  
+
   $items['community-tags/user'] = array(
     'page callback' => 'community_tags_by_user',
     'access callback' => '_community_tags_menu_access',
@@ -260,6 +260,9 @@ function community_tags_get_user_node_ta
     $tags[$term->tid] = $term;
   }
 
+  // allow other modules to have a say
+  drupal_alter('community_tags_get_user_node_tags', $tags, $uid, $nid);
+
   return $tags;
 }
 
@@ -292,11 +295,15 @@ function community_tags_taxonomy_node_sa
   if (isset($terms['tags'])) {
     $typed_input = $terms['tags'];
     unset($terms['tags']);
-    
+
       foreach ($typed_input as $vid=>$vid_value) {
         if (isset($community_tagged[$vid])) {
 
         $typed_terms = is_array($vid_value)?$vid_value:drupal_explode_tags($vid_value);
+
+        // allow other modules to alter the terms
+        drupal_alter('community_tags_terms', $typed_terms, $vid, $node, $is_owner, $uid);
+
         foreach ($typed_terms as $typed_term) {
           // See if the term exists in the chosen vocabulary
           // and return the tid, otherwise, add a new record.
@@ -307,21 +314,21 @@ function community_tags_taxonomy_node_sa
               $typed_term_tid = $possibility->tid;
             }
           }
-    
+
           if (!$typed_term_tid) {
             $edit = array ('vid'=>$vid, 'name'=>$typed_term);
             $status = taxonomy_save_term($edit);
             $typed_term_tid = $edit['tid'];
-    
+
             // Add only new terms to return value
             $tids[$typed_term_tid] = $typed_term;
           }
-    
+
           // If we already added this term in this cycle, skip this duplicate.
           if ( isset ($inserted_tids[$typed_term_tid])) {
             continue ;
           }
-    
+
           // If there was an existing tag by this user, load that data.
           $tag_node = new stdClass ();
           $tag_node->tid = $typed_term_tid;
@@ -329,7 +336,7 @@ function community_tags_taxonomy_node_sa
           $tag_node->uid = $uid;
           $tag_node->date = time();
           $tag_node->vid = $node->vid;
-    
+
           // So we don't add this tag again on this run or re-insert the old tag for this user.
           $inserted_tids[$typed_term_tid] = $typed_term_tid;
           $tag_nodes[] = $tag_node;
@@ -392,7 +399,7 @@ function community_tags_taxonomy_node_sa
       db_query('DELETE FROM {term_node} WHERE nid = %d AND tid = %d', $tag->nid, $tag->tid);
     }
   }
-  
+
   // Force re-indexing to include new tags in the search index.
   if (module_exists('search')) {
     search_touch_node($node->nid);
@@ -478,13 +485,13 @@ function community_tags_node_view($node,
   $tags = community_tags_get_user_node_tags($user->uid, $node->nid);
   $names = array();
   $output = '';
-  
+
   module_load_include('inc', 'community_tags', 'community_tags.pages');
 
   if (!count($tags)) {
     // User has not yet added tags to this node yet. Show form.
     $output .= drupal_get_form('community_tags_form', array('node' => $node, 'cloud' => $cloud, 'nid' => $node->nid, 'vid' => $vid, 'tags' => NULL, 'inline' => $inline));
-  } 
+  }
   elseif (user_access('edit own tags')) {
     // User has already tagged this node, but can edit their tags. Show form
     // with the user's tags pre-populated.
Index: contrib/community_tags_unitag/community_tags_unitag.info
===================================================================
RCS file: contrib/community_tags_unitag/community_tags_unitag.info
diff -N contrib/community_tags_unitag/community_tags_unitag.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/community_tags_unitag/community_tags_unitag.info	18 Oct 2010 16:55:33 -0000
@@ -0,0 +1,7 @@
+; $Id$
+name = Community Tags Unitag
+description = "Integrates community tags with unitag."
+dependencies[] = community_tags
+dependencies[] = unitag
+package = "Taxonomy"
+core=6.x
\ No newline at end of file
Index: contrib/community_tags_unitag/community_tags_unitag.install
===================================================================
RCS file: contrib/community_tags_unitag/community_tags_unitag.install
diff -N contrib/community_tags_unitag/community_tags_unitag.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/community_tags_unitag/community_tags_unitag.install	18 Oct 2010 16:55:33 -0000
@@ -0,0 +1,51 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * The install file for the community_tags_unitags module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function community_tags_unitag_install() {
+  // Install schema
+  drupal_install_schema('community_tags_unitag');
+
+  // Drop COMMUNITY_TAGS module weight so we act after unitag. We need it's nodeapi to run after unitag's
+  $weight = (int)db_result(db_query("SELECT weight FROM {system} WHERE name = 'unitag'"));
+  db_query("UPDATE {system} SET weight = %d WHERE name = 'community_tags'", $weight + 1);
+
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function community_tags_unitag_uninstall() {
+  drupal_uninstall_schema('community_tags_unitag');
+}
+
+/**
+ * Implementation of hook_schema().
+ */
+function community_tags_unitag_schema() {
+  $schema['community_tags_unitag'] = array(
+    'fields' => array(
+      'basename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'name' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'nid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'uid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'vid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'date' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+    ),
+    'indexes' => array(
+      'basename' => array('basename'),
+      'nid' => array('nid'),
+      'uid' => array('uid'),
+      'vid' => array('vid'),
+    ),
+    'primary key' => array('basename', 'uid', 'nid', 'vid'),
+  );
+  return $schema;
+}
Index: contrib/community_tags_unitag/community_tags_unitag.module
===================================================================
RCS file: contrib/community_tags_unitag/community_tags_unitag.module
diff -N contrib/community_tags_unitag/community_tags_unitag.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/community_tags_unitag/community_tags_unitag.module	18 Oct 2010 16:55:33 -0000
@@ -0,0 +1,163 @@
+<?php
+/**
+ * A module to push communtity tags through the unitag pipeline.
+ */
+
+/**
+ * Implementation of hook_community_tags_terms_alter(). This method is called
+ * after CT ajax form submission and node edit form submission:
+ * - CT ajax - no unitag processing so far so we do that here
+ * - node edit - tags will have been processed by unitag - new tags for moderation placed in $node->unitag_suggestions
+ */
+function community_tags_unitag_community_tags_terms_alter(&$terms, $vid, $node, $is_owner, $uid) {
+  if (isset($node->unitag_suggestions)) {
+    // node edit form mode - terms are correct but we need to record unitag suggestions against this user
+    _community_tags_unitag_save_unitag_suggestions($node->unitag_suggestions[$vid], $node, $uid, $vid);
+  }
+  else {
+    // CT ajax mode - have to replicate functionailty of unitag node edit form submission
+
+    // get terms back in the format required by unitag
+    $term_str = drupal_implode_tags($terms);
+
+    // get unitag to do it's thing
+    $unitag_result = unitag_taxonomy_terms_resolve_tags($vid, $term_str);
+
+    // replace terms to be processed by community tags with ones allowed by unitag
+    $terms = $unitag_result['parsed'];
+
+    if (!empty($unitag_result['new'])) {
+      // save nodes as unitag suggestions
+      foreach ($unitag_result['new'] as $suggestion) {
+        unitag_suggestion_save($node->nid, $vid, $suggestion);
+      }
+
+      // cleanup old suggestions
+      _community_tags_unitag_cleanup_existing_suggestions_unique_to_user($unitag_result['new'], $node->nid, $uid, $vid);
+
+      // record unitag suggestions against this user
+      _community_tags_unitag_save_unitag_suggestions($unitag_result['new'], $node, $uid, $vid);
+    }
+  }
+}
+
+/**
+ * Implementation of hook_community_tags_get_user_node_tags_alter(). Adds
+ * users tags that are waiting for moderation and aren't yet terms.
+ */
+function community_tags_unitag_community_tags_get_user_node_tags_alter(&$tags, $uid, $nid) {
+  $query = db_query("SELECT basename as tid, name, uid, nid FROM {community_tags_unitag} WHERE nid = %d AND uid = %d", $nid, $uid);
+  while ($row = db_fetch_object($query)) {
+    // obviously not a tid but it's a unique identifier for the associative array of users tags.
+    $tags[$row->tid] = $row;
+  }
+}
+
+/**
+ * Any existing CT unitag suggestions that aren't in the up to date list of suggestions
+ * for the user/node combination (i.e. have been removed by the user) and have not
+ * been suggested by another user should be removed from unitag moderation queue.
+ */
+function _community_tags_unitag_cleanup_existing_suggestions_unique_to_user($unitag_suggestions, $nid, $uid, $vid) {
+  $basenames = array();
+  foreach ($unitag_suggestions as $suggestion) {
+    $basenames[] = _unitag_get_basename($suggestion);
+  }
+
+  // query to get existing suggestions for this node that are unique to this user.
+  $query = db_query(
+    "SELECT ctu.* FROM {community_tags_unitag} ctu
+     LEFT JOIN (SELECT count(*) AS others, nid, basename, uid, vid FROM {community_tags_unitag} GROUP BY nid, basename, uid, vid) ctu2 ON ctu2.nid = ctu.nid AND ctu2.basename = ctu.basename AND ctu2.vid = ctu.vid AND ctu2.uid <> ctu.uid
+     WHERE ctu.nid = %d AND ctu.uid = %d AND ctu.vid = %d AND ctu2.others IS NULL AND ctu.basename NOT IN (" . db_placeholders($basenames, 'varchar') . ")", array_merge(array($nid, $uid, $vid), $basenames));
+
+  while ($row = db_fetch_object($query)) {
+    // remove this from unitag processing
+    unitag_suggestion_delete($row, TRUE);
+  }
+}
+
+/**
+ * Save suggestions with against node and user. Delete first as will be supplied complete
+ * up to date list of suggestions.
+ */
+function _community_tags_unitag_save_unitag_suggestions($unitag_suggestions, $node, $uid, $vid) {
+  // Insert new suggestions
+  db_lock_table('{community_tags_unitag}');
+
+  // delete existing suggestions because some may have been removed by user
+  db_query("DELETE FROM {community_tags_unitag} WHERE nid = %d AND uid = %d AND vid = %d", $node->nid, $uid, $vid);
+  foreach ($unitag_suggestions as $suggestion) {
+    // can't use utid as unitag records are deleted and re-inserted - so use basename
+    $basename = _unitag_get_basename($suggestion);
+    $date = time();
+    db_query("INSERT INTO {community_tags_unitag} (nid, uid, vid, name, basename, date) VALUES (%d, %d, %d, '%s', '%s', %d)", $node->nid, $uid, $vid, $suggestion, $basename, $date);
+  }
+
+  db_unlock_tables();
+}
+
+/**
+ * Implementation of hook_form_FROM_ID_alter() for form id = unitag_manage_suggestions_form.
+ *
+ * Processes the form submission before unitag to act on suggestion moderataion before suggestions
+ * are deleted.
+ */
+function community_tags_unitag_form_unitag_manage_suggestions_form_alter(&$form, &$form_state) {
+  array_unshift($form['#submit'], 'community_tags_unitag_unitag_manage_suggestions_form_pre_submit');
+  array_push($form['#submit'], 'community_tags_unitag_unitag_manage_suggestions_form_submit');
+}
+
+/**
+ * Just need to statically cache suggestions before unitag form processing deletes
+ * them from the database.
+ */
+function community_tags_unitag_unitag_manage_suggestions_form_pre_submit($form, &$form_state) {
+  $form_state['ct_suggestions'] = array();
+
+  $utids = array_filter($form_state['values']['utids']);
+  foreach ($utids as $utid) {
+    if ($suggestion = unitag_suggestion_load($utid)) {
+      $form_state['ct_suggestions'][$utid] = $suggestion;
+    }
+  }
+}
+
+/**
+ * Process manage suggestions form submission.
+ */
+function community_tags_unitag_unitag_manage_suggestions_form_submit($form, &$form_state) {
+  foreach ($form_state['ct_suggestions'] as $utid => $suggestion) {
+    switch ($form_state['values']['operation']) {
+      case 'new-term':
+      case 'new-child':
+        // suggestion has been saved as term (new-child just means new term saved with parents set)- so get the term by name and update community tags records
+        if ($term = unitag_taxonomy_get_term_by_name($suggestion->name, $suggestion->vid)) {
+          _community_tags_unitag_suggestion_to_term($suggestion, $term);
+        }
+        break;
+      case 'new-synonym':
+        // suggestion deemed to be a synonym of existing term - get the existing term and update community tags accordingly.
+        if ($term = unitag_taxonomy_get_term_by_name($form_state['values']['root'][$utid], $suggestion->vid)) {
+          _community_tags_unitag_suggestion_to_term($suggestion, $term);
+        }
+        break;
+      case 'deny':
+        // rejected suggestion remove from ct unitag table. Perhaps a hook here or action to notify user(s).
+        db_query("DELETE FROM {community_tags_unitag} WHERE basename = '%s' AND vid = %d", $suggestion->basename, $suggestion->vid);
+        break;
+    }
+  }
+}
+
+/**
+ * Find the suggestion in the ct unitags table and for all nid/uid's insert
+ * into community tags table with the term.
+ */
+function _community_tags_unitag_suggestion_to_term($suggestion, $term) {
+  $query = db_query("SELECT * FROM {community_tags_unitag} WHERE basename = '%s' AND vid = %d", $suggestion->basename, $suggestion->vid);
+  while ($row = db_fetch_object($query)) {
+    // create proper CT record for this approved new term.
+    db_query('INSERT INTO {community_tags} (tid, nid, uid, date) VALUES (%d, %d, %d, %d)', $term->tid, $row->nid, $row->uid, $row->date);
+  }
+  db_query("DELETE FROM {community_tags_unitag} WHERE basename = '%s' AND vid = %d", $suggestion->basename, $suggestion->vid);
+}
