Index: contact/project_issue_contact.info
===================================================================
--- contact/project_issue_contact.info	(revision 0)
+++ contact/project_issue_contact.info	(revision 0)
@@ -0,0 +1,7 @@
+; $Id$
+name = Project issue contact integration
+description = Allows the site-wide contact tab to optionally generate project issues instead of emails.
+dependencies[] = contact
+dependencies[] = project_issue
+package = Project
+core = 6.x
Index: contact/project_issue_contact.module
===================================================================
--- contact/project_issue_contact.module	(revision 0)
+++ contact/project_issue_contact.module	(revision 0)
@@ -0,0 +1,245 @@
+<?php
+// $Id$
+// $Name$
+
+/**
+ * @file Integrates Project issue tracking with the core Contact
+ * module so that the site-wide contact tab can be optionally
+ * configured to create new project issues instead of sending email.
+ *
+ * @todo Need to do something reasonable about permissions.
+ *
+ * @todo All the validation hooks need to be written.
+ *
+ * @todo The admin UI still needs lots of work.  Currently, it's a 3 step
+ *   process if you want to add an issue queue for a contact tab.
+ *
+ * @todo Core's contact.module makes this difficult:
+ *   - auto_increment/serial cid means we can't set issue when we add
+ *   - core validate/submit handler assumes email is required
+ *
+ * @todo Do something intelligent with the name/email fields for
+ *   anonymous users? Perhaps we should maintain a table to store that
+ *   info and associate with the node, then have a hook_nodeapi() in
+ *   here to somehow display at least the name (and for site admins,
+ *   the email or something?
+ * @todo Replace arg(X) handling with parameters.
+ */
+
+/**
+ * Implementation of hook_form_alter().
+ * Calls the appropriate form-specific alter method depending on form_id.
+ *
+ * @todo: Use hook_form_FORM_ID_alter() for this.
+ */
+function project_issue_contact_form_alter(&$form, $form_state, $form_id) {
+  switch ($form_id) {
+    case 'contact_admin_edit':
+      return project_issue_contact_alter_admin_form($form_id, $form);
+    case 'contact_admin_delete':
+      return project_issue_contact_alter_delete_form($form_id, $form);
+    case 'contact_mail_page':
+      return project_issue_contact_alter_mail_page_form($form_id, $form);
+  }
+}
+
+/**
+ * Alter the admin form for adding or editing contact tab categories.
+ *
+ * Adds optional settings to send the information into an issue queue,
+ * not just to the email recipients. 
+ */
+function project_issue_contact_alter_admin_form($form_id, &$form) {
+  $form['issues'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Issue queue integration'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  if (arg(3) == "edit" && ($cid = arg(4)) && $cid > 0) {
+    $defaults = db_fetch_array(db_query("SELECT * FROM {project_issue_contact} WHERE cid = %d", $cid));
+    $default_state = variable_get('project_issue_default_state', 1);
+    $uris = NULL;
+    $projects = array(t('<none>')) + project_projects_select_options($uris);
+    if (isset($defaults['pid'])) {
+      $project = node_load(array('nid' => $defaults['pid'], 'type' => 'project_project'));
+    }
+    $components = array();
+    if (!empty($project->components)) {
+      $components = array(t('<none>'));
+      foreach ($project->components as $component) {
+        $component = check_plain($component);
+        $components[$component] = $component;
+      }
+    }
+    if (module_exists('project_release') && isset($project) &&
+        $releases = project_release_get_releases($project, 0)) {
+      $releases = array(t('<none>')) + $releases;
+    }
+    $categories = array_merge(array(t('<none>')), project_issue_category(0, 0));
+    $priorities = project_issue_priority();
+    $states = project_issue_state();
+
+    // Add the appropriate description to the fieldset. Since we're
+    // editing an existing contact category, the issue settings are valid.
+    $form['issues']['#description'] = t('Optionally define an issue queue where issues should be created whenever a user submits a contact form for this category. If the %project setting is set to %none, no issue will be generated and the other settings are ignored. However, if you select a %project, the other settings determine the values to use the corresponding fields in the issue creation form when users use this contact category.', array('%project' => t('Project'), '%none' => t('<none>')));
+
+    $form['issues']['pid'] = array(
+      '#type' => 'select',
+      '#title' => t('Project'),
+      '#default_value' => isset($defaults['pid']) ? $defaults['pid'] : 0,
+      '#options' => $projects,
+    );
+    if (!empty($components)) {
+      $form['issues']['component'] = array(
+        '#type' => 'select',
+        '#title' => t('Component'),
+        '#default_value' => isset($defaults['component']) ? $defaults['component'] : 0,
+        '#options' => $components,
+      );
+    }
+    if (!empty($releases)) {
+      $form['issues']['rid'] = array(
+        '#type' => 'select',
+        '#title' => t('Version'),
+        '#default_value' => isset($defaults['rid']) ? $defaults['rid'] : 0,
+        '#options' => $releases,
+      );
+    }
+    $form['issues']['issue_category'] = array(
+      '#type' => 'select',
+      '#title' => t('Issue category'),
+      '#default_value' => isset($defaults['category']) ? $defaults['category'] : 'support',
+      '#options' => $categories,
+    );
+    $form['issues']['priority'] = array(
+      '#type' => 'select',
+      '#title' => t('Priority'),
+      '#default_value' => isset($defaults['priority']) ? $defaults['priority'] : 2,
+      '#options' => $priorities,
+    );
+    if (count($states) > 1) {
+      $form['issues']['sid'] = array(
+        '#type' => 'select',
+        '#title' => t('Status'),
+        '#default_value' => isset($defaults['sid']) ? $defaults['sid'] : $default_state,
+        '#options' => $states,
+      );
+    }
+    else {
+      $form['issues']['sid'] = array(
+        '#type' => 'hidden',
+        '#value' => $default_state,
+      );
+      $form['issues']['status'] = array(
+        '#type' => 'item',
+        '#title' => t('Status'),
+        '#value' => project_issue_state($default_state),
+      );
+    }
+    $form['#validate'][] = 'project_issue_contact_admin_edit_validate';
+    $form['#submit'][] = 'project_issue_contact_admin_edit_submit';
+  }
+  else {
+    // Add the appropriate description to the fieldset. Since we're
+    // not going to know the cid until the category is added, we
+    // currently don't present any of the settings on the add form.
+    /// @todo This is lame!
+    $form['issues']['#description'] = t('You can only configure issue queue integration once you have created the contact tab initially. After submitting this form, you can click on the %edit link and new settings will be present here.', array('%edit' => t('edit')));
+  }
+  $form['submit']['#weight'] = 10;
+}
+
+/**
+ * Validation handler for contact admin form.
+ *
+ * @todo !!!
+ *
+ */
+function project_issue_contact_admin_edit_validate($form, &$form_state) {
+}
+
+/**
+ * Submit handler for contact admin form. Deletes, updates, or inserts
+ * records into the {project_issue_contact} table as approriate.
+ */
+function project_issue_contact_admin_edit_submit($form, &$form_state) {
+  if ($form_state['values']['pid'] == 0) {
+    db_query("DELETE FROM {project_issue_contact} WHERE cid = %d", $form_state['values']['cid']);
+  }
+  // @todo: Do the D7 equivalent here. COUNT(*) sucks on InnoDB.
+  else  if (arg(3) != 'add' && db_result(db_query("SELECT COUNT(*) from {project_issue_contact} WHERE cid = %d", $form_state['values']['cid'])))) {
+    db_query("UPDATE {project_issue_contact} SET pid = %d, rid = %d, category = '%s', component = '%s', priority = %d, sid = %d WHERE cid = %d", $form_state['values']['pid'], $form_state['values']['rid'], $form_state['values']['issue_category'], $form_state['values']['component'], $form_state['values']['priority'], $form_state['values']['sid'], $form_state['values']['cid']);
+    drupal_set_message(t('Category %category issue queue settings modified.', array('%category' => $form_state['values']['category'])));
+  }
+  else if (!empty($form_state['values']['cid'])) {
+    db_query("INSERT INTO {project_issue_contact} (cid, pid, rid, category, component, priority, sid) VALUES (%d, %d, %d, '%s', '%s', %d, %d)", $form_state['values']['cid'], $form_state['values']['pid'], $form_state['values']['rid'], $form_state['values']['issue_category'], $form_state['values']['component'], $form_state['values']['priority'], $form_state['values']['sid']);
+    drupal_set_message(t('Category %category configured to create issues when users fill out the contact form.', array('%category' => $form_state['values']['category'])));
+  }
+}
+
+
+/**
+ * Alters the confirmation form for deleting a contact tab to add
+ * another submit handler.
+ */
+function project_issue_contact_alter_delete_form($form_id, &$form) {
+  $form['#submit'][] = 'project_issue_contact_delete_submit';
+}
+
+/**
+ * Submit handler for contact tab delete form that cleans out the
+ * appropriate record from the {project_issue_contact} table.
+ */
+function project_issue_contact_delete_submit($form, &$form_state) {
+  db_query("DELETE FROM {project_issue_contact} WHERE cid = %d", arg(4));
+}
+
+function project_issue_contact_alter_mail_page_form($form_id, &$form) {
+  // for debugging only
+  unset($form['#submit']);
+  $form['#submit'][] = 'project_issue_contact_mail_page_form_submit';
+}
+
+function project_issue_contact_mail_page_form_submit($form, &$form_state) {
+  $project_issue_contact_values = db_fetch_array(db_query("SELECT * FROM {project_issue_contact} WHERE cid = %d", $form_state['values']['cid']));
+  global $user;
+
+  $node->type = 'project_issue';
+  $node->uid = $user->uid;
+  $node->title = $form_state['values']['subject'];
+  $node->body = $form_state['values']['message'];
+  $node->teaser = node_teaser($node->body);
+  $node->filter = variable_get('filter_default_format', 1);
+  $node->status = 1;
+
+  foreach (array('pid', 'rid', 'category', 'component', 'priority', 'sid') as $field) {
+    $node->$field = $project_issue_contact_values[$field];
+  }
+
+  /// @todo : store name/email somewhere reasonable for anon contacts?
+
+  node_save($node);
+  if (node_access('view', $node)) {
+    drupal_set_message(t('Your message has been recorded into !issue_link', array('!issue_link' => l('this issue', 'node/' . $node->nid))));
+  }
+  else {
+    drupal_set_message(t('Your message has been recorded on the site'));
+  }
+}
+
+/*
+// TODO: maybe we need this (or something like it) if we want to support
+// adding issue queue stuff when we first add contact tab categories. :(
+function project_issue_contact_get_last_cid() {
+ switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      return mysql_insert_id();
+    case 'pgsql:
+      return db_result(db_query("SELECT currval {contact}_cid_seq"));
+  }
+  return 0;
+}
+*/
+
Index: contact/project_issue_contact.install
===================================================================
--- contact/project_issue_contact.install	(revision 0)
+++ contact/project_issue_contact.install	(revision 0)
@@ -0,0 +1,74 @@
+<?php
+// $Id$
+// $Name$
+
+fuction project_issue_contact_schema() {
+  $schema['project_issue_contact'] = array(
+    'description' => t('TODO: please describe this table!'),
+    'fields' => array(
+      'cid' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'pid' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'category' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'component' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'priority' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sid' => array(
+        'description' => t('TODO: please describe this field!'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('cid'),
+  );
+
+  return $schema;
+}
+
+function project_issue_contact_install() {
+  drupal_install_schema('project_issue_contact');
+  db_query("UPDATE {system} SET weight = 2 WHERE name = 'pi_contact'");
+}
+
+
+function project_issue_contact_uninstall() {
+  drupal_uninstall_schema('project_issue_contact');
+}
\ No newline at end of file
