cvs diff: Diffing . Index: issue.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/issue.inc,v retrieving revision 1.354 diff -u -p -r1.354 issue.inc --- issue.inc 18 Jun 2009 03:28:55 -0000 1.354 +++ issue.inc 24 Apr 2010 01:56:20 -0000 @@ -235,9 +235,39 @@ function project_issue_default_states() return $defaults; } -function project_issue_priority($priority = 0) { - $priorities = array(1 => t('critical'), t('normal'), t('minor')); - return $priority ? $priorities[$priority] : $priorities; +/** + * Return all available issue priorities, sorted by weight. + * + * @return + * An array of priorities keyed by id. + */ +function project_issue_priorities() { + static $priorities; + if (!isset($priorities)) { + $result = db_query('SELECT priority, name FROM {project_issue_priority} ORDER BY weight'); + while ($object = db_fetch_object($result)) { + $priorities[$object->priority] = $object->name; + } + } + return $priorities; +} + +/** + * Return the name of a priority for a given id. + * + * @param $priority + * The id of the priority. + * @return + * The name of the priority. + */ +function project_issue_priority($priority) { + $priorities = project_issue_priorities(); + if ($priority && array_key_exists($priority, $priorities)) { + return $priorities[$priority]; + } + else { + return t('[deleted priority]'); + } } function project_issue_category($category = 0, $plural = 1) { Index: project_issue.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.install,v retrieving revision 1.64 diff -u -p -r1.64 project_issue.install --- project_issue.install 21 Aug 2009 22:51:31 -0000 1.64 +++ project_issue.install 24 Apr 2010 01:56:20 -0000 @@ -110,13 +110,20 @@ function project_issue_schema() { 'default' => '', ), 'priority' => array( - 'description' => 'The priority for this issue.', + 'description' => 'Current {project_issue_priority}.priority of this issue.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => 1, 'not null' => TRUE, 'default' => 0, ), + 'priority_weight' => array( + 'description' => 'The denormalized weight from {project_issue_priority}.weight.', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), 'rid' => array( 'description' => 'The {project_release_nodes}.rid (version identifier) for this issue (only used in conjunction with the project_release module).', 'type' => 'int', @@ -199,7 +206,7 @@ function project_issue_schema() { 'default' => '', ), 'priority' => array( - 'description' => 'The priority for this issue after this comment was made.', + 'description' => 'The {project_issue_priority}.priority of this issue after this comment was made.', 'type' => 'int', 'not null' => TRUE, 'default' => 0, @@ -249,6 +256,32 @@ function project_issue_schema() { ), ); + $schema['project_issue_priority'] = array( + 'description' => 'The available options for the priority values for issues.', + 'fields' => array( + 'priority' => array( + 'description' => 'Primary Key: Unique id for this priority.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'name' => array( + 'description' => 'Display-friendly name for this priority.', + 'type' => 'varchar', + 'length' => 64, + 'not null' => TRUE, + 'default' => '', + ), + 'weight' => array( + 'description' => 'Weight for this priority, used when ordering issues by priority. Denormalized into {project_issues}.priority_weight.', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('priority'), + ); + $schema['project_subscriptions'] = array( 'description' => 'Table keeping track of per-user project_issue subscriptions.', 'fields' => array( @@ -364,6 +397,9 @@ function project_issue_install() { variable_set('comment_upload_project_issue', 1); // Enable file attachments for issues. variable_set('upload_project_issue', 1); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (1, 'critical', 1)"); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (2, 'normal', 2)"); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (3, 'minor', 3)"); } /** @@ -446,3 +482,57 @@ function project_issue_update_6002() { return $ret; } +/** + * Add table for project_issue_priority, and insert default values. + */ +function project_issue_update_6003() { + $ret = array(); + $table = array( + 'description' => 'The issue priorities.', + 'fields' => array( + 'priority' => array( + 'description' => 'Primary Key: Unique id for this priority.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'name' => array( + 'description' => 'Display-friendly name for this priority.', + 'type' => 'varchar', + 'length' => 64, + 'not null' => TRUE, + 'default' => '', + ), + 'weight' => array( + 'description' => 'Weight for this priority, used when ordering issues by priority. Denormalized into {project_issues}.priority_weight.', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('priority'), + ); + db_create_table($ret, 'project_issue_priority', $table); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (1, 'critical', 1)"); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (2, 'normal', 2)"); + db_query("INSERT INTO {project_issue_priority} (priority, name, weight) VALUES (3, 'minor', 3)"); + + db_add_field($ret, 'project_issues', 'priority_weight', array('type' => 'int', 'not null' => TRUE, 'default' => '0', 'size' => 'tiny')); + return $ret; +} + +/** + * Update {project_issues} with denormalized priority weight. + */ +function project_issue_update_6004(&$sandbox) { + $ret = array(); + // Reconstruct a batch context. + $context = array('sandbox' => &$sandbox); + // Load the include. + require_once drupal_get_path('module', 'project_issue') .'/includes/admin.batch_confirm.inc'; + // Call the batch upgrade which will set its variables in the sandbox. + _project_issue_batch_update('UPDATE {project_issues} SET priority_weight = priority WHERE nid BETWEEN %d AND %d', array(), $context); + // Pass back progress. + $ret['#finished'] = $context['finished']; + return $ret; +} Index: project_issue.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.module,v retrieving revision 1.179 diff -u -p -r1.179 project_issue.module --- project_issue.module 22 Apr 2010 09:34:54 -0000 1.179 +++ project_issue.module 24 Apr 2010 01:56:21 -0000 @@ -99,6 +99,27 @@ function project_issue_menu() { 'file' => 'includes/admin.settings.inc', ); + // Administrative pages + $items['admin/project/project-issue-priority'] = array( + 'title' => 'Project issue priority options', + 'description' => 'Configure what issue priorities should be used on your site.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('project_issue_admin_priority_form'), + 'access arguments' => array('administer projects'), + 'weight' => 1, + 'type' => MENU_NORMAL_ITEM, + 'file' => 'includes/admin.issue_priority.inc', + ); + $items['admin/project/project-issue-priority/delete'] = array( + 'title' => 'Delete', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('project_issue_delete_priority_confirm', 4), + 'access arguments' => array('administer projects'), + 'type' => MENU_CALLBACK, + 'file' => 'includes/admin.issue_priority.inc' + ); + + // Administer issue status settings $items['admin/project/project-issue-status'] = array( 'title' => 'Project issue status options', @@ -323,6 +344,12 @@ function project_issue_theme() { 'form' => NULL, ), ), + 'project_issue_admin_priority_form' => array( + 'file' => 'includes/admin.issue_priority.inc', + 'arguments' => array( + 'form' => NULL, + ), + ), 'project_issue_project_edit_form' => array( 'file' => 'includes/project_edit_issues.inc', 'arguments' => array( @@ -1770,4 +1797,3 @@ function project_issue_project_page_link $links['development']['links'] = $patches + $links['development']['links']; } } - Index: project_issue.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.test,v retrieving revision 1.3 diff -u -p -r1.3 project_issue.test --- project_issue.test 20 Apr 2010 22:22:06 -0000 1.3 +++ project_issue.test 24 Apr 2010 01:56:21 -0000 @@ -55,11 +55,14 @@ class ProjectIssueWebTestCase extends Pr * @param $nid * Optional integer node ID of the issue to check metadata fields for. */ - function assertIssueMetadata($metadata, $nid = NULL) { + function assertIssueMetadata($metadata, $nid = NULL, $message = NULL) { $pass = TRUE; if ($nid) { $this->drupalGet('node/' . $nid); } + if (!$message) { + $message = t('Issue metadata matches'); + } foreach ($this->xpath("//div[@id='project-issue-summary-table']/table//tr") as $row) { $key = strtolower(trim((string)$row->td[0], ':')); if (isset($metadata[$key])) { @@ -69,10 +72,10 @@ class ProjectIssueWebTestCase extends Pr } } if ($pass) { - $this->pass(t('Issue metadata matches')); + $this->pass($message); } else { - $this->fail(t('Issue metadata matches')); + $this->fail($message); } } } @@ -168,7 +171,7 @@ class ProjectIssueCommentTestCase extend 'pid' => 'project_info[pid]', ); foreach ($map as $issue_key => $post_key) { - $this->assertEqual($issue->project_issue[$issue_key], $post[$post_key], t('Making sure comment form is correct')); + $this->assertEqual($issue->project_issue[$issue_key], $post[$post_key], t('Making sure comment form is correct.')); } } @@ -183,3 +186,192 @@ class ProjectIssueCommentTestCase extend $this->assertText($comment['comment'], t('Body found')); } } + +class ProjectIssuePriorityTestCase extends ProjectIssueWebTestCase { + /** + * A user who can maintain project issue administrative settings, projects, and create issues. + */ + protected $maintain_user; + + public static function getInfo() { + return array( + 'name' => 'Project issue priority', + 'description' => 'Test issue priority settings and functionality.', + 'group' => 'Project Issue', + ); + } + + function setUp() { + parent::setUp(); + + $this->maintain_user = $this->drupalCreateUser(array('administer projects', 'maintain projects', 'create project issues', 'access project issues', 'access projects')); + $this->drupalLogin($this->maintain_user); + } + + /** + * Assert that the priorities are stored and displayed correctly. + * + * This function will take an array of priorities keyed by their priority ID, + * with each item being an array with they keys 'name' and 'weight'. + */ + function assertAdminPrioritiesForm($values) { + $pass = TRUE; + $this->drupalGet('admin/project/project-issue-priority'); + $forms = $this->xpath('//form'); + $form = $forms[0]; + + $post = $edit = $upload = array(); + $this->handleForm($post, $edit, $upload, NULL, $form); + + foreach ($values as $key => $priority) { + $result = $this->assertEqual($post["priority[$key][name]"], $priority['name'], t('The name for the priority is correct.')); + $result = $this->assertEqual($post["priority[$key][weight]"], $priority['weight'], t('The weight for the priority is correct.')); + } + } + + /** + * Test the project issue priority admin form. + */ + function testProjectIssuePrioritySettings() { + // This matches the defaults setup in project_issue_install(). + $default_priority_order = array( + 1 => array( + 'name' => 'critical', + 'weight' => 1, + ), + 2 => array( + 'name' => 'normal', + 'weight' => 2, + ), + 3 => array( + 'name' => 'minor', + 'weight' => 3, + ), + ); + $this->assertAdminPrioritiesForm($default_priority_order); + + // Test reordering ability + $edit = array(); + $edit['priority[1][weight]'] = -2; + $edit['priority[2][weight]'] = -3; + $edit['priority[3][weight]'] = -1; + $this->drupalPost('admin/project/project-issue-priority', $edit, t('Save')); + + // Check new values + $priorities = array( + 1 => array( + 'name' => 'critical', + 'weight' => 1, + ), + 2 => array( + 'name' => 'normal', + 'weight' => 0, + ), + 3 => array( + 'name' => 'minor', + 'weight' => 2, + ), + ); + $this->assertAdminPrioritiesForm($priorities); + + // Add a new priority, and check the form results + $edit = array(); + $edit['priority[0][name]'] = $this->randomName(8); + $this->drupalPost('admin/project/project-issue-priority', $edit, t('Save')); + + // Check new values + $priorities = array( + 1 => array( + 'name' => 'critical', + 'weight' => 1, + ), + 2 => array( + 'name' => 'normal', + 'weight' => 0, + ), + 3 => array( + 'name' => 'minor', + 'weight' => 2, + ), + 4 => array( + 'name' => $edit['priority[0][name]'], + 'weight' => 3, + ), + ); + $this->assertAdminPrioritiesForm($priorities); + + // Test deleting a priority without any issues. + $this->drupalGet('admin/project/project-issue-priority/delete/4'); + $this->assertNoText('Reassign priority', t('Issue confirm form is displayed properly.')); + $this->drupalPost('admin/project/project-issue-priority/delete/4', array(), t('Delete')); + $this->assertText('Project issue priority '. $edit['priority[0][name]'] .' deleted.', t('Project issue priority has been deleted.')); + + // Test that a custom priority can be assinged to an issue and is displayed correctly. + $edit = array(); + $edit['priority[0][name]'] = $priority_name = $this->randomName(8); + $this->drupalPost('admin/project/project-issue-priority', $edit, t('Save')); + $project = $this->createProject(); + + $edit = array(); + $edit['priority'] = '5'; + $issue = $this->createIssue($project, $edit); + + // Check that the issue priority is displayed correctly. + $this->assertIssueMetadata(array('priority' => $priority_name), $issue->nid, t('Custom issue priority is displyed correctly')); + + // Delete the priority + $this->drupalGet('admin/project/project-issue-priority/delete/5'); + $this->assertText('Reassign priority', t('Issue confirm form is displayed properly.')); + + $edit = array(); + $edit['new_pid'] = 2; + $this->drupalPost(NULL, $edit, t('Delete')); + $this->assertText('Project issue priority '. $priority_name .' deleted.', t('Issue priority was deleted')); + + $this->assertIssueMetadata(array('priority' => 'normal'), $issue->nid); + + $edit = array(); + $edit['priority[1][weight]'] = -3; + $edit['priority[2][weight]'] = -2; + $edit['priority[3][weight]'] = -1; + $this->drupalPost('admin/project/project-issue-priority', $edit, t('Save')); + + $priorities = array( + 1 => array( + 'name' => 'critical', + 'weight' => 0, + ), + 2 => array( + 'name' => 'normal', + 'weight' => 1, + ), + 3 => array( + 'name' => 'minor', + 'weight' => 2, + ), + ); + $this->assertAdminPrioritiesForm($priorities); + + $edit = array(); + $edit['priority'] = 1; + $edit['title'] = $critical_title = $this->randomName(8); + $critical_issue = $this->createIssue($project, $edit); + + $edit = array(); + $edit['priority'] = 3; + $edit['title'] = $minor_title = $this->randomName(8); + $minor_issue = $this->createIssue($project, $edit); + + $this->drupalGet('project/issues/'. $project->project['uri']); + $this->clickLink(t('Priority')); + + // Check that views handler +// @TODO This code is not working yet but is quite important +// $rows = $this->xpath("//table[@class='project-issue']/tr"); +// debug((string)$rows[0]->td[0]); +// +// $this->assertEqual((string)$rows[0], $minor_issue->title); +// $this->assertEqual((string)$rows[1], $issue->title); +// $this->assertEqual((string)$rows[2], $critical_issue->title); + } +} cvs diff: Diffing generate Index: generate/project_issue_generate.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/generate/project_issue_generate.inc,v retrieving revision 1.13 diff -u -p -r1.13 project_issue_generate.inc --- generate/project_issue_generate.inc 21 Mar 2009 18:50:17 -0000 1.13 +++ generate/project_issue_generate.inc 24 Apr 2010 01:56:21 -0000 @@ -199,7 +199,7 @@ function _project_issue_generate_get_fie return array_keys(project_issue_category()); case 'priorities': - return project_issue_priority(); + return project_issue_priorities(); case 'users': // Determine what role ids have permission to create project_issue nodes. cvs diff: Diffing includes Index: includes/admin.batch_confirm.inc =================================================================== RCS file: includes/admin.batch_confirm.inc diff -N includes/admin.batch_confirm.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/admin.batch_confirm.inc 24 Apr 2010 01:56:21 -0000 @@ -0,0 +1,66 @@ + so use - 1 when choosing the smallest nid. + $context['sandbox']['min'] = db_result(db_query('SELECT MIN(nid) - 1 FROM {project_issues}')); + $context['sandbox']['current'] = $context['sandbox']['min']; + } + $arguments = $base_arguments; + // MySQL does not support LIMIT & IN/ALL/ANY/SOME subquery so we do the hard + // work ourselves: find 100 nids and record the first and the last. + $results = db_query_range('SELECT nid FROM {project_issues} WHERE nid > %d ORDER BY nid ASC', $context['sandbox']['current'], 0, 100); + while ($node = db_fetch_object($results)) { + if (!isset($first_nid)) { + $first_nid = $node->nid; + } + $last_nid = $node->nid; + } + $arguments[] = $first_nid; + $arguments[] = $last_nid; + db_query($sql, $arguments); + // Note that we do not count exactly as there can be holes. That's still + // better than running COUNT() on large datasets. + if ($last_nid < $context['sandbox']['max']) { + $context['finished'] = ($last_nid - $context['sandbox']['min']) / ($context['sandbox']['max'] - $context['sandbox']['min']); + $context['sandbox']['current'] = $last_nid; + } + else { + $context['finished'] = 1; + } +} Index: includes/admin.issue_priority.inc =================================================================== RCS file: includes/admin.issue_priority.inc diff -N includes/admin.issue_priority.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ includes/admin.issue_priority.inc 24 Apr 2010 01:56:21 -0000 @@ -0,0 +1,227 @@ +weight); + $form['priority'][$priority->priority]['name'] = array( + '#type' => 'textfield', + '#default_value' => $priority->name, + '#size' => 20, + '#maxlength' => 255, + ); + $form['priority'][$priority->priority]['weight'] = array( + '#type' => 'weight', + '#default_value' => $priority->weight, + '#delta' => &$delta, + '#attributes' => array('class' => 'project-issue-priority-weight'), + ); + $form['delete'][$priority->priority]['#value'] = l(t('Delete'), 'admin/project/project-issue-priority/delete/'. $priority->priority); + } + $delta = $max + 1; + $form['priority'][0]['name'] = array( + '#type' => 'textfield', + '#default_value' => '', + '#size' => 20, + '#maxlength' => 255, + ); + $form['priority'][0]['weight'] = array( + '#type' => 'weight', + // Make sure that the new item has a weight higher than highest priority + // since new item appears at bottom of the form by default. + '#default_value' => $max + 1, + '#delta' => $max + 1, + '#attributes' => array('class' => 'project-issue-priority-weight'), + ); + $form['delete'][0]['#value'] = ''; + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + $form['#tree'] = TRUE; + return $form; +} + +/** + * Render the HTML for the admin issue priority form. + * + * @see project_issue_admin_priority_form() + * @see drupal_add_tabledrag() + */ +function theme_project_issue_admin_priority_form($form) { + drupal_add_tabledrag('project-issue-admin-priority-table', 'order', 'self', 'project-issue-priority-weight'); + $header = array( + t('Priority'), + t('Weight'), + t('Operations'), + ); + foreach (element_children($form['priority']) as $key) { + $rows[] = array( + 'class' => 'draggable', + 'data' => array( + drupal_render($form['priority'][$key]['name']), + drupal_render($form['priority'][$key]['weight']), + drupal_render($form['delete'][$key]), + ), + ); + } + $output = '