Commit c3c2eccd authored by Dylan William Hardison's avatar Dylan William Hardison Committed by Dylan William Hardison

Bug 69267: Add the ability to deactivate keywords

r/a=glob
parent 0e68998f
...@@ -1851,6 +1851,20 @@ sub _check_keywords { ...@@ -1851,6 +1851,20 @@ sub _check_keywords {
my $obj = Bugzilla::Keyword->check($keyword); my $obj = Bugzilla::Keyword->check($keyword);
$keywords{$obj->id} = $obj; $keywords{$obj->id} = $obj;
} }
my %old_kw_id;
if (blessed $invocant) {
my @old_keywords = @{$invocant->keyword_objects};
%old_kw_id = map { $_->id => 1 } @old_keywords;
}
foreach my $keyword (values %keywords) {
next if $keyword->is_active || exists $old_kw_id{$keyword->id};
ThrowUserError('value_inactive',
{ value => $keyword->name, class => ref $keyword });
}
return [values %keywords]; return [values %keywords];
} }
......
...@@ -588,6 +588,8 @@ use constant ABSTRACT_SCHEMA => { ...@@ -588,6 +588,8 @@ use constant ABSTRACT_SCHEMA => {
PRIMARYKEY => 1}, PRIMARYKEY => 1},
name => {TYPE => 'varchar(64)', NOTNULL => 1}, name => {TYPE => 'varchar(64)', NOTNULL => 1},
description => {TYPE => 'MEDIUMTEXT', NOTNULL => 1}, description => {TYPE => 'MEDIUMTEXT', NOTNULL => 1},
is_active => {TYPE => 'BOOLEAN', NOTNULL => 1,
DEFAULT => 'TRUE'},
], ],
INDEXES => [ INDEXES => [
keyworddefs_name_idx => {FIELDS => ['name'], keyworddefs_name_idx => {FIELDS => ['name'],
...@@ -605,7 +607,6 @@ use constant ABSTRACT_SCHEMA => { ...@@ -605,7 +607,6 @@ use constant ABSTRACT_SCHEMA => {
REFERENCES => {TABLE => 'keyworddefs', REFERENCES => {TABLE => 'keyworddefs',
COLUMN => 'id', COLUMN => 'id',
DELETE => 'CASCADE'}}, DELETE => 'CASCADE'}},
], ],
INDEXES => [ INDEXES => [
keywords_bug_id_idx => {FIELDS => [qw(bug_id keywordid)], keywords_bug_id_idx => {FIELDS => [qw(bug_id keywordid)],
......
...@@ -730,6 +730,10 @@ sub update_table_definitions { ...@@ -730,6 +730,10 @@ sub update_table_definitions {
$dbh->bz_add_column('longdescs', 'is_markdown', $dbh->bz_add_column('longdescs', 'is_markdown',
{TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}); {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
# 2014-11-18 dylan@mozilla.com - Bug 69267
$dbh->bz_add_column('keyworddefs', 'is_active',
{TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'TRUE'});
################################################################ ################################################################
# New --TABLE-- changes should go *** A B O V E *** this point # # New --TABLE-- changes should go *** A B O V E *** this point #
################################################################ ################################################################
......
...@@ -26,6 +26,7 @@ use constant DB_COLUMNS => qw( ...@@ -26,6 +26,7 @@ use constant DB_COLUMNS => qw(
keyworddefs.id keyworddefs.id
keyworddefs.name keyworddefs.name
keyworddefs.description keyworddefs.description
keyworddefs.is_active
); );
use constant DB_TABLE => 'keyworddefs'; use constant DB_TABLE => 'keyworddefs';
...@@ -33,11 +34,13 @@ use constant DB_TABLE => 'keyworddefs'; ...@@ -33,11 +34,13 @@ use constant DB_TABLE => 'keyworddefs';
use constant VALIDATORS => { use constant VALIDATORS => {
name => \&_check_name, name => \&_check_name,
description => \&_check_description, description => \&_check_description,
is_active => \&_check_is_active,
}; };
use constant UPDATE_COLUMNS => qw( use constant UPDATE_COLUMNS => qw(
name name
description description
is_active
); );
############################### ###############################
...@@ -62,6 +65,7 @@ sub bug_count { ...@@ -62,6 +65,7 @@ sub bug_count {
sub set_name { $_[0]->set('name', $_[1]); } sub set_name { $_[0]->set('name', $_[1]); }
sub set_description { $_[0]->set('description', $_[1]); } sub set_description { $_[0]->set('description', $_[1]); }
sub set_is_active { $_[0]->set('is_active', $_[1]); }
############################### ###############################
#### Subroutines ###### #### Subroutines ######
...@@ -125,6 +129,10 @@ sub _check_description { ...@@ -125,6 +129,10 @@ sub _check_description {
return $desc; return $desc;
} }
sub _check_is_active { return $_[1] ? 1 : 0 }
sub is_active { return $_[0]->{is_active} }
1; 1;
__END__ __END__
...@@ -145,13 +153,13 @@ Bugzilla::Keyword - A Keyword that can be added to a bug. ...@@ -145,13 +153,13 @@ Bugzilla::Keyword - A Keyword that can be added to a bug.
Bugzilla::Keyword represents a keyword that can be added to a bug. Bugzilla::Keyword represents a keyword that can be added to a bug.
This implements all standard C<Bugzilla::Object> methods. See This implements all standard C<Bugzilla::Object> methods. See
L<Bugzilla::Object> for more details. L<Bugzilla::Object> for more details.
=head1 SUBROUTINES =head1 METHODS
This is only a list of subroutines specific to C<Bugzilla::Keyword>. This is only a list of methods specific to C<Bugzilla::Keyword>.
See L<Bugzilla::Object> for more subroutines that this object See L<Bugzilla::Object> for more methods that this object
implements. implements.
=over =over
...@@ -166,6 +174,18 @@ implements. ...@@ -166,6 +174,18 @@ implements.
Returns: A reference to an array of Keyword objects, or an empty Returns: A reference to an array of Keyword objects, or an empty
arrayref if there are no keywords. arrayref if there are no keywords.
=item C<is_active>
Description: Indicates if the keyword may be used on a bug
Params: none
Returns: a boolean value that is true if the keyword can be applied to bugs.
=item C<set_is_active($is_active)>
Description: Set the is_active property to a boolean value
Params: the new value of the is_active property.
Returns: nothing
=back =back
=cut =cut
......
...@@ -1106,11 +1106,16 @@ sub create { ...@@ -1106,11 +1106,16 @@ sub create {
# Whether or not keywords are enabled, in this Bugzilla. # Whether or not keywords are enabled, in this Bugzilla.
'use_keywords' => sub { return Bugzilla::Keyword->any_exist; }, 'use_keywords' => sub { return Bugzilla::Keyword->any_exist; },
# All the keywords. # All the keywords
'all_keywords' => sub { 'all_keywords' => sub {
return [map { $_->name } Bugzilla::Keyword->get_all()]; return [map { $_->name } Bugzilla::Keyword->get_all()];
}, },
# All the active keywords
'active_keywords' => sub {
return [map { $_->name } grep { $_->is_active } Bugzilla::Keyword->get_all()];
},
'feature_enabled' => sub { return Bugzilla->feature(@_); }, 'feature_enabled' => sub { return Bugzilla->feature(@_); },
# field_descs can be somewhat slow to generate, so we generate # field_descs can be somewhat slow to generate, so we generate
......
...@@ -245,6 +245,7 @@ sub _legal_field_values { ...@@ -245,6 +245,7 @@ sub _legal_field_values {
elsif ($field_name eq 'keywords') { elsif ($field_name eq 'keywords') {
my @legal_keywords = Bugzilla::Keyword->get_all; my @legal_keywords = Bugzilla::Keyword->get_all;
foreach my $value (@legal_keywords) { foreach my $value (@legal_keywords) {
next unless $value->is_active;
push (@result, { push (@result, {
name => $self->type('string', $value->name), name => $self->type('string', $value->name),
description => $self->type('string', $value->description), description => $self->type('string', $value->description),
......
...@@ -9,8 +9,6 @@ A company might have a policy stating all regressions ...@@ -9,8 +9,6 @@ A company might have a policy stating all regressions
must be fixed by the next release—this keyword can make tracking those must be fixed by the next release—this keyword can make tracking those
bugs much easier. Keywords are global, rather than per product. bugs much easier. Keywords are global, rather than per product.
Keywords can be created, edited, or deleted by clicking the "Keywords" Keywords can be created, edited, deactivated, or deleted by clicking the "Keywords"
link in the admin page. There are two fields for each keyword—the keyword link in the admin page. There are two fields for each keyword—the keyword
itself and a brief description. Currently keywords cannot be marked obsolete itself and a brief description.
to prevent future usage.
...@@ -71,11 +71,12 @@ if ($action eq 'add') { ...@@ -71,11 +71,12 @@ if ($action eq 'add') {
# #
if ($action eq 'new') { if ($action eq 'new') {
check_token_data($token, 'add_keyword'); check_token_data($token, 'add_keyword');
my $name = $cgi->param('name') || ''; my $name = $cgi->param('name') || '';
my $desc = $cgi->param('description') || ''; my $is_active = $cgi->param('is_active');
my $desc = $cgi->param('description') || '';
my $keyword = Bugzilla::Keyword->create( my $keyword = Bugzilla::Keyword->create(
{ name => $name, description => $desc }); { name => $name, is_active => $is_active, description => $desc });
delete_token($token); delete_token($token);
...@@ -123,6 +124,7 @@ if ($action eq 'update') { ...@@ -123,6 +124,7 @@ if ($action eq 'update') {
$keyword->set_all({ $keyword->set_all({
name => scalar $cgi->param('name'), name => scalar $cgi->param('name'),
description => scalar $cgi->param('description'), description => scalar $cgi->param('description'),
is_active => scalar $cgi->param('is_active'),
}); });
my $changes = $keyword->update(); my $changes = $keyword->update();
......
...@@ -18,14 +18,19 @@ ...@@ -18,14 +18,19 @@
<form method="post" action="editkeywords.cgi"> <form method="post" action="editkeywords.cgi">
<table id="admin_table_edit"> <table id="admin_table_edit">
<tr> <tr>
<th>Name:</th> <th><label for="name">Name:</label></th>
<td><input size="64" maxlength="64" name="name" <td><input size="64" maxlength="64" name="name" id="name"
value="[% keyword.name FILTER html %]" required></td> value="[% keyword.name FILTER html %]" required></td>
</tr> </tr>
<tr> <tr>
<th>Description:</th> <th><label for="is_active">Enabled For [% terms.Bugs %]</label></th>
<td><input id="is_active" name="is_active" type="checkbox" [% "checked" IF keyword.is_active %]></td>
</tr>
<tr>
<th><label for="decription">Description:</label></th>
<td> <td>
[% INCLUDE global/textarea.html.tmpl [% INCLUDE global/textarea.html.tmpl
id = 'description'
name = 'description' name = 'description'
minrows = 4 minrows = 4
cols = 64 cols = 64
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
# keywords: array keyword objects having the properties: # keywords: array keyword objects having the properties:
# - id: number. The ID of the keyword. # - id: number. The ID of the keyword.
# - name: string. The name of the keyword. # - name: string. The name of the keyword.
# - is_active: boolean. true if the keyword can be used.
# - description: string. The description of the keyword. # - description: string. The description of the keyword.
# - bug_count: number. The number of bugs with the keyword. # - bug_count: number. The number of bugs with the keyword.
#%] #%]
...@@ -20,34 +21,39 @@ ...@@ -20,34 +21,39 @@
%] %]
[% columns = [ [% columns = [
{ {
name => "name" name => "name"
heading => "Edit keyword..." heading => "Edit keyword..."
contentlink => "editkeywords.cgi?action=edit&amp;id=%%id%%" contentlink => "editkeywords.cgi?action=edit&amp;id=%%id%%"
}, },
{ {
name => "description" name => "description"
heading => "Description" heading => "Description"
allow_html_content => 1 allow_html_content => 1
}, },
{ {
name => "bug_count" name => "is_active",
heading => "$terms.Bugs" heading => "Active",
class => "right" yesno_field => 1
contentlink => "buglist.cgi?keywords=%%name%%" },
}, {
{ name => "bug_count"
heading => "Action" heading => "$terms.Bugs"
content => "Delete" class => "right"
contentlink => "editkeywords.cgi?action=del&amp;id=%%id%%" contentlink => "buglist.cgi?keywords=%%name%%"
} },
] {
heading => "Action"
content => "Delete"
contentlink => "editkeywords.cgi?action=del&amp;id=%%id%%"
}
]
%] %]
[% PROCESS admin/table.html.tmpl [% PROCESS admin/table.html.tmpl
columns = columns columns = columns
data = keywords data = keywords
footer = footer_row footer = footer_row
%] %]
<p><a href="editkeywords.cgi?action=add">Add a new keyword</a></p> <p><a href="editkeywords.cgi?action=add">Add a new keyword</a></p>
......
...@@ -537,7 +537,7 @@ TUI_hide_default('attachment_text_field'); ...@@ -537,7 +537,7 @@ TUI_hide_default('attachment_text_field');
<tr> <tr>
[% INCLUDE bug/field.html.tmpl [% INCLUDE bug/field.html.tmpl
bug = default, field = bug_fields.keywords, editable = 1, bug = default, field = bug_fields.keywords, editable = 1,
value = keywords, possible_values = all_keywords, value = keywords, possible_values = active_keywords,
desc_url = "describekeywords.cgi", value_span = 3 desc_url = "describekeywords.cgi", value_span = 3
%] %]
</tr> </tr>
......
...@@ -552,7 +552,7 @@ ...@@ -552,7 +552,7 @@
[% INCLUDE bug/field.html.tmpl [% INCLUDE bug/field.html.tmpl
bug = bug, field = bug_fields.keywords, value = bug.keywords bug = bug, field = bug_fields.keywords, value = bug.keywords
editable = bug.check_can_change_field("keywords", 0, 1), editable = bug.check_can_change_field("keywords", 0, 1),
desc_url = "describekeywords.cgi", possible_values = all_keywords desc_url = "describekeywords.cgi", possible_values = active_keywords
%] %]
</tr> </tr>
[% END %] [% END %]
......
...@@ -1452,7 +1452,7 @@ ...@@ -1452,7 +1452,7 @@
Either you mis-typed the name or that user has not yet registered Either you mis-typed the name or that user has not yet registered
for a [% terms.Bugzilla %] account. for a [% terms.Bugzilla %] account.
[% ELSIF class == "Bugzilla::Keyword" %] [% ELSIF class == "Bugzilla::Keyword" %]
See the list of available <a href="describekeywords.cgi">keywords</a>. See the list of available <a href="describekeywords.cgi?show_inactive_keywords=1">keywords</a>.
[% END %] [% END %]
[% ELSIF error == "old_password_incorrect" %] [% ELSIF error == "old_password_incorrect" %]
......
...@@ -18,36 +18,67 @@ ...@@ -18,36 +18,67 @@
title = "$terms.Bugzilla Keyword Descriptions" title = "$terms.Bugzilla Keyword Descriptions"
style_urls = ['skins/standard/admin.css'] style_urls = ['skins/standard/admin.css']
%] %]
[% cgi = Bugzilla.cgi %]
[% show_inactive_keywords = cgi.param("show_inactive_keywords") %]
<table id="admin_table"> <script>
$(document).ready(function () {
var show_inactive_keywords = [% show_inactive_keywords ? "true" : "false" FILTER none %];
link = $("#keywords_show_hide"),
rows = $("tr.keyword_inactive");
link.click(function (event) {
if (show_inactive_keywords) {
show_inactive_keywords = false;
rows.show();
link.html("Hide inactive keywords");
}
else {
show_inactive_keywords = true;
rows.hide();
link.html("Show inactive keywords");
}
event.preventDefault();
}).click();
});
</script>
<p>
<a href="[% urlbase FILTER html %]?show_inactive_keywords=[% show_inactive_keywords ? "1" : "0" FILTER none %]"
id="keywords_show_hide">[% show_inactive_keywords ? "Show" : "Hide" FILTER html %] inactive keywords</a>
</p>
<table id="admin_table" class="describe_keywords">
<tr class="column_header"> <tr class="column_header">
<th>Name</th> <th>Name</th>
<th>Description</th> <th>Description</th>
<th>Active</th>
<th>Open [% terms.Bugs %]</th> <th>Open [% terms.Bugs %]</th>
<th>Total [% terms.Bugs %]</th> <th>Total [% terms.Bugs %]</th>
</tr> </tr>
[% FOREACH keyword = keywords %] [% FOREACH keyword = keywords %]
<tr id="[% keyword.name FILTER html %]"> <tr id="[% keyword.name FILTER html %]" class="[% keyword.is_active ? "keyword_active" : "keyword_inactive" FILTER html %]">
<td>[% keyword.name FILTER html %]</td> <td>[% keyword.name FILTER html %]</td>
<td>[% keyword.description FILTER html_light %]</td> <td>[% keyword.description FILTER html_light %]</td>
<td class="center"> <td>[% keyword.is_active ? "Yes" : "No" FILTER html %]</td>
[% IF keyword.bug_count > 0 %] <td class="center">
<a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]&amp;resolution=---"> [% IF keyword.bug_count > 0 %]
Search</a> <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]&amp;resolution=---">
[% ELSE %] Search</a>
none [% ELSE %]
[% END %] none
</td> [% END %]
<td class="right"> </td>
[% IF keyword.bug_count > 0 %] <td class="right">
<a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]"> [% IF keyword.bug_count > 0 %]
[% keyword.bug_count %]</a> <a href="buglist.cgi?keywords=[% keyword.name FILTER uri %]">
[% ELSE %] [% keyword.bug_count %]</a>
none [% ELSE %]
[% END %] none
</td> [% END %]
</tr> </td>
</tr>
[% END %] [% END %]
</table> </table>
......
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