Index: modules/project/comment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/comment.inc,v
retrieving revision 1.42
diff -u -r1.42 comment.inc
--- modules/project/comment.inc	17 May 2005 06:21:20 -0000	1.42
+++ modules/project/comment.inc	26 May 2005 06:44:46 -0000
@@ -7,7 +7,7 @@
       if (user_access('create project issues')) {
         $node = node_load(array('nid' => arg(3), 'type' => 'project_issue'));
 
-        foreach (array('nid', 'type', 'pid', 'rid', 'category', 'component', 'priority', 'assigned', 'state', 'title') as $var) {
+        foreach (array('nid', 'type', 'pid', 'rid', 'category', 'component', 'priority', 'assigned', 'sid', 'title') as $var) {
           $comment->$var = $node->$var;
         }
 
@@ -103,7 +103,7 @@
     'category' => 'Category',
     'priority' => 'Priority',
     'assigned' => 'Assigned to',
-    'state' => 'Status'
+    'sid' => 'Status'
   );
 
   $result = db_query('SELECT p.*, u.name FROM {project_comments} p INNER JOIN {users} u USING (uid) WHERE p.nid = %d ORDER BY p.created ASC', $node->nid);
@@ -168,7 +168,7 @@
     $node = node_load(array('nid' => $edit->nid, 'type' => 'project_issue'));
 
     // Check if comment changed any of the state values and update the node if necessary
-    foreach (array('pid', 'rid', 'category', 'component', 'priority', 'assigned', 'state', 'title') as $var) {
+    foreach (array('pid', 'rid', 'category', 'component', 'priority', 'assigned', 'sid', 'title') as $var) {
       if ($node->$var != $edit->$var) {
         $data['old']->$var = $node->$var;
         $data['new']->$var = $edit->$var;
Index: modules/project/issue.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/issue.inc,v
retrieving revision 1.102
diff -u -r1.102 issue.inc
--- modules/project/issue.inc	17 May 2005 06:21:20 -0000	1.102
+++ modules/project/issue.inc	26 May 2005 06:33:09 -0000
@@ -5,6 +5,16 @@
   return t('issue');
 }
 
+function project_issue_nodeapi(&$node, $op, $arg) {
+  switch ($op) {
+    case 'validate':
+      if (!user_access("set issue status '" . $node->sid . "'")) {
+        form_set_error('sid', t('Invalid issue status %status: you do not have permission to set this status', array('%status' => "<em>$node->sid</em>")));
+      }
+      break;
+  }
+}
+
 function project_issue_page() {
   switch ($_POST['op'] ? $_POST['op'] : arg(2)) {
     case 'search':
@@ -95,14 +105,14 @@
   $header = array(t('Category'), t('Overall'), t('Last month'));
   $rows = array();
   $duration = time() - 30 * 24 * 60 * 60;
-  $result = db_query('SELECT p.category, SUM(n.changed - n.created) / COUNT(p.category) AS duration FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND p.state > 1 GROUP BY p.category', $filter);
+  $result = db_query('SELECT p.category, SUM(n.changed - n.created) / COUNT(p.category) AS duration FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND p.sid > 1 GROUP BY p.category', $filter);
   while ($stat = db_fetch_object($result)) {
     $i++;
     $rows[$i][0] = project_issue_category($stat->category);;
     $rows[$i][1] = array('data' => format_interval($stat->duration, 2), 'class' => 'numeric');
   }
 
-  $result = db_query('SELECT p.category, SUM(n.changed - n.created) / COUNT(p.category) AS duration FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND p.state > 1 AND n.created > %d GROUP BY p.category', $filter, $duration);
+  $result = db_query('SELECT p.category, SUM(n.changed - n.created) / COUNT(p.category) AS duration FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND p.sid > 1 AND n.created > %d GROUP BY p.category', $filter, $duration);
   while ($stat = db_fetch_object($result)) {
     $j++;
     $rows[$j][2] = array('data' => format_interval($stat->duration, 2), 'class' => 'numeric');
@@ -114,16 +124,16 @@
   $rows = array();
   // Activity overall
   $total = db_result(db_query(db_rewrite_sql('SELECT COUNT(n.nid) AS total FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s'), $filter));
-  $result = db_query(db_rewrite_sql('SELECT COUNT(n.nid) AS total, p.state FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s GROUP BY p.state'), $filter);
+  $result = db_query(db_rewrite_sql('SELECT COUNT(n.nid) AS total, p.sid FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s GROUP BY p.sid'), $filter);
   while ($stat = db_fetch_object($result)) {
-    $rows[$stat->state][0] = project_issue_state($stat->state);;
-    $rows[$stat->state][1] = array('data' => $stat->total, 'class' => 'project-numeric');
-    $rows[$stat->state][2] = array('data' => number_format($stat->total / $total * 100) .'%', 'class' => 'project-numeric2');
+    $rows[$stat->sid][0] = project_issue_state($stat->sid);;
+    $rows[$stat->sid][1] = array('data' => $stat->total, 'class' => 'project-numeric');
+    $rows[$stat->sid][2] = array('data' => number_format($stat->total / $total * 100) .'%', 'class' => 'project-numeric2');
   }
   // Activity this week
-  $result = db_query(db_rewrite_sql('SELECT COUNT(n.nid) AS total, p.state FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND n.changed > %d GROUP BY p.state'), $filter, $duration);
+  $result = db_query(db_rewrite_sql('SELECT COUNT(n.nid) AS total, p.sid FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1%s AND n.changed > %d GROUP BY p.sid'), $filter, $duration);
   while ($stat = db_fetch_object($result)) {
-    $rows[$stat->state][3] = array('data' => $stat->total, 'class' => 'project-numeric');
+    $rows[$stat->sid][3] = array('data' => $stat->total, 'class' => 'project-numeric');
   }
   $output .= '<h2>'. t('Issue activity') .'</h2>';
   $output .= theme('table', $header, $rows);
@@ -132,7 +142,7 @@
   if (!$project->nid) {
     $header = array_merge(array(t('Project')), project_issue_state(), array(t('Total')));
     $rows = array();
-    $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, p.state, COUNT(p.nid) AS total FROM {node} n INNER JOIN {project_issues} p ON n.nid = p.pid WHERE n.type = 'project_project' AND n.status = 1 GROUP BY n.nid, p.state, n.title"));
+    $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, p.sid, COUNT(p.nid) AS total FROM {node} n INNER JOIN {project_issues} p ON n.nid = p.pid WHERE n.type = 'project_project' AND n.status = 1 GROUP BY n.nid, p.sid, n.title"));
 
     $orig = array('project' => array('data' => 0));
     foreach (project_issue_state() as $key => $value) {
@@ -146,7 +156,7 @@
         $rows[$stat->nid]['project']['data'] = l($stat->title, "node/$stat->nid");
       }
       $rows[$stat->nid]['total']['data'] += $stat->total;
-      $rows[$stat->nid][$stat->state]['data'] = $stat->total;
+      $rows[$stat->nid][$stat->sid]['data'] = $stat->total;
     }
     usort($rows, create_function('$a,$b', 'return $a[1]["data"] < $b[1]["data"];'));
     $output .= '<h2>'. t('Project overview') .'</h2>';
@@ -255,7 +265,7 @@
     }
     $categories = array_merge(array(t('<none>')), project_issue_category(0, 0));
     $priorities = project_issue_priority();
-    $states = project_issue_state();
+    $states = project_issue_state(0, true);
 
     if ($user->uid == $node->assigned) {
       $assigned = array(0 => t('Unassign'), $user->uid => $user->name);
@@ -276,7 +286,7 @@
     $group2 = form_select(t('Category'), 'category', $node->category, $categories, NULL, 0, FALSE, TRUE);
     $group2 .= form_select(t('Priority'), 'priority', $node->priority, $priorities);
     $group2 .= form_select(t('Assigned'), 'assigned', $node->assigned, $assigned);
-    $group2 .= form_select(t('Status'), 'state', $node->state, $states);
+    $group2 .= form_select(t('Status'), 'sid', $node->sid, $states);
 
     $output .= '</div>';
     $output .= '<div class="admin">';
@@ -325,7 +335,7 @@
       }
       empty($node->priority) and $node->priority = 2;
       empty($node->category) and $node->category = arg(4);
-      empty($node->state) and $node->state = 1;
+      empty($node->sid) and $node->sid = 1;
 
       if (isset($node->title)) {
         empty($node->component) and form_set_error($error['component'], t('You have to specify a valid component.'));
@@ -369,7 +379,7 @@
     $rows[] = array(t('Category:'), check_plain($node->category));
     $rows[] = array(t('Priority:'), project_issue_priority($node->priority));
     $rows[] = array(t('Assigned:'), $assigned);
-    $rows[] = array(t('Status:'), project_issue_state($node->state));
+    $rows[] = array(t('Status:'), project_issue_state($node->sid));
     if ($node->file_path && file_exists($node->file_path)) {
       $rows[] = array(t('Attachment:'), '<a href="'. file_create_url($node->file_path). '">'. basename($node->file_path) .'</a> ('. format_size($node->file_size) .')');
     }
@@ -405,7 +415,7 @@
     $file = file_save_upload($node->file, variable_get('project_directory_issues', 'issues'));
   }
 
-  db_query("INSERT INTO {project_issues} (nid, pid, category, component, priority, rid, assigned, state, file_path, file_mime, file_size) VALUES (%d, %d, '%s', '%s', %d, %d, %d, %d, '%s', '%s', %d)", $node->nid, $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->state, $file->filepath, $file->filemime, $file->filesize);
+  db_query("INSERT INTO {project_issues} (nid, pid, category, component, priority, rid, assigned, sid, file_path, file_mime, file_size) VALUES (%d, %d, '%s', '%s', %d, %d, %d, %d, '%s', '%s', %d)", $node->nid, $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->sid, $file->filepath, $file->filemime, $file->filesize);
   project_mail_notify($node);
 }
 
@@ -414,10 +424,10 @@
     // Remove old file.
     file_delete(db_result(db_query('SELECT file_path FROM {project_issues} WHERE nid = %d', $node->nid)));
     $file = file_save_upload($node->file, variable_get('project_directory_issues', 'issues'));
-    db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, state = %d, file_path = '%s', file_mime = '%s', file_size = %d WHERE nid = %d", $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->state, $file->filepath, $file->filemime, $file->filesize, $node->nid);
+    db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, sid = %d, file_path = '%s', file_mime = '%s', file_size = %d WHERE nid = %d", $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->sid, $file->filepath, $file->filemime, $file->filesize, $node->nid);
   }
   else {
-    db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, state = %d WHERE nid = %d", $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->state, $node->nid);
+    db_query("UPDATE {project_issues} SET pid = %d, category = '%s', component = '%s', priority = %d, rid = %d, assigned = %d, sid = %d WHERE nid = %d", $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->sid, $node->nid);
   }
   project_mail_notify($node);
 }
@@ -440,9 +450,28 @@
 }
 
 // Support stuff
-function project_issue_state($state = 0) {
-  $states = array(1 => t('active'), 2 => t('fixed'), 8=> t('patch'), 3 => t('duplicate'), 4 => t('postponed'), 5 => t("won't fix"), 6 => t('by design'), 7 => t('closed'));
-  return $state ? $states[$state] : $states;
+function project_issue_state($sid = 0, $restrict = false) {
+  static $options;
+
+  if (!$options) {
+    $result = db_query('SELECT * FROM {project_issue_state} ORDER BY weight');
+    while ($stat = db_fetch_object($result)) {
+      $options[$stat->sid] = $stat->name;
+    }
+  }
+
+  if($restrict) {
+    foreach($options as $key => $value) {
+      if (user_access("set issue status '" . $value . "'")) {
+        $states[$key] = $value;
+      }
+    }
+  }
+  else {
+    $states = $options;
+  }
+
+  return $sid ? $states[$sid] : $states;
 }
 
 function project_issue_priority($priority = 0) {
@@ -462,9 +491,9 @@
 
 function project_issue_count($pid) {
   $state = array();
-  $result = db_query('SELECT p.state, count(p.state) AS count FROM {node} n INNER JOIN {project_issues} p ON n.nid = p.nid WHERE n.status = 1 AND p.pid = %d GROUP BY p.state', $pid);
+  $result = db_query('SELECT p.sid, count(p.sid) AS count FROM {node} n INNER JOIN {project_issues} p ON n.nid = p.nid WHERE n.status = 1 AND p.pid = %d GROUP BY p.sid', $pid);
   while ($data = db_fetch_object($result)) {
-    $state[$data->state] = $data->count;
+    $state[$data->sid] = $data->count;
   }
   return $state;
 }
@@ -529,6 +558,111 @@
   return $output;
 }
 
+function project_issue_admin_states() {
+  $result = db_query('SELECT * FROM {project_issue_state} ORDER BY weight');
+
+  while ($state = db_fetch_object($result)) {
+    $rows[] = array($state->sid, form_textfield(NULL, 'status][' . $state->sid .'][name', $state->name, 64, 255), form_weight(NULL, 'status][' . $state->sid .'][weight', $state->weight, 15), l(t('delete'), 'project/issues/status_settings/delete/'. $state->sid));
+  }
+  for ($i = 0; $i < 3; $i++) {
+    $rows[] = array(NULL, form_textfield(NULL, 'status_add][' . $i . '][name', '', 64, 255), form_weight(NULL, 'status_add][' . $i .'][weight', 0, 15), NULL);
+  }
+  return $rows;
+}
+
+function project_issue_admin_states_page() {
+  switch ($_POST['edit']['op'] ? $_POST['edit']['op'] : arg(3)) {
+    case 'save':
+      project_issue_admin_save_states();
+      break;
+    case 'delete':
+      project_issue_admin_delete_state();
+      break;
+    default:
+      $header = array(
+        array('data' => t('ID')),
+        array('data' => t('Name')),
+        array('data' => t('Weight'), 'colspan' => 2)
+      );
+    
+      $output = '<div>' . theme('table', $header, project_issue_admin_states()) . '</div>';
+      $output .= form_hidden('op', 'save');
+      $output .= form_submit(t('Save issue settings'));
+    
+      $output = form($output);
+    
+      $output .= l('Project settings', 'admin/settings/project');
+      print theme('page', $output);
+      break;
+  }      
+}
+
+function project_issue_admin_save_states() {
+  // Check for and apply changes or additions to project issue status options.
+  $edit = $_POST['edit'];
+  // Update existing status options.
+  if($edit['status']) {
+    foreach ($edit['status'] as $sid => $value) {
+      $state = db_fetch_object(db_query('SELECT name, weight FROM {project_issue_state} WHERE sid = %d', $sid));
+      // Check to see whether the name needs updating:
+      if ($state->name != $value['name']) {
+        db_query("UPDATE {project_issue_state} SET name = '%s' WHERE sid = %d", $value['name'], $sid);
+      }
+  
+      // Check to see whether the weight needs updating:
+      if ($state->weight != $value['weight']) {
+        db_query('UPDATE {project_issue_state} SET weight = %d WHERE sid = %d', $value['weight'], $sid);
+      }
+    }
+  }
+  // Add any new status options.
+  if($edit['status_add']) {
+    foreach ($edit['status_add'] as $i => $value) {
+      if($value['name']) {
+        // Check to see whether the state already exists:
+        $name = db_result(db_query("SELECT name FROM {project_issue_state} WHERE name = '%s'", $value['name']));
+        if (!db_num_rows($name)) {
+          db_query("INSERT INTO {project_issue_state} SET name = '%s', weight = %d", $value['name'], $value['weight']);
+        }
+      }
+    }
+  }
+  drupal_goto('project/issues/status_settings');
+}
+
+function project_issue_admin_delete_state() {
+  $sid = arg(4);
+  $edit = $_POST['edit'];
+  if (!$sid) {
+    $sid = $edit['sid'];
+  }
+  $states = project_issue_state();
+  $name = $states[$sid];
+  if ($edit['confirm'] && ($edit['new_sid'] != $sid)) {
+    if ($edit['new_sid']) {
+      db_query('UPDATE {project_issues} SET sid = %d WHERE sid = %d', $edit['new_sid'], $sid);
+    }
+    db_query('DELETE FROM {project_issue_state} WHERE sid = %d', $sid);
+    drupal_set_message(t('Project issue status %issue deleted.', array('%issue' => $name)));
+    drupal_goto('project/issues/status_settings');
+  }
+  else {
+    if($edit['new_sid'] == $sid) {
+      form_set_error('new_sid', t('Choose a new issue status for existing issues of status %name.', array('%name' => $name)));
+    }
+    $total = db_result(db_query(db_rewrite_sql('SELECT COUNT(nid) AS total FROM {project_issues} WHERE sid = %d'), $sid));
+    if ($total > 0) {
+      $output .= form_select(t('Reassign status'), 'new_sid', $sid, $states, t('There are %total existing issues with the status of %name. Please select a new status for these issues.', array('%total' => $total, '%name' => $name)));
+    }
+    $output .= form_item(t('Confirm deletion'), $name);
+    $output .= form_hidden('sid', $sid);
+    $output .= form_hidden('confirm', 1);
+    $output .= form_submit(t('Delete'));
+    $output = form($output);
+    print theme('page', $output);
+  }
+}
+
 function project_issue_query_result($query = NULL, $format = 'html', $search = true) {
   $query = project_issue_query_parse($query);
 
@@ -569,7 +703,7 @@
     $header[] = array('data' => t('Project'), 'field' => 'p.pid');
   }
   $header[] = array('data' => t('Summary'), 'field' => 'n.title');
-  $header[] = array('data' => t('Status'), 'field' => 'p.state');
+  $header[] = array('data' => t('Status'), 'field' => 'p.sid');
   $header[] = array('data' => t('Pri'), 'field' => 'p.priority');
   $header[] = array('data' => t('Category'), 'field' => 'p.category');
   if (count($releases)) {
@@ -584,7 +718,7 @@
     $result = pager_query(db_rewrite_sql($sql['sql'] . tablesort_sql($header)), 20, 0, $sql['count']);
   }
   else {
-    $result = pager_query(db_rewrite_sql('SELECT p.nid FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid INNER JOIN {users} u ON p.assigned = u.uid INNER JOIN {node} np ON np.nid = p.pid WHERE n.status = 1 AND ('. implode(' OR ', $pids) .') AND (p.state = 1 OR p.state = 2)'. tablesort_sql($header), 'p'), 20);
+    $result = pager_query(db_rewrite_sql('SELECT p.nid FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid INNER JOIN {users} u ON p.assigned = u.uid INNER JOIN {node} np ON np.nid = p.pid WHERE n.status = 1 AND ('. implode(' OR ', $pids) .') AND (p.sid = 1 OR p.sid = 2)'. tablesort_sql($header), 'p'), 20);
   }
 
   if ($search) {
@@ -627,12 +761,12 @@
       $node = node_load($node);
       $row = array();
       $number++;
-      $class = 'state_'. ($number % 2 ? 'light' : 'dark') ."_$node->state";
+      $class = 'state_'. ($number % 2 ? 'light' : 'dark') ."_$node->sid";
       if (!$project->nid) {
         $row[] = l($projects[$node->pid], "project/issues/$node->pid");
       }
       $row[] = l(substr($node->title, 0, 50), "node/$node->nid") .  theme('mark', node_mark($node->nid, $node->changed));
-      $row[] = $states[$node->state];
+      $row[] = $states[$node->sid];
       $row[] = $priorities[$node->priority];
       $row[] = t($node->category);
       if (count($releases)) {
@@ -764,7 +898,7 @@
         $sql[] = project_issue_query_sql_field('p.rid', $value);
         break;
       case 'states':
-        $sql[] = project_issue_query_sql_field('p.state', $value);
+        $sql[] = project_issue_query_sql_field('p.sid', $value);
         break;
       case 'priorities':
         $sql[] = project_issue_query_sql_field('p.priority', $value);
Index: modules/project/mail.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/mail.inc,v
retrieving revision 1.48
diff -u -r1.48 mail.inc
--- modules/project/mail.inc	26 May 2005 01:56:21 -0000	1.48
+++ modules/project/mail.inc	26 May 2005 06:46:42 -0000
@@ -22,7 +22,7 @@
         'priority' => t('Priority'),
         'rid' => t('Version'),
         'assigned' => t('Assigned to'),
-        'state' => t('Status')
+        'sid' => t('Status')
       );
 
       /*
@@ -68,9 +68,9 @@
                 $entry->assigned = $user->uid;
               }
               break;
-            case 'state':
+            case 'sid':
               if (($state = array_search($node->$text, project_issue_state()))) {
-                $entry->state = $state;
+                $entry->sid = $state;
               }
               break;
             case 'component':
@@ -85,7 +85,7 @@
       }
 
       if (empty($entry->nid)) {
-        $entry->state = 1;
+        $entry->sid = 1;
         $entry->type = 'project_issue';
         $entry = node_validate($entry, $error);
         $error or ($entry->nid = node_save($entry));
@@ -179,7 +179,7 @@
     case 'assigned':
       $user = user_load(array('uid' => $value));
       return $user->name;
-    case 'state':
+    case 'sid':
       return $value ? project_issue_state($value) : t('<none>');
     default:
       return $value;
@@ -202,7 +202,7 @@
     'assigned' => t('Assigned to'),
     'name' => t('Reported by'),
     'updator' => t('Updated by'),
-    'state' => t('Status')
+    'sid' => t('Status')
   );
 
   // Create complete history of the bug report
@@ -323,7 +323,7 @@
     return;
   }
 
-  if (count($project->mail_copy_filter_state) && !$project->mail_copy_filter_state[$node->state]) {
+  if (count($project->mail_copy_filter_state) && !$project->mail_copy_filter_state[$node->sid]) {
     return;
   }
 
@@ -344,7 +344,7 @@
     $sender->name = variable_get('site_name', '');
     $sender->mail = variable_get('site_mail', '');
 
-    $result = db_query(db_rewrite_sql('SELECT p.nid, n.*, p.*, u.name, u.mail FROM {project_issues} p INNER JOIN {node} n ON p.nid = n.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.status = 1 AND u.status = 1 AND ('. implode(' OR ', $pids) .") AND u.mail <> '' AND (p.state = 1 OR p.state = 2) ORDER BY u.uid, p.pid, p.component, p.state, n.changed DESC", 'p'));
+    $result = db_query(db_rewrite_sql('SELECT p.nid, n.*, p.*, u.name, u.mail FROM {project_issues} p INNER JOIN {node} n ON p.nid = n.nid INNER JOIN {users} u ON n.uid = u.uid WHERE n.status = 1 AND u.status = 1 AND ('. implode(' OR ', $pids) .") AND u.mail <> '' AND (p.sid = 1 OR p.sid = 2) ORDER BY u.uid, p.pid, p.component, p.sid, n.changed DESC", 'p'));
 
     while (($node = db_fetch_object($result)) || !empty($body)) {
       if ($body && $mail && ((!$node) || ($mail != $node->mail))) {
@@ -374,7 +374,7 @@
         if ($node->assigned && $assigned = user_load(array('uid' => $node->assigned))) {
           $body .= "  assigned: $assigned->name\n";
         }
-        $body .= '  state: '. project_issue_state($node->state) ."\n";
+        $body .= '  state: '. project_issue_state($node->sid) ."\n";
         $body .= '  age: '. format_interval(time() - $node->created) ."\n";
         $body .= '  url: '. url("node/$node->nid", NULL, NULL, 1) ."\n";
         $body .= "\n";
@@ -395,7 +395,7 @@
   $result = db_query(db_rewrite_sql("SELECT p.nid, p.* FROM {project_projects} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1 AND p.mail_digest <> '' ORDER BY title, p.mail_digest", 'p'));
   while ($project = db_fetch_object($result)) {
     $category = '';
-    $result2 = db_query(db_rewrite_sql('SELECT p.nid, n.title, n.created, p.state, p.category, p.component, p.priority, p.assigned FROM {project_issues} p INNER JOIN {node} n ON p.nid = n.nid WHERE n.status = 1 AND p.pid = %d AND p.state = 1 AND p.priority = 1 ORDER BY p.category, n.created DESC', 'p'), $project->nid);
+    $result2 = db_query(db_rewrite_sql('SELECT p.nid, n.title, n.created, p.sid, p.category, p.component, p.priority, p.assigned FROM {project_issues} p INNER JOIN {node} n ON p.nid = n.nid WHERE n.status = 1 AND p.pid = %d AND p.sid = 1 AND p.priority = 1 ORDER BY p.category, n.created DESC', 'p'), $project->nid);
     while ($node = db_fetch_object($result2)) {
       if ($category != $node->category) {
         $category = $node->category;
Index: modules/project/project.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.module,v
retrieving revision 1.195
diff -u -r1.195 project.module
--- modules/project/project.module	24 May 2005 20:38:45 -0000	1.195
+++ modules/project/project.module	26 May 2005 07:09:27 -0000
@@ -40,6 +40,13 @@
       return t('Add a new issue (bug report, feature request, etc) to an existing project.');
     case 'node/add/project_project':
       return variable_get('project_help_node_add', '');
+    case 'project/issues/status_settings':
+      return t('<p>Use this page to add new status options for project issues or to change or delete existing options.<dl>
+      <dt>Adding</dt><dd>To add a new status option, put its name in one of the blank places at the bottom of the form and assign it a weight.</dd></p>
+      <dt>Updating</dt><dd>When renaming existing issues, keep in mind that issues with the existing name will receive the new one.</dd>
+      <dt>Deleting</dt><dd>If you delete an existing issue status, you will be prompted for a new status to assign to existing issues with the deleted status.</dd>
+      <dt>Weights</dt><dd>The weight of an issue determines the order it appears in lists, like in the select box where users designate a status for their issue.</dd>
+      </dl></p>');
   }
 }
 
@@ -52,7 +59,7 @@
 }
 
 function project_perm() {
-  return array(
+  $perms = array(
     'administer projects',
     'maintain projects',
     'access projects',
@@ -61,9 +68,15 @@
     'access project issues',
     'access own project issues'
   );
+  $states = project_issue_state();
+  foreach($states as $key => $value) {
+    $perms[] = "set issue status '" . $value . "'";
+  }
+  return $perms;
 }
 
 function project_settings() {
+
   if (!file_check_directory(file_create_path(variable_get('project_directory_issues', 'issues')))) {
     $error['project_directory_issues'] = theme('error', t('Directory does not exist, or is not writable.'));
   }
@@ -87,6 +100,8 @@
     $output .= form_select(t('Reply-to address on e-mail notifications'), 'project_reply_to', variable_get('project_reply_to', ''), $items);
   }
 
+  $output .= '<div>' . l('Administer project issue status settings', 'project/issues/status_settings') . '</div>';
+
   return $output;
 }
 
@@ -106,9 +121,9 @@
     project_mail_reminder();
   }
 
-  $result = db_query(db_rewrite_sql('SELECT p.nid, p.pid, p.category, p.component, p.priority, p.assigned, p.state, n.title FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1 AND p.state = 2 AND n.changed < %d', 'p'), time() - 14 * 24 * 60 * 60);
+  $result = db_query(db_rewrite_sql('SELECT p.nid, p.pid, p.category, p.component, p.priority, p.assigned, p.sid, n.title FROM {project_issues} p INNER JOIN {node} n ON n.nid = p.nid WHERE n.status = 1 AND p.sid = 2 AND n.changed < %d', 'p'), time() - 14 * 24 * 60 * 60);
   while ($node = db_fetch_object($result)) {
-    foreach (array('nid', 'pid', 'category', 'component', 'priority', 'assigned', 'state', 'title') as $var) {
+    foreach (array('nid', 'pid', 'category', 'component', 'priority', 'assigned', 'sid', 'title') as $var) {
       $comment->$var = $node->$var;
     }
     $comment->state = 7;
@@ -209,7 +224,14 @@
     $access = user_access('create project issues');
     $items[] = array('path' => 'node/add/project_issue', 'title' => t('issue'), 'callback' => 'node_page', 'access' => $access, 'type' => MENU_NORMAL_ITEM, 'weight' => 1);
 
+    // Administer issue status settings
+    $access = user_access('administer projects');
+    $items[] = array('path' => 'project/issues/status_settings', 'title' => t('status options'), 'callback' => 'project_issue_admin_states_page', 'access' => $access, 'type' => MENU_NORMAL_ITEM);
+    $items[] = array('path' => 'project/issues/status_settings/save', 'title' => t('save'), 'callback' => 'project_issue_admin_states_page', 'access' => $access, 'type' => MENU_CALLBACK);
+    $items[] = array('path' => 'project/issues/status_settings/delete', 'title' => t('delete'), 'callback' => 'project_issue_admin_states_page', 'access' => $access, 'type' => MENU_CALLBACK);
+
     // Comments
+    $access = user_access('create project issues');
     $items[] = array('path' => 'project/comments', 'title' => t('comments'), 'callback' => 'project_comment_page', 'access' => $access, 'type' => MENU_CALLBACK);
 
     // Releases
@@ -386,7 +408,7 @@
     array('data' => t('Issues'), 'colspan' => 4, 'field' => 'count')
   );
 
-  $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.changed, COUNT(p.nid) AS count FROM {node} n LEFT JOIN {project_issues} p ON n.nid = p.pid AND p.state IN (1,2,8) WHERE n.type = 'project_project' AND n.status = 1 AND n.uid = %d GROUP BY n.nid, n.title, n.changed %s"), $user->uid, tablesort_sql($header));
+  $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.changed, COUNT(p.nid) AS count FROM {node} n LEFT JOIN {project_issues} p ON n.nid = p.pid AND p.sid IN (1,2,8) WHERE n.type = 'project_project' AND n.status = 1 AND n.uid = %d GROUP BY n.nid, n.title, n.changed %s"), $user->uid, tablesort_sql($header));
 
   if (!db_num_rows($result)) {
     return ($current_user ? t('You have no projects.') : t('This user has no projects.'));
Index: modules/project/project.mysql
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.mysql,v
retrieving revision 1.14
diff -u -r1.14 project.mysql
--- modules/project/project.mysql	25 May 2004 19:42:39 -0000	1.14
+++ modules/project/project.mysql	26 May 2005 06:40:48 -0000
@@ -70,6 +70,7 @@
 ALTER TABLE project_issues ADD file_path varchar(255) NOT NULL default '';
 ALTER TABLE project_issues ADD file_mime varchar(255) NOT NULL default '';
 ALTER TABLE project_issues ADD file_size int NOT NULL default 0;
+ALTER TABLE project_issues CHANGE state sid int(10) unsigned NOT NULL default '0';
 
 --
 -- Table structure for table 'project_comments'
@@ -104,3 +105,31 @@
   level tinyint(3) unsigned NOT NULL default '0',
   KEY project_subscriptions_nid_uid_level (nid, uid, level)
 ) TYPE=MyISAM;
+
+--
+-- Table structure for table 'project_issue_state'
+--
+
+CREATE TABLE project_issue_state (
+  sid int(10) unsigned NOT NULL auto_increment,
+  name varchar(32) NOT NULL default '',
+  weight tinyint(2) DEFAULT '0' NOT NULL,
+  PRIMARY KEY  (sid)
+) TYPE=MyISAM;
+
+--
+-- Data for table 'project_issue_state'
+--
+
+INSERT INTO project_issue_state VALUES (1, 'active', -13);
+INSERT INTO project_issue_state VALUES (2, 'applied', 1);
+INSERT INTO project_issue_state VALUES (3, 'duplicate', 4);
+INSERT INTO project_issue_state VALUES (4, 'postponed', 6);
+INSERT INTO project_issue_state VALUES (5, 'won\'t fix', 9);
+INSERT INTO project_issue_state VALUES (6, 'by design', 11);
+INSERT INTO project_issue_state VALUES (7, 'closed', 13);
+INSERT INTO project_issue_state VALUES (8, 'patch', -8);
+INSERT INTO project_issue_state VALUES (9, 'needs work', -11);
+INSERT INTO project_issue_state VALUES (10, 'testers needed', -6);
+INSERT INTO project_issue_state VALUES (11, 'reviewed', -3);
+INSERT INTO project_issue_state VALUES (12, 'ready to commit', -1);
Index: modules/project/project.pgsql
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project/project.pgsql,v
retrieving revision 1.1
diff -u -r1.1 project.pgsql
--- modules/project/project.pgsql	8 May 2005 13:47:56 -0000	1.1
+++ modules/project/project.pgsql	26 May 2005 07:13:48 -0000
@@ -59,7 +59,7 @@
   priority smallint NOT NULL default '0',
   rid int NOT NULL default '0',
   assigned int NOT NULL default '0',
-  state smallint NOT NULL default '0',
+  sid int NOT NULL default '0',
   file_path varchar(255) NOT NULL default '',
   file_mime varchar(255) default '' NOT NULL,
   file_size int default 0 NOT NULL,
@@ -102,3 +102,32 @@
 
 CREATE SEQUENCE project_cid_seq INCREMENT 1 START 1;
 CREATE SEQUENCE project_rid_seq INCREMENT 1 START 1;
+
+
+--
+-- Table structure for table 'project_issue_state'
+--
+
+CREATE TABLE project_issue_state (
+  sid SERIAL,
+  name varchar(32) NOT NULL default '',
+  weight smallint DEFAULT '0' NOT NULL,
+  PRIMARY KEY  (sid)
+) TYPE=MyISAM;
+
+--
+-- Data for table 'project_issue_state'
+--
+
+INSERT INTO project_issue_state VALUES (1, 'active', -13);
+INSERT INTO project_issue_state VALUES (2, 'applied', 1);
+INSERT INTO project_issue_state VALUES (3, 'duplicate', 4);
+INSERT INTO project_issue_state VALUES (4, 'postponed', 6);
+INSERT INTO project_issue_state VALUES (5, 'won\'t fix', 9);
+INSERT INTO project_issue_state VALUES (6, 'by design', 11);
+INSERT INTO project_issue_state VALUES (7, 'closed', 13);
+INSERT INTO project_issue_state VALUES (8, 'patch', -8);
+INSERT INTO project_issue_state VALUES (9, 'needs work', -11);
+INSERT INTO project_issue_state VALUES (10, 'testers needed', -6);
+INSERT INTO project_issue_state VALUES (11, 'reviewed', -3);
+INSERT INTO project_issue_state VALUES (12, 'ready to commit', -1);
