summaryrefslogtreecommitdiffstats
path: root/Bugzilla
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla')
-rwxr-xr-xBugzilla/Bug.pm160
1 files changed, 129 insertions, 31 deletions
diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm
index 56018cebd..10c595d94 100755
--- a/Bugzilla/Bug.pm
+++ b/Bugzilla/Bug.pm
@@ -388,7 +388,7 @@ sub run_create_validators {
$params->{version} = $class->_check_version($product, $params->{version});
- $params->{keywords} = $class->_check_keywords($product, $params->{keywords});
+ $params->{keywords} = $class->_check_keywords($params->{keywords}, $product);
$params->{groups} = $class->_check_groups($product,
$params->{groups});
@@ -496,8 +496,8 @@ sub update_cc {
# If any changes were found, record it in the activity log
if (scalar @$removed || scalar @$added) {
- my $removed_names = join ', ', (map {$_->login} @$removed_users);
- my $added_names = join ', ', (map {$_->login} @$added_users);
+ my $removed_names = join(', ', (map {$_->login} @$removed_users));
+ my $added_names = join(', ', (map {$_->login} @$added_users));
LogActivityEntry($self->id, "cc", $removed_names, $added_names,
Bugzilla->user->id, $delta_ts);
}
@@ -505,6 +505,45 @@ sub update_cc {
return ($removed_users, $added_users);
}
+# XXX Temporary hack until all of process_bug uses update()
+sub update_keywords {
+ my $self = shift;
+
+ my $dbh = Bugzilla->dbh;
+ my $delta_ts = shift || $dbh->selectrow_array("SELECT NOW()");
+
+ my $old_bug = $self->new($self->id);
+ my @old_ids = map { $_->id } @{$old_bug->keyword_objects};
+ my @new_ids = map { $_->id } @{$self->keyword_objects};
+
+ my ($removed, $added) = diff_arrays(\@old_ids, \@new_ids);
+
+ if (scalar @$removed) {
+ $dbh->do('DELETE FROM keywords WHERE bug_id = ? AND keywordid IN ('
+ . join(',', @$removed) . ')', undef, $self->id);
+ }
+ foreach my $keyword_id (@$added) {
+ $dbh->do('INSERT INTO keywords (bug_id, keywordid) VALUES (?,?)',
+ undef, $self->id, $keyword_id);
+ }
+
+ $dbh->do('UPDATE bugs SET keywords = ? WHERE bug_id = ?', undef,
+ $self->keywords, $self->id);
+
+ my $removed_keywords = Bugzilla::Keyword->new_from_list($removed);
+ my $added_keywords = Bugzilla::Keyword->new_from_list($added);
+
+ # If any changes were found, record it in the activity log
+ if (scalar @$removed || scalar @$added) {
+ my $removed_names = join(', ', (map {$_->name} @$removed_keywords));
+ my $added_names = join(', ', (map {$_->name} @$added_keywords));
+ LogActivityEntry($self->id, "keywords", $removed_names,
+ $added_names, Bugzilla->user->id, $delta_ts);
+ }
+
+ return [$removed_keywords, $added_keywords];
+}
+
# This is the correct way to delete bugs from the DB.
# No bug should be deleted from anywhere else except from here.
#
@@ -626,9 +665,7 @@ sub _check_bug_status {
my @valid_statuses;
if (ref $invocant) {
- $invocant->{'prod_obj'} ||=
- new Bugzilla::Product({name => $invocant->product});
- $product = $invocant->{'prod_obj'};
+ $product = $invocant->product_obj;
@valid_statuses = map { $_->name } @{$invocant->status->can_change_to};
}
else {
@@ -846,11 +883,15 @@ sub _check_groups {
}
sub _check_keywords {
- my ($invocant, $product, $keyword_string) = @_;
+ my ($invocant, $keyword_string, $product) = @_;
$keyword_string = trim($keyword_string);
- return [] if (!$keyword_string
- || !Bugzilla->user->in_group('editbugs', $product->id));
-
+ return [] if !$keyword_string;
+
+ # On creation, only editbugs users can set keywords.
+ if (!ref $invocant) {
+ return [] if !Bugzilla->user->in_group('editbugs', $product->id);
+ }
+
my %keywords;
foreach my $keyword (split(/[\s,]+/, $keyword_string)) {
next unless $keyword;
@@ -1068,6 +1109,8 @@ sub set_status {
# "Add/Remove" Methods #
########################
+# These are in alphabetical order by field name.
+
# Accepts a User object or a username. Adds the user only if they
# don't already exist as a CC on the bug.
sub add_cc {
@@ -1142,6 +1185,57 @@ sub add_comment {
push(@{$self->{added_comments}}, $add_comment);
}
+# There was a lot of duplicate code when I wrote this as three separate
+# functions, so I just combined them all into one. This is also easier for
+# process_bug to use.
+sub modify_keywords {
+ my ($self, $keywords, $action) = @_;
+
+ $action ||= "makeexact";
+ if (!grep($action eq $_, qw(add delete makeexact))) {
+ $action = "makeexact";
+ }
+
+ $keywords = $self->_check_keywords($keywords);
+
+ my (@result, $any_changes);
+ if ($action eq 'makeexact') {
+ @result = @$keywords;
+ # Check if anything was added or removed.
+ my @old_ids = map { $_->id } @{$self->keyword_objects};
+ my @new_ids = map { $_->id } @result;
+ my ($removed, $added) = diff_arrays(\@old_ids, \@new_ids);
+ $any_changes = scalar @$removed || scalar @$added;
+ }
+ else {
+ # We're adding or deleting specific keywords.
+ my %keys = map {$_->id => $_} @{$self->keyword_objects};
+ if ($action eq 'add') {
+ $keys{$_->id} = $_ foreach @$keywords;
+ }
+ else {
+ delete $keys{$_->id} foreach @$keywords;
+ }
+ @result = values %keys;
+ $any_changes = scalar @$keywords;
+ }
+ # Make sure we retain the sort order.
+ @result = sort {lc($a->name) cmp lc($b->name)} @result;
+
+ if ($any_changes) {
+ my $privs;
+ my $new = join(', ', (map {$_->name} @result));
+ my $check = $self->check_can_change_field('keywords', 0, 1, \$privs)
+ || ThrowUserError('illegal_change', { field => 'keywords',
+ oldvalue => $self->keywords,
+ newvalue => $new,
+ privs => $privs });
+ }
+
+ $self->{'keyword_objects'} = \@result;
+ return $any_changes;
+}
+
#####################################################################
# Instance Accessors
#####################################################################
@@ -1339,20 +1433,20 @@ sub isunconfirmed {
sub keywords {
my ($self) = @_;
- return $self->{'keywords'} if exists $self->{'keywords'};
- return () if $self->{'error'};
+ return join(', ', (map { $_->name } @{$self->keyword_objects}));
+}
- my $dbh = Bugzilla->dbh;
- my $list_ref = $dbh->selectcol_arrayref(
- "SELECT keyworddefs.name
- FROM keyworddefs, keywords
- WHERE keywords.bug_id = ?
- AND keyworddefs.id = keywords.keywordid
- ORDER BY keyworddefs.name",
- undef, ($self->bug_id));
+# XXX At some point, this should probably replace the normal "keywords" sub.
+sub keyword_objects {
+ my $self = shift;
+ return $self->{'keyword_objects'} if defined $self->{'keyword_objects'};
+ return [] if $self->{'error'};
- $self->{'keywords'} = join(', ', @$list_ref);
- return $self->{'keywords'};
+ my $dbh = Bugzilla->dbh;
+ my $ids = $dbh->selectcol_arrayref(
+ "SELECT keywordid FROM keywords WHERE bug_id = ?", undef, $self->id);
+ $self->{'keyword_objects'} = Bugzilla::Keyword->new_from_list($ids);
+ return $self->{'keyword_objects'};
}
sub longdescs {
@@ -1368,8 +1462,7 @@ sub milestoneurl {
return $self->{'milestoneurl'} if exists $self->{'milestoneurl'};
return '' if $self->{'error'};
- $self->{'prod_obj'} ||= new Bugzilla::Product({name => $self->product});
- $self->{'milestoneurl'} = $self->{'prod_obj'}->milestone_url;
+ $self->{'milestoneurl'} = $self->product_obj->milestone_url;
return $self->{'milestoneurl'};
}
@@ -1383,6 +1476,14 @@ sub product {
return $self->{product};
}
+# XXX This should eventually replace the "product" subroutine.
+sub product_obj {
+ my $self = shift;
+ return {} if $self->{error};
+ $self->{prod_obj} ||= new Bugzilla::Product($self->{product_id});
+ return $self->{prod_obj};
+}
+
sub qa_contact {
my ($self) = @_;
return $self->{'qa_contact'} if exists $self->{'qa_contact'};
@@ -1443,10 +1544,8 @@ sub use_votes {
my ($self) = @_;
return 0 if $self->{'error'};
- $self->{'prod_obj'} ||= new Bugzilla::Product({name => $self->product});
-
return Bugzilla->params->{'usevotes'}
- && $self->{'prod_obj'}->votes_per_user > 0;
+ && $self->product_obj->votes_per_user > 0;
}
sub groups {
@@ -1549,7 +1648,6 @@ sub choices {
return {} if $self->{'error'};
$self->{'choices'} = {};
- $self->{prod_obj} ||= new Bugzilla::Product({name => $self->product});
my @prodlist = map {$_->name} @{Bugzilla->user->get_enterable_products};
# The current product is part of the popup, even if new bugs are no longer
@@ -1571,9 +1669,9 @@ sub choices {
'op_sys' => get_legal_field_values('op_sys'),
'bug_status' => get_legal_field_values('bug_status'),
'resolution' => \@res,
- 'component' => [map($_->name, @{$self->{prod_obj}->components})],
- 'version' => [map($_->name, @{$self->{prod_obj}->versions})],
- 'target_milestone' => [map($_->name, @{$self->{prod_obj}->milestones})],
+ 'component' => [map($_->name, @{$self->product_obj->components})],
+ 'version' => [map($_->name, @{$self->product_obj->versions})],
+ 'target_milestone' => [map($_->name, @{$self->product_obj->milestones})],
};
return $self->{'choices'};