Commit 92c064fb authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 385379: Move dependency DB updating from process_bug into Bugzilla::Bug

Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=LpSolit
parent 96b80ae8
...@@ -506,6 +506,58 @@ sub update_cc { ...@@ -506,6 +506,58 @@ sub update_cc {
} }
# XXX Temporary hack until all of process_bug uses update() # XXX Temporary hack until all of process_bug uses update()
sub update_dependencies {
# We need to send mail for dependson/blocked bugs if the dependencies
# change or the status or resolution change. This var keeps track of that.
my $check_dep_bugs = 0;
my $self = shift;
my $dbh = Bugzilla->dbh;
my $delta_ts = shift || $dbh->selectrow_array("SELECT NOW()");
my $old_bug = $self->new($self->id);
my %changes;
foreach my $pair ([qw(dependson blocked)], [qw(blocked dependson)]) {
my ($type, $other) = @$pair;
my $old = $old_bug->$type;
my $new = $self->$type;
my ($removed, $added) = diff_arrays($old, $new);
foreach my $removed_id (@$removed) {
$dbh->do("DELETE FROM dependencies WHERE $type = ? AND $other = ?",
undef, $removed_id, $self->id);
# Add an activity entry for the other bug.
LogActivityEntry($removed_id, $other, $self->id, '',
Bugzilla->user->id, $delta_ts);
# Update delta_ts on the other bug so that we trigger mid-airs.
$dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
undef, $delta_ts, $removed_id);
}
foreach my $added_id (@$added) {
$dbh->do("INSERT INTO dependencies ($type, $other) VALUES (?,?)",
undef, $added_id, $self->id);
# Add an activity entry for the other bug.
LogActivityEntry($added_id, $other, '', $self->id,
Bugzilla->user->id, $delta_ts);
# Update delta_ts on the other bug so that we trigger mid-airs.
$dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
undef, $delta_ts, $added_id);
}
LogActivityEntry($self->id, $type, join(', ', @$removed),
join(', ', @$added), Bugzilla->user->id, $delta_ts);
$changes{$type} = [$removed, $added];
}
return \%changes;
}
# XXX Temporary hack until all of process_bug uses update()
sub update_keywords { sub update_keywords {
my $self = shift; my $self = shift;
...@@ -1096,6 +1148,16 @@ sub fields { ...@@ -1096,6 +1148,16 @@ sub fields {
# "Set" Methods # # "Set" Methods #
################# #################
sub set_dependencies {
my ($self, $dependson, $blocked) = @_;
($dependson, $blocked) = $self->_check_dependencies($dependson, $blocked);
# These may already be detainted, but all setters are supposed to
# detaint their input if they've run a validator (just as though
# we had used Bugzilla::Object::set), so we do that here.
detaint_natural($_) foreach (@$dependson, @$blocked);
$self->{'dependson'} = $dependson;
$self->{'blocked'} = $blocked;
}
sub _set_everconfirmed { $_[0]->set('everconfirmed', $_[1]); } sub _set_everconfirmed { $_[0]->set('everconfirmed', $_[1]); }
sub set_resolution { $_[0]->set('resolution', $_[1]); } sub set_resolution { $_[0]->set('resolution', $_[1]); }
sub set_status { sub set_status {
......
...@@ -166,11 +166,11 @@ $cgi->param('comment', $bug->_check_comment($cgi->param('comment'))); ...@@ -166,11 +166,11 @@ $cgi->param('comment', $bug->_check_comment($cgi->param('comment')));
# instead of throwing an error, f.e. when one or more of the values # instead of throwing an error, f.e. when one or more of the values
# is a bug alias that gets converted to its corresponding bug ID # is a bug alias that gets converted to its corresponding bug ID
# during validation. # during validation.
if ($cgi->param('id')) { if ($cgi->param('id') && (defined $cgi->param('dependson')
my ($dependson, $blocks) = $bug->_check_dependencies( || defined $cgi->param('blocked')) )
scalar $cgi->param('dependson'), scalar $cgi->param('blocked')); {
$cgi->param('dependson', $dependson); $bug->set_dependencies(scalar $cgi->param('dependson'),
$cgi->param('blocked', $blocks); scalar $cgi->param('blocked'));
} }
# Right now, you can't modify dependencies on a mass change. # Right now, you can't modify dependencies on a mass change.
else { else {
...@@ -945,34 +945,8 @@ sub SnapShotBug { ...@@ -945,34 +945,8 @@ sub SnapShotBug {
return @row; return @row;
} }
sub SnapShotDeps {
my ($bug_id, $target, $me) = (@_);
my $list = Bugzilla::Bug::EmitDependList($me, $target, $bug_id);
return join(',', @$list);
}
my $timestamp; my $timestamp;
local our $bug_changed;
sub LogDependencyActivity {
my ($i, $oldstr, $target, $me, $timestamp) = (@_);
my $dbh = Bugzilla->dbh;
my $newstr = SnapShotDeps($i, $target, $me);
if ($oldstr ne $newstr) {
# Figure out what's really different...
my ($removed, $added) = diff_strings($oldstr, $newstr);
LogActivityEntry($i,$target,$removed,$added,$whoid,$timestamp);
# update timestamp on target bug so midairs will be triggered
$dbh->do(q{UPDATE bugs SET delta_ts = ? WHERE bug_id = ?},
undef, $timestamp, $i);
$bug_changed = 1;
return 1;
}
return 0;
}
if ($prod_changed && Bugzilla->params->{"strict_isolation"}) { if ($prod_changed && Bugzilla->params->{"strict_isolation"}) {
my $sth_cc = $dbh->prepare("SELECT who my $sth_cc = $dbh->prepare("SELECT who
FROM cc FROM cc
...@@ -1094,8 +1068,7 @@ foreach my $id (@idlist) { ...@@ -1094,8 +1068,7 @@ foreach my $id (@idlist) {
$comma = ','; $comma = ',';
} }
my %dependencychanged; my $bug_changed = 0;
$bug_changed = 0;
my $write = "WRITE"; # Might want to make a param to control my $write = "WRITE"; # Might want to make a param to control
# whether we do LOW_PRIORITY ... # whether we do LOW_PRIORITY ...
$dbh->bz_lock_tables("bugs $write", "bugs_activity $write", "cc $write", $dbh->bz_lock_tables("bugs $write", "bugs_activity $write", "cc $write",
...@@ -1216,11 +1189,6 @@ foreach my $id (@idlist) { ...@@ -1216,11 +1189,6 @@ foreach my $id (@idlist) {
exit; exit;
} }
# Gather the dependency list, and make sure there are no circular refs
my %deps = Bugzilla::Bug::ValidateDependencies(scalar($cgi->param('dependson')),
scalar($cgi->param('blocked')),
$id);
# #
# Start updating the relevant database entries # Start updating the relevant database entries
# #
...@@ -1342,69 +1310,14 @@ foreach my $id (@idlist) { ...@@ -1342,69 +1310,14 @@ foreach my $id (@idlist) {
my ($cc_removed) = $bug_objects{$id}->update_cc($timestamp); my ($cc_removed) = $bug_objects{$id}->update_cc($timestamp);
$cc_removed = [map {$_->login} @$cc_removed]; $cc_removed = [map {$_->login} @$cc_removed];
my ($dep_changes) = $bug_objects{$id}->update_dependencies($timestamp);
# We need to send mail for dependson/blocked bugs if the dependencies
# change or the status or resolution change. This var keeps track of that. # Convert the "changes" hash into a list of all the bug ids, then
my $check_dep_bugs = 0; # convert that into a hash to eliminate duplicates. ("map {@$_}" collapses
# an array of arrays.)
foreach my $pair ("blocked/dependson", "dependson/blocked") { my @all_changed_deps = map { @$_ } @{$dep_changes->{'dependson'}};
my ($me, $target) = split("/", $pair); push(@all_changed_deps, map { @$_ } @{$dep_changes->{'blocked'}});
my %changed_deps = map { $_ => 1 } @all_changed_deps;
my @oldlist = @{$dbh->selectcol_arrayref("SELECT $target FROM dependencies
WHERE $me = ? ORDER BY $target",
undef, $id)};
# Only bugs depending on the current one should get notification.
# Bugs blocking the current one never get notification, unless they
# are added or removed from the dependency list. This case is treated
# below.
@dependencychanged{@oldlist} = 1 if ($me eq 'dependson');
if (defined $cgi->param($target)) {
my %snapshot;
my @newlist = sort {$a <=> $b} @{$deps{$target}};
while (0 < @oldlist || 0 < @newlist) {
if (@oldlist == 0 || (@newlist > 0 &&
$oldlist[0] > $newlist[0])) {
$snapshot{$newlist[0]} = SnapShotDeps($newlist[0], $me,
$target);
shift @newlist;
} elsif (@newlist == 0 || (@oldlist > 0 &&
$newlist[0] > $oldlist[0])) {
$snapshot{$oldlist[0]} = SnapShotDeps($oldlist[0], $me,
$target);
shift @oldlist;
} else {
if ($oldlist[0] != $newlist[0]) {
ThrowCodeError('list_comparison_error');
}
shift @oldlist;
shift @newlist;
}
}
my @keys = keys(%snapshot);
if (@keys) {
my $oldsnap = SnapShotDeps($id, $target, $me);
$dbh->do(qq{DELETE FROM dependencies WHERE $me = ?},
undef, $id);
my $sth =
$dbh->prepare(qq{INSERT INTO dependencies ($me, $target)
VALUES (?, ?)});
foreach my $i (@{$deps{$target}}) {
$sth->execute($id, $i);
}
foreach my $k (@keys) {
LogDependencyActivity($k, $snapshot{$k}, $me, $target, $timestamp);
}
LogDependencyActivity($id, $oldsnap, $target, $me, $timestamp);
$check_dep_bugs = 1;
# All bugs added or removed from the dependency list
# must be notified.
@dependencychanged{@keys} = 1;
}
}
}
# get a snapshot of the newly set values out of the database, # get a snapshot of the newly set values out of the database,
# and then generate any necessary bug activity entries by seeing # and then generate any necessary bug activity entries by seeing
...@@ -1432,7 +1345,8 @@ foreach my $id (@idlist) { ...@@ -1432,7 +1345,8 @@ foreach my $id (@idlist) {
# $msgs will store emails which have to be sent to voters, if any. # $msgs will store emails which have to be sent to voters, if any.
my $msgs; my $msgs;
my %notify_deps;
foreach my $c (@editable_bug_fields) { foreach my $c (@editable_bug_fields) {
my $col = $c; # We modify it, don't want to modify array my $col = $c; # We modify it, don't want to modify array
# values in place. # values in place.
...@@ -1483,10 +1397,12 @@ foreach my $id (@idlist) { ...@@ -1483,10 +1397,12 @@ foreach my $id (@idlist) {
CheckIfVotedConfirmed($id, $whoid); CheckIfVotedConfirmed($id, $whoid);
} }
# If this bug has changed from opened to closed or vice-versa,
# then all of the bugs we block need to be notified.
if ($col eq 'bug_status' if ($col eq 'bug_status'
&& is_open_state($old) ne is_open_state($new)) && is_open_state($old) ne is_open_state($new))
{ {
$check_dep_bugs = 1; $notify_deps{$_} = 1 foreach (@{$bug_objects{$id}->blocked});
} }
LogActivityEntry($id,$col,$old,$new,$whoid,$timestamp); LogActivityEntry($id,$col,$old,$new,$whoid,$timestamp);
...@@ -1563,18 +1479,17 @@ foreach my $id (@idlist) { ...@@ -1563,18 +1479,17 @@ foreach my $id (@idlist) {
send_results($duplicate, $vars); send_results($duplicate, $vars);
} }
if ($check_dep_bugs) { my %all_dep_changes = (%notify_deps, %changed_deps);
foreach my $k (keys(%dependencychanged)) { foreach my $id (sort { $a <=> $b } (keys %all_dep_changes)) {
$vars->{'mailrecipients'} = { 'changer' => Bugzilla->user->login }; $vars->{'mailrecipients'} = { 'changer' => Bugzilla->user->login };
$vars->{'id'} = $k; $vars->{'id'} = $id;
$vars->{'type'} = "dep"; $vars->{'type'} = "dep";
# Let the user (if he is able to see the bug) know we checked to # Let the user (if he is able to see the bug) know we checked to
# see if we should email notice of this change to users with a # see if we should email notice of this change to users with a
# relationship to the dependent bug and who did and didn't # relationship to the dependent bug and who did and didn't
# receive email about it. # receive email about it.
send_results($k, $vars); send_results($id, $vars);
}
} }
} }
......
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