Commit 8cb6f0fa authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 101179: Fully implement support for customised bug statuses and workflow…

Bug 101179: Fully implement support for customised bug statuses and workflow (final checkin!) - Patch by Fré©ric Buclin <LpSolit@gmail.com> r=gerv a=justdave
parent 8240cb08
...@@ -28,14 +28,14 @@ use Bugzilla::Constants; ...@@ -28,14 +28,14 @@ use Bugzilla::Constants;
use Bugzilla::Config qw(:admin); use Bugzilla::Config qw(:admin);
use Bugzilla::Token; use Bugzilla::Token;
use Bugzilla::Field; use Bugzilla::Field;
use Bugzilla::Bug;
# List of different tables that contain the changeable field values # List of different tables that contain the changeable field values
# (the old "enums.") Keep them in alphabetical order by their # (the old "enums.") Keep them in alphabetical order by their
# English name from field-descs.html.tmpl. # English name from field-descs.html.tmpl.
# Format: Array of valid field names. # Format: Array of valid field names.
# Admins may add bug_status to this list, but they do so at their own risk.
our @valid_fields = ('op_sys', 'rep_platform', 'priority', 'bug_severity', our @valid_fields = ('op_sys', 'rep_platform', 'priority', 'bug_severity',
'resolution'); 'bug_status', 'resolution');
# Add custom select fields. # Add custom select fields.
my @custom_fields = Bugzilla->get_fields({custom => 1, my @custom_fields = Bugzilla->get_fields({custom => 1,
...@@ -136,6 +136,7 @@ $defaults{'bug_severity'} = 'defaultseverity'; ...@@ -136,6 +136,7 @@ $defaults{'bug_severity'} = 'defaultseverity';
# Alternatively, a list of non-editable values can be specified. # Alternatively, a list of non-editable values can be specified.
# In this case, only the sortkey can be altered. # In this case, only the sortkey can be altered.
my %static; my %static;
$static{'bug_status'} = ['UNCONFIRMED'];
$static{'resolution'} = ['', 'FIXED', 'MOVED', 'DUPLICATE']; $static{'resolution'} = ['', 'FIXED', 'MOVED', 'DUPLICATE'];
$static{$_->name} = ['---'] foreach (@custom_fields); $static{$_->name} = ['---'] foreach (@custom_fields);
...@@ -219,13 +220,24 @@ if ($action eq 'new') { ...@@ -219,13 +220,24 @@ if ($action eq 'new') {
{'field' => $field, {'field' => $field,
'value' => $value}); 'value' => $value});
} }
if ($field eq 'bug_status'
&& (grep { lc($value) eq $_ } SPECIAL_STATUS_WORKFLOW_ACTIONS))
{
$vars->{'value'} = $value;
ThrowUserError('fieldvalue_reserved_word', $vars);
}
# Value is only used in a SELECT placeholder and through the HTML filter. # Value is only used in a SELECT placeholder and through the HTML filter.
trick_taint($value); trick_taint($value);
# Add the new field value. # Add the new field value.
my $sth = $dbh->prepare("INSERT INTO $field ( value, sortkey ) $dbh->do("INSERT INTO $field (value, sortkey) VALUES (?, ?)",
VALUES ( ?, ? )"); undef, ($value, $sortkey));
$sth->execute($value, $sortkey);
if ($field eq 'bug_status' && !$cgi->param('is_open')) {
# The bug status is a closed state, but they are open by default.
$dbh->do('UPDATE bug_status SET is_open = 0 WHERE value = ?', undef, $value);
}
delete_token($token); delete_token($token);
...@@ -292,7 +304,9 @@ if ($action eq 'delete') { ...@@ -292,7 +304,9 @@ if ($action eq 'delete') {
trick_taint($value); trick_taint($value);
$dbh->bz_lock_tables('bugs READ', "$field WRITE"); my @lock_tables = ('bugs READ', "$field WRITE");
push(@lock_tables, 'status_workflow WRITE') if ($field eq 'bug_status');
$dbh->bz_lock_tables(@lock_tables);
# Check if there are any bugs that still have this value. # Check if there are any bugs that still have this value.
my $bug_ids = $dbh->selectcol_arrayref( my $bug_ids = $dbh->selectcol_arrayref(
...@@ -306,6 +320,14 @@ if ($action eq 'delete') { ...@@ -306,6 +320,14 @@ if ($action eq 'delete') {
count => scalar(@$bug_ids) }); count => scalar(@$bug_ids) });
} }
if ($field eq 'bug_status') {
my $status_id = $dbh->selectrow_arrayref('SELECT id FROM bug_status
WHERE value = ?', undef, $value);
$dbh->do('DELETE FROM status_workflow
WHERE old_status = ? OR new_status = ?',
undef, ($status_id, $status_id));
}
$dbh->do("DELETE FROM $field WHERE value = ?", undef, $value); $dbh->do("DELETE FROM $field WHERE value = ?", undef, $value);
$dbh->bz_unlock_tables(); $dbh->bz_unlock_tables();
...@@ -332,6 +354,10 @@ if ($action eq 'edit') { ...@@ -332,6 +354,10 @@ if ($action eq 'edit') {
$vars->{'value'} = $value; $vars->{'value'} = $value;
$vars->{'is_static'} = (lsearch($static{$field}, $value) >= 0) ? 1 : 0; $vars->{'is_static'} = (lsearch($static{$field}, $value) >= 0) ? 1 : 0;
$vars->{'token'} = issue_session_token('edit_field_value'); $vars->{'token'} = issue_session_token('edit_field_value');
if ($field eq 'bug_status') {
$vars->{'is_open'} = $dbh->selectrow_array('SELECT is_open FROM bug_status
WHERE value = ?', undef, $value);
}
$template->process("admin/fieldvalues/edit.html.tmpl", $vars) $template->process("admin/fieldvalues/edit.html.tmpl", $vars)
|| ThrowTemplateError($template->error()); || ThrowTemplateError($template->error());
...@@ -391,6 +417,12 @@ if ($action eq 'update') { ...@@ -391,6 +417,12 @@ if ($action eq 'update') {
if (ValueExists($field, $value)) { if (ValueExists($field, $value)) {
ThrowUserError('fieldvalue_already_exists', $vars); ThrowUserError('fieldvalue_already_exists', $vars);
} }
if ($field eq 'bug_status'
&& (grep { lc($value) eq $_ } SPECIAL_STATUS_WORKFLOW_ACTIONS))
{
$vars->{'value'} = $value;
ThrowUserError('fieldvalue_reserved_word', $vars);
}
trick_taint($value); trick_taint($value);
$dbh->do("UPDATE bugs SET $field = ? WHERE $field = ?", $dbh->do("UPDATE bugs SET $field = ? WHERE $field = ?",
......
...@@ -496,6 +496,10 @@ CrossCheck('whine_events', 'id', ...@@ -496,6 +496,10 @@ CrossCheck('whine_events', 'id',
CrossCheck('attachments', 'attach_id', CrossCheck('attachments', 'attach_id',
['attach_data', 'id']); ['attach_data', 'id']);
CrossCheck('bug_status', 'id',
['status_workflow', 'old_status'],
['status_workflow', 'new_status']);
########################################################################### ###########################################################################
# Perform double field referential (cross) checks # Perform double field referential (cross) checks
########################################################################### ###########################################################################
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
# The Original Code is the Bugzilla Bug Tracking System. # The Original Code is the Bugzilla Bug Tracking System.
# #
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org> # Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
# Frédéric Buclin <LpSolit@gmail.com>
#%] #%]
[%# INTERFACE: [%# INTERFACE:
...@@ -41,6 +42,24 @@ ...@@ -41,6 +42,24 @@
<td><input id="sortkey" size="10" maxlength="20" name="sortkey" <td><input id="sortkey" size="10" maxlength="20" name="sortkey"
value=""></td> value=""></td>
</tr> </tr>
[% IF field.name == "bug_status" %]
<tr>
<th align="right"><label for="is_open">Status Type:</label></th>
<td>
<input type="radio" id="open_status" name="is_open" value="1" checked="checked">
<label for="open_status">Open</label><br>
<input type="radio" id="closed_status" name="is_open" value="0">
<label for="closed_status">Closed (requires a Resolution)</label>
</td>
</tr>
<tr>
<th>&nbsp;</th>
<td>
Note: The open/close attribute can only be set now, when you create
the status. It cannot be edited later.
</td>
</tr>
[% END %]
</table> </table>
<input type="submit" id="create" value="Add"> <input type="submit" id="create" value="Add">
<input type="hidden" name="action" value="new"> <input type="hidden" name="action" value="new">
......
...@@ -34,6 +34,11 @@ ...@@ -34,6 +34,11 @@
[%- value FILTER html %]</a>' has been added as a valid choice for [%- value FILTER html %]</a>' has been added as a valid choice for
the '[% field.description FILTER html %]' field.</p> the '[% field.description FILTER html %]' field.</p>
[% IF field.name == "bug_status" %]
You should now visit the <a href="editworkflow.cgi">status workflow page</a>
to include your new [% terms.bug %] status.
[% END %]
[% PROCESS admin/fieldvalues/footer.html.tmpl %] [% PROCESS admin/fieldvalues/footer.html.tmpl %]
[% PROCESS global/footer.html.tmpl %] [% PROCESS global/footer.html.tmpl %]
...@@ -50,7 +50,12 @@ ...@@ -50,7 +50,12 @@
<td><input id="sortkey" size="20" maxlength="20" name="sortkey" value=" <td><input id="sortkey" size="20" maxlength="20" name="sortkey" value="
[%- sortkey FILTER html %]"></td> [%- sortkey FILTER html %]"></td>
</tr> </tr>
[% IF field.name == "bug_status" %]
<tr>
<th align="right"><label for="is_open">Status Type:</label></th>
<td>[% IF is_open %]Open[% ELSE %]Closed[% END %]</td>
</tr>
[% END %]
</table> </table>
<input type="hidden" name="valueold" value="[% value FILTER html %]"> <input type="hidden" name="valueold" value="[% value FILTER html %]">
......
...@@ -459,6 +459,12 @@ ...@@ -459,6 +459,12 @@
[% title = "Field Value Not Specified" %] [% title = "Field Value Not Specified" %]
No field value specified when trying to edit a field value. No field value specified when trying to edit a field value.
[% ELSIF error == "fieldvalue_reserved_word" %]
[% title = "Reserved Word Not Allowed" %]
You cannot use the '[% value FILTER html %]' value for the
'[% field.description FILTER html %]' field. This value is used internally.
Please choose another one.
[% ELSIF error == "fieldvalue_sortkey_invalid" %] [% ELSIF error == "fieldvalue_sortkey_invalid" %]
[% title = "Invalid Field Value Sortkey" %] [% title = "Invalid Field Value Sortkey" %]
The sortkey '[% sortkey FILTER html %]' for the '[% name FILTER html %]' The sortkey '[% sortkey FILTER html %]' for the '[% name FILTER html %]'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment