Commit d0002e96 authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 415541: Implement $bug->set_flags() and $attachment->set_flags() - Patch by…

Bug 415541: Implement $bug->set_flags() and $attachment->set_flags() - Patch by Fré©ric Buclin <LpSolit@gmail.com> a=LpSolit
parent 8b2db148
...@@ -101,7 +101,6 @@ use constant UPDATE_COLUMNS => qw( ...@@ -101,7 +101,6 @@ use constant UPDATE_COLUMNS => qw(
ispatch ispatch
isprivate isprivate
mimetype mimetype
modification_time
); );
use constant VALIDATORS => { use constant VALIDATORS => {
...@@ -445,9 +444,9 @@ flags that have been set on the attachment ...@@ -445,9 +444,9 @@ flags that have been set on the attachment
sub flags { sub flags {
my $self = shift; my $self = shift;
return $self->{flags} if exists $self->{flags};
$self->{flags} = Bugzilla::Flag->match({ 'attach_id' => $self->id }); # Don't cache it as it must be in sync with ->flag_types.
$self->{flags} = [map { @{$_->{flags}} } @{$self->flag_types}];
return $self->{flags}; return $self->{flags};
} }
...@@ -471,7 +470,7 @@ sub flag_types { ...@@ -471,7 +470,7 @@ sub flag_types {
component_id => $self->bug->component_id, component_id => $self->bug->component_id,
attach_id => $self->id }; attach_id => $self->id };
$self->{flag_types} = Bugzilla::Flag::_flag_types($vars); $self->{flag_types} = Bugzilla::Flag->_flag_types($vars);
return $self->{flag_types}; return $self->{flag_types};
} }
...@@ -482,10 +481,34 @@ sub flag_types { ...@@ -482,10 +481,34 @@ sub flag_types {
sub set_content_type { $_[0]->set('mimetype', $_[1]); } sub set_content_type { $_[0]->set('mimetype', $_[1]); }
sub set_description { $_[0]->set('description', $_[1]); } sub set_description { $_[0]->set('description', $_[1]); }
sub set_filename { $_[0]->set('filename', $_[1]); } sub set_filename { $_[0]->set('filename', $_[1]); }
sub set_is_obsolete { $_[0]->set('isobsolete', $_[1]); }
sub set_is_patch { $_[0]->set('ispatch', $_[1]); } sub set_is_patch { $_[0]->set('ispatch', $_[1]); }
sub set_is_private { $_[0]->set('isprivate', $_[1]); } sub set_is_private { $_[0]->set('isprivate', $_[1]); }
sub set_is_obsolete {
my ($self, $obsolete) = @_;
my $old = $self->isobsolete;
$self->set('isobsolete', $obsolete);
my $new = $self->isobsolete;
# If the attachment is being marked as obsolete, cancel pending requests.
if ($new && $old != $new) {
my @requests = grep { $_->status eq '?' } @{$self->flags};
return unless scalar @requests;
my %flag_ids = map { $_->id => 1 } @requests;
foreach my $flagtype (@{$self->flag_types}) {
@{$flagtype->{flags}} = grep { !$flag_ids{$_->id} } @{$flagtype->{flags}};
}
}
}
sub set_flags {
my ($self, $flags, $new_flags) = @_;
Bugzilla::Flag->set_flag($self, $_) foreach (@$flags, @$new_flags);
}
sub _check_bug { sub _check_bug {
my ($invocant, $bug) = @_; my ($invocant, $bug) = @_;
my $user = Bugzilla->user; my $user = Bugzilla->user;
...@@ -799,7 +822,7 @@ Params: takes a hashref with the following keys: ...@@ -799,7 +822,7 @@ Params: takes a hashref with the following keys:
parameter has no effect. parameter has no effect.
C<mimetype> - string - a valid MIME type. C<mimetype> - string - a valid MIME type.
C<creation_ts> - string (optional) - timestamp of the insert C<creation_ts> - string (optional) - timestamp of the insert
as returned by SELECT NOW(). as returned by SELECT LOCALTIMESTAMP(0).
C<ispatch> - boolean (optional, default false) - true if the C<ispatch> - boolean (optional, default false) - true if the
attachment is a patch. attachment is a patch.
C<isprivate> - boolean (optional, default false) - true if C<isprivate> - boolean (optional, default false) - true if
...@@ -887,7 +910,7 @@ sub run_create_validators { ...@@ -887,7 +910,7 @@ sub run_create_validators {
$params->{ispatch} = $params->{ispatch} ? 1 : 0; $params->{ispatch} = $params->{ispatch} ? 1 : 0;
$params->{filename} = $class->_check_filename($params->{filename}, $params->{isurl}); $params->{filename} = $class->_check_filename($params->{filename}, $params->{isurl});
$params->{mimetype} = $class->_check_content_type($params->{mimetype}); $params->{mimetype} = $class->_check_content_type($params->{mimetype});
$params->{creation_ts} ||= Bugzilla->dbh->selectrow_array('SELECT NOW()'); $params->{creation_ts} ||= Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
$params->{modification_time} = $params->{creation_ts}; $params->{modification_time} = $params->{creation_ts};
$params->{submitter_id} = Bugzilla->user->id || ThrowCodeError('invalid_user'); $params->{submitter_id} = Bugzilla->user->id || ThrowCodeError('invalid_user');
...@@ -898,14 +921,14 @@ sub update { ...@@ -898,14 +921,14 @@ sub update {
my $self = shift; my $self = shift;
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $user = Bugzilla->user; my $user = Bugzilla->user;
my $bug = $self->bug; my $timestamp = shift || $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
my $timestamp = shift || $dbh->selectrow_array('SELECT NOW()');
$self->{modification_time} = $timestamp;
my ($changes, $old_self) = $self->SUPER::update(@_); my ($changes, $old_self) = $self->SUPER::update(@_);
# Ignore this change.
delete $changes->{modification_time}; my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_self, $timestamp);
if ($removed || $added) {
$changes->{'flagtypes.name'} = [$removed, $added];
}
# Record changes in the activity table. # Record changes in the activity table.
my $sth = $dbh->prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, my $sth = $dbh->prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
...@@ -914,14 +937,17 @@ sub update { ...@@ -914,14 +937,17 @@ sub update {
foreach my $field (keys %$changes) { foreach my $field (keys %$changes) {
my $change = $changes->{$field}; my $change = $changes->{$field};
my $fieldid = get_field_id("attachments.$field"); $field = "attachments.$field" unless $field eq "flagtypes.name";
$sth->execute($bug->id, $self->id, $user->id, $timestamp, my $fieldid = get_field_id($field);
$sth->execute($self->bug_id, $self->id, $user->id, $timestamp,
$fieldid, $change->[0], $change->[1]); $fieldid, $change->[0], $change->[1]);
} }
if (scalar(keys %$changes)) { if (scalar(keys %$changes)) {
$dbh->do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?',
undef, ($timestamp, $self->id));
$dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?', $dbh->do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
undef, $timestamp, $bug->id); undef, ($timestamp, $self->bug_id));
} }
return $changes; return $changes;
......
...@@ -590,7 +590,7 @@ sub run_create_validators { ...@@ -590,7 +590,7 @@ sub run_create_validators {
# Callers cannot set Reporter, currently. # Callers cannot set Reporter, currently.
$params->{reporter} = $class->_check_reporter(); $params->{reporter} = $class->_check_reporter();
$params->{creation_ts} ||= Bugzilla->dbh->selectrow_array('SELECT NOW()'); $params->{creation_ts} ||= Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
$params->{delta_ts} = $params->{creation_ts}; $params->{delta_ts} = $params->{creation_ts};
if ($params->{estimated_time}) { if ($params->{estimated_time}) {
...@@ -646,7 +646,7 @@ sub update { ...@@ -646,7 +646,7 @@ sub update {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
# XXX This is just a temporary hack until all updating happens # XXX This is just a temporary hack until all updating happens
# inside this function. # inside this function.
my $delta_ts = shift || $dbh->selectrow_array("SELECT NOW()"); my $delta_ts = shift || $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
my ($changes, $old_bug) = $self->SUPER::update(@_); my ($changes, $old_bug) = $self->SUPER::update(@_);
...@@ -774,7 +774,13 @@ sub update { ...@@ -774,7 +774,13 @@ sub update {
$changes->{'bug_group'} = [join(', ', @removed_names), $changes->{'bug_group'} = [join(', ', @removed_names),
join(', ', @added_names)]; join(', ', @added_names)];
} }
# Flags
my ($removed, $added) = Bugzilla::Flag->update_flags($self, $old_bug, $delta_ts);
if ($removed || $added) {
$changes->{'flagtypes.name'} = [$removed, $added];
}
# Comments # Comments
foreach my $comment (@{$self->{added_comments} || []}) { foreach my $comment (@{$self->{added_comments} || []}) {
my $columns = join(',', keys %$comment); my $columns = join(',', keys %$comment);
...@@ -1931,6 +1937,11 @@ sub set_dup_id { ...@@ -1931,6 +1937,11 @@ sub set_dup_id {
} }
sub set_estimated_time { $_[0]->set('estimated_time', $_[1]); } sub set_estimated_time { $_[0]->set('estimated_time', $_[1]); }
sub _set_everconfirmed { $_[0]->set('everconfirmed', $_[1]); } sub _set_everconfirmed { $_[0]->set('everconfirmed', $_[1]); }
sub set_flags {
my ($self, $flags, $new_flags) = @_;
Bugzilla::Flag->set_flag($self, $_) foreach (@$flags, @$new_flags);
}
sub set_op_sys { $_[0]->set('op_sys', $_[1]); } sub set_op_sys { $_[0]->set('op_sys', $_[1]); }
sub set_platform { $_[0]->set('rep_platform', $_[1]); } sub set_platform { $_[0]->set('rep_platform', $_[1]); }
sub set_priority { $_[0]->set('priority', $_[1]); } sub set_priority { $_[0]->set('priority', $_[1]); }
...@@ -2632,10 +2643,18 @@ sub flag_types { ...@@ -2632,10 +2643,18 @@ sub flag_types {
component_id => $self->{component_id}, component_id => $self->{component_id},
bug_id => $self->bug_id }; bug_id => $self->bug_id };
$self->{'flag_types'} = Bugzilla::Flag::_flag_types($vars); $self->{'flag_types'} = Bugzilla::Flag->_flag_types($vars);
return $self->{'flag_types'}; return $self->{'flag_types'};
} }
sub flags {
my $self = shift;
# Don't cache it as it must be in sync with ->flag_types.
$self->{flags} = [map { @{$_->{flags}} } @{$self->flag_types}];
return $self->{flags};
}
sub isopened { sub isopened {
my $self = shift; my $self = shift;
return is_open_state($self->{bug_status}) ? 1 : 0; return is_open_state($self->{bug_status}) ? 1 : 0;
......
...@@ -377,7 +377,7 @@ Params: ...@@ -377,7 +377,7 @@ Params:
=head2 flag-end_of_update =head2 flag-end_of_update
This happens at the end of L<Bugzilla::Flag/process>, after all other changes This happens at the end of L<Bugzilla::Flag/update_flags>, after all other changes
are made to the database and after emails are sent. It gives you a before/after are made to the database and after emails are sent. It gives you a before/after
snapshot of flags so you can react to specific flag changes. snapshot of flags so you can react to specific flag changes.
This generally occurs inside a database transaction. This generally occurs inside a database transaction.
...@@ -389,7 +389,7 @@ Params: ...@@ -389,7 +389,7 @@ Params:
=over =over
=item C<bug> - The changed bug object. =item C<object> - The changed bug or attachment object.
=item C<timestamp> - The timestamp used for all updates in this transaction. =item C<timestamp> - The timestamp used for all updates in this transaction.
......
...@@ -469,26 +469,16 @@ sub insert { ...@@ -469,26 +469,16 @@ sub insert {
store_in_file => scalar $cgi->param('bigfile'), store_in_file => scalar $cgi->param('bigfile'),
}); });
Bugzilla::Flag->set_flags($bug, $attachment, $timestamp, $vars);
my $fieldid = get_field_id('attachments.isobsolete');
foreach my $obsolete_attachment (@obsolete_attachments) { foreach my $obsolete_attachment (@obsolete_attachments) {
# If the obsolete attachment has request flags, cancel them. $obsolete_attachment->set_is_obsolete(1);
# This call must be done before updating the 'attachments' table. $obsolete_attachment->update($timestamp);
Bugzilla::Flag->CancelRequests($bug, $obsolete_attachment, $timestamp);
$dbh->do('UPDATE attachments SET isobsolete = 1, modification_time = ?
WHERE attach_id = ?',
undef, ($timestamp, $obsolete_attachment->id));
$dbh->do('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
fieldid, removed, added)
VALUES (?,?,?,?,?,?,?)',
undef, ($bug->bug_id, $obsolete_attachment->id, $user->id,
$timestamp, $fieldid, 0, 1));
} }
my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi(
$bug, $attachment, $vars, SKIP_REQUESTEE_ON_ERROR);
$attachment->set_flags($flags, $new_flags);
$attachment->update($timestamp);
# Insert a comment about the new attachment into the database. # Insert a comment about the new attachment into the database.
my $comment = "Created an attachment (id=" . $attachment->id . ")\n" . my $comment = "Created an attachment (id=" . $attachment->id . ")\n" .
$attachment->description . "\n"; $attachment->description . "\n";
...@@ -627,27 +617,18 @@ sub update { ...@@ -627,27 +617,18 @@ sub update {
$bug->add_comment($comment, { isprivate => $attachment->isprivate }); $bug->add_comment($comment, { isprivate => $attachment->isprivate });
} }
# The order of these function calls is important, as Flag::validate my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi($bug, $attachment, $vars);
# assumes User::match_field has ensured that the values in the $attachment->set_flags($flags, $new_flags);
# requestee fields are legitimate user email addresses.
Bugzilla::User::match_field($cgi, {
'^requestee(_type)?-(\d+)$' => { 'type' => 'multi' }
});
Bugzilla::Flag::validate($bug->id, $attachment->id);
# Figure out when the changes were made. # Figure out when the changes were made.
my ($timestamp) = $dbh->selectrow_array("SELECT NOW()"); my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
# Update flags. We have to do this before committing changes
# to attachments so that we can delete pending requests if the user
# is obsoleting this attachment without deleting any requests
# the user submits at the same time.
Bugzilla::Flag->process($bug, $attachment, $timestamp, $vars);
$attachment->update($timestamp); my $changes = $attachment->update($timestamp);
# If there are changes, we updated delta_ts in the DB. We have to
# reflect this change in the bug object.
$bug->{delta_ts} = $timestamp if scalar(keys %$changes);
# Commit the comment, if any. # Commit the comment, if any.
$bug->update(); $bug->update($timestamp);
# Commit the transaction now that we are finished updating the database. # Commit the transaction now that we are finished updating the database.
$dbh->bz_commit_transaction(); $dbh->bz_commit_transaction();
......
...@@ -413,11 +413,7 @@ sub update { ...@@ -413,11 +413,7 @@ sub update {
WHERE flags.type_id = ? WHERE flags.type_id = ?
AND i.type_id IS NULL', AND i.type_id IS NULL',
undef, $id); undef, $id);
my $flags = Bugzilla::Flag->new_from_list($flag_ids); Bugzilla::Flag->force_retarget($flag_ids);
foreach my $flag (@$flags) {
my $bug = new Bugzilla::Bug($flag->bug_id);
Bugzilla::Flag::clear($flag, $bug, $flag->attachment);
}
$flag_ids = $dbh->selectcol_arrayref('SELECT DISTINCT flags.id $flag_ids = $dbh->selectcol_arrayref('SELECT DISTINCT flags.id
FROM flags FROM flags
...@@ -431,11 +427,7 @@ sub update { ...@@ -431,11 +427,7 @@ sub update {
AND (bugs.component_id = e.component_id AND (bugs.component_id = e.component_id
OR e.component_id IS NULL)', OR e.component_id IS NULL)',
undef, $id); undef, $id);
$flags = Bugzilla::Flag->new_from_list($flag_ids); Bugzilla::Flag->force_retarget($flag_ids);
foreach my $flag (@$flags) {
my $bug = new Bugzilla::Bug($flag->bug_id);
Bugzilla::Flag::clear($flag, $bug, $flag->attachment);
}
# Now silently remove requestees from flags which are no longer # Now silently remove requestees from flags which are no longer
# specifically requestable. # specifically requestable.
......
...@@ -481,35 +481,36 @@ if ($action eq 'search') { ...@@ -481,35 +481,36 @@ if ($action eq 'search') {
my $sth_set_bug_timestamp = my $sth_set_bug_timestamp =
$dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?'); $dbh->prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
# Reference removals which need LogActivityEntry. my $sth_updateFlag = $dbh->prepare('INSERT INTO bugs_activity
my $statement_flagupdate = 'UPDATE flags set requestee_id = NULL (bug_id, attach_id, who, bug_when, fieldid, removed, added)
WHERE bug_id = ? VALUES (?, ?, ?, ?, ?, ?, ?)');
AND attach_id %s
AND requestee_id = ?'; # Flags
my $sth_flagupdate_attachment = my $flag_ids =
$dbh->prepare(sprintf($statement_flagupdate, '= ?')); $dbh->selectcol_arrayref('SELECT id FROM flags WHERE requestee_id = ?',
my $sth_flagupdate_bug = undef, $otherUserID);
$dbh->prepare(sprintf($statement_flagupdate, 'IS NULL'));
my $flags = Bugzilla::Flag->new_from_list($flag_ids);
my $buglist = $dbh->selectall_arrayref('SELECT DISTINCT bug_id, attach_id
FROM flags $dbh->do('UPDATE flags SET requestee_id = NULL, modification_date = ?
WHERE requestee_id = ?', WHERE requestee_id = ?', undef, ($timestamp, $otherUserID));
undef, $otherUserID);
# We want to remove the requestee but leave the requester alone,
foreach (@$buglist) { # so we have to log these changes manually.
my ($bug_id, $attach_id) = @$_; my %bugs;
my @old_summaries = Bugzilla::Flag->snapshot($bug_id, $attach_id); push(@{$bugs{$_->bug_id}->{$_->attach_id || 0}}, $_) foreach @$flags;
if ($attach_id) { my $fieldid = get_field_id('flagtypes.name');
$sth_flagupdate_attachment->execute($bug_id, $attach_id, $otherUserID); foreach my $bug_id (keys %bugs) {
foreach my $attach_id (keys %{$bugs{$bug_id}}) {
my @old_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id});
$_->_set_requestee() foreach @{$bugs{$bug_id}->{$attach_id}};
my @new_summaries = Bugzilla::Flag->snapshot($bugs{$bug_id}->{$attach_id});
my ($removed, $added) =
Bugzilla::Flag->update_activity(\@old_summaries, \@new_summaries);
$sth_updateFlag->execute($bug_id, $attach_id || undef, $userid,
$timestamp, $fieldid, $removed, $added);
} }
else { $sth_set_bug_timestamp->execute($timestamp, $bug_id);
$sth_flagupdate_bug->execute($bug_id, $otherUserID);
}
my @new_summaries = Bugzilla::Flag->snapshot($bug_id, $attach_id);
# Let update_activity do all the dirty work, including setting
# the bug timestamp.
Bugzilla::Flag::update_activity($bug_id, $attach_id, $timestamp,
\@old_summaries, \@new_summaries);
$updatedbugs{$bug_id} = 1; $updatedbugs{$bug_id} = 1;
} }
...@@ -536,9 +537,8 @@ if ($action eq 'search') { ...@@ -536,9 +537,8 @@ if ($action eq 'search') {
($otherUserID, $otherUserID)); ($otherUserID, $otherUserID));
# Deletions in referred tables which need LogActivityEntry. # Deletions in referred tables which need LogActivityEntry.
$buglist = $dbh->selectcol_arrayref('SELECT bug_id FROM cc my $buglist = $dbh->selectcol_arrayref('SELECT bug_id FROM cc WHERE who = ?',
WHERE who = ?', undef, $otherUserID);
undef, $otherUserID);
$dbh->do('DELETE FROM cc WHERE who = ?', undef, $otherUserID); $dbh->do('DELETE FROM cc WHERE who = ?', undef, $otherUserID);
foreach my $bug_id (@$buglist) { foreach my $bug_id (@$buglist) {
LogActivityEntry($bug_id, 'cc', $otherUser->login, '', $userid, LogActivityEntry($bug_id, 'cc', $otherUser->login, '', $userid,
......
...@@ -26,15 +26,15 @@ use Bugzilla::Util qw(diff_arrays); ...@@ -26,15 +26,15 @@ use Bugzilla::Util qw(diff_arrays);
# This code doesn't actually *do* anything, it's just here to show you # This code doesn't actually *do* anything, it's just here to show you
# how to use this hook. # how to use this hook.
my $args = Bugzilla->hook_args; my $args = Bugzilla->hook_args;
my ($bug, $timestamp, $old_flags, $new_flags) = my ($object, $timestamp, $old_flags, $new_flags) =
@$args{qw(bug timestamp old_flags new_flags)}; @$args{qw(object timestamp old_flags new_flags)};
my ($removed, $added) = diff_arrays($old_flags, $new_flags); my ($removed, $added) = diff_arrays($old_flags, $new_flags);
my ($granted, $denied) = (0, 0); my ($granted, $denied) = (0, 0);
foreach my $new_flag (@$added) { foreach my $new_flag (@$added) {
$granted++ if $new_flag =~ /\+$/; $granted++ if $new_flag =~ /\+$/;
$denied++ if $new_flag =~ /-$/; $denied++ if $new_flag =~ /-$/;
} }
my $bug_id = $bug->id; my $bug_id = (ref $object eq 'Bugzilla::Bug') ? $object->id : $object->bug_id;
my $result = "$granted flags were granted and $denied flags were denied" my $result = "$granted flags were granted and $denied flags were denied"
. " on bug $bug_id at $timestamp."; . " on bug $bug_id at $timestamp.";
# Uncomment this line to see $result in your webserver's error log whenever # Uncomment this line to see $result in your webserver's error log whenever
......
...@@ -104,7 +104,7 @@ if (defined $cgi->param('maketemplate')) { ...@@ -104,7 +104,7 @@ if (defined $cgi->param('maketemplate')) {
umask 0; umask 0;
# get current time # get current time
my $timestamp = $dbh->selectrow_array(q{SELECT NOW()}); my $timestamp = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
# Group Validation # Group Validation
my @selected_groups; my @selected_groups;
...@@ -219,7 +219,10 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl')) { ...@@ -219,7 +219,10 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl')) {
if ($attachment) { if ($attachment) {
# Set attachment flags. # Set attachment flags.
Bugzilla::Flag->set_flags($bug, $attachment, $timestamp, $vars); my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi(
$bug, $attachment, $vars, SKIP_REQUESTEE_ON_ERROR);
$attachment->set_flags($flags, $new_flags);
$attachment->update($timestamp);
# Update the comment to include the new attachment ID. # Update the comment to include the new attachment ID.
# This string is hardcoded here because Template::quoteUrls() # This string is hardcoded here because Template::quoteUrls()
...@@ -246,7 +249,10 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl')) { ...@@ -246,7 +249,10 @@ if (defined($cgi->upload('data')) || $cgi->param('attachurl')) {
} }
# Set bug flags. # Set bug flags.
Bugzilla::Flag->set_flags($bug, undef, $timestamp, $vars); my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi($bug, undef, $vars,
SKIP_REQUESTEE_ON_ERROR);
$bug->set_flags($flags, $new_flags);
$bug->update($timestamp);
# Email everyone the details of the new bug # Email everyone the details of the new bug
$vars->{'mailrecipients'} = {'changer' => $user->login}; $vars->{'mailrecipients'} = {'changer' => $user->login};
......
...@@ -143,22 +143,13 @@ if (defined $cgi->param('dontchange')) { ...@@ -143,22 +143,13 @@ if (defined $cgi->param('dontchange')) {
} }
# do a match on the fields if applicable # do a match on the fields if applicable
Bugzilla::User::match_field($cgi, {
# The order of these function calls is important, as Flag::validate
# assumes User::match_field has ensured that the values
# in the requestee fields are legitimate user email addresses.
&Bugzilla::User::match_field($cgi, {
'qa_contact' => { 'type' => 'single' }, 'qa_contact' => { 'type' => 'single' },
'newcc' => { 'type' => 'multi' }, 'newcc' => { 'type' => 'multi' },
'masscc' => { 'type' => 'multi' }, 'masscc' => { 'type' => 'multi' },
'assigned_to' => { 'type' => 'single' }, 'assigned_to' => { 'type' => 'single' },
'^requestee(_type)?-(\d+)$' => { 'type' => 'multi' },
}); });
# Validate flags in all cases. validate() should not detect any
# reference to flags if $cgi->param('id') is undefined.
Bugzilla::Flag::validate($cgi->param('id'));
print $cgi->header() unless Bugzilla->usage_mode == USAGE_MODE_EMAIL; print $cgi->header() unless Bugzilla->usage_mode == USAGE_MODE_EMAIL;
# Check for a mid-air collision. Currently this only works when updating # Check for a mid-air collision. Currently this only works when updating
...@@ -280,6 +271,12 @@ foreach my $bug (@bug_objects) { ...@@ -280,6 +271,12 @@ foreach my $bug (@bug_objects) {
$product_change ||= $changed; $product_change ||= $changed;
} }
# Flags should be set AFTER the bug has been moved into another product/component.
if ($cgi->param('id')) {
my ($flags, $new_flags) = Bugzilla::Flag->extract_flags_from_cgi($first_bug, undef, $vars);
$first_bug->set_flags($flags, $new_flags);
}
if ($cgi->param('id') && (defined $cgi->param('dependson') if ($cgi->param('id') && (defined $cgi->param('dependson')
|| defined $cgi->param('blocked')) ) || defined $cgi->param('blocked')) )
{ {
...@@ -586,9 +583,6 @@ foreach my $bug (@bug_objects) { ...@@ -586,9 +583,6 @@ foreach my $bug (@bug_objects) {
CheckIfVotedConfirmed($bug->id); CheckIfVotedConfirmed($bug->id);
} }
# Set and update flags.
Bugzilla::Flag->process($bug, undef, $timestamp, $vars);
$dbh->bz_commit_transaction(); $dbh->bz_commit_transaction();
############### ###############
......
...@@ -222,15 +222,10 @@ ...@@ -222,15 +222,10 @@
but you tried to flag it as obsolete while creating a new attachment to but you tried to flag it as obsolete while creating a new attachment to
[% terms.bug %] [%+ my_bug_id FILTER html %]. [% terms.bug %] [%+ my_bug_id FILTER html %].
[% ELSIF error == "flags_not_available" %] [% ELSIF error == "flag_unexpected_object" %]
[% title = "Flag Editing not Allowed" %] [% title = "Object Not Recognized" %]
[% IF type == "b" %] Flags cannot be set for objects of type [% caller FILTER html %].
Flags cannot be set or changed when They can only be set for [% terms.bugs %] and attachments.
changing several [% terms.bugs %] at once.
[% ELSE %]
References to existing flags when creating
a new attachment are invalid.
[% END %]
[% ELSIF error == "flag_requestee_disabled" %] [% ELSIF error == "flag_requestee_disabled" %]
[% title = "Flag not Requestable from Specific Person" %] [% title = "Flag not Requestable from Specific Person" %]
......
...@@ -568,12 +568,6 @@ ...@@ -568,12 +568,6 @@
<br>Alternately, if your attachment is an image, you could convert <br>Alternately, if your attachment is an image, you could convert
it to a compressible format like JPG or PNG and try again. it to a compressible format like JPG or PNG and try again.
[% ELSIF error == "flag_not_multiplicable" %]
[% docslinks = {'flags-overview.html' => 'An overview on Flags',
'flags.html' => 'Using Flags'} %]
You can't ask more than one person at a time for
<em>[% type.name FILTER html %]</em>.
[% ELSIF error == "flag_requestee_needs_privs" %] [% ELSIF error == "flag_requestee_needs_privs" %]
[% title = "Flag Requestee Needs Privileges" %] [% title = "Flag Requestee Needs Privileges" %]
[% requestee.identity FILTER html %] does not have permission to set the [% requestee.identity FILTER html %] does not have permission to set the
...@@ -632,6 +626,12 @@ ...@@ -632,6 +626,12 @@
The name <em>[% name FILTER html %]</em> must be 1-50 characters long The name <em>[% name FILTER html %]</em> must be 1-50 characters long
and must not contain any spaces or commas. and must not contain any spaces or commas.
[% ELSIF error == "flag_type_not_multiplicable" %]
[% docslinks = {'flags-overview.html' => 'An overview on Flags',
'flags.html' => 'Using Flags'} %]
You cannot have several <em>[% type.name FILTER html %]</em> flags
for this [% IF attachment %] attachment [% ELSE %] [%+ terms.bug %] [% END %].
[% ELSIF error == "flag_update_denied" %] [% ELSIF error == "flag_update_denied" %]
[% title = "Flag Modification Denied" %] [% title = "Flag Modification Denied" %]
[% admindocslinks = {'flags-overview.html#flags-admin' => 'Administering Flags', [% admindocslinks = {'flags-overview.html#flags-admin' => 'Administering Flags',
...@@ -1158,9 +1158,11 @@ ...@@ -1158,9 +1158,11 @@
[% ELSIF error == "no_bugs_in_list" %] [% ELSIF error == "no_bugs_in_list" %]
[% title = "Delete Tag?" %] [% title = "Delete Tag?" %]
This will remove all [% terms.bugs %] from the This will remove all [% terms.bugs %] from the
[% tag FILTER html %] tag. This will delete the tag completely. Click <em>[% name FILTER html %]</em> tag. This will delete the tag completely. Click
<a href="buglist.cgi?cmdtype=dorem&amp;remaction=forget&amp;namedcmd= <a href="buglist.cgi?cmdtype=dorem&amp;remaction=forget&amp;namedcmd=
[%- tag FILTER url_quote %]">here</a> if you really want to delete it. [%- name FILTER url_quote %]&amp;token=
[%- issue_hash_token([query_id, name]) FILTER url_quote %]">here</a>
if you really want to delete it.
[% ELSIF error == "no_bugs_to_remove" %] [% ELSIF error == "no_bugs_to_remove" %]
[% title = "No Tag Selected" %] [% title = "No Tag Selected" %]
...@@ -1742,6 +1744,10 @@ ...@@ -1742,6 +1744,10 @@
milestone milestone
[% ELSIF class == "Bugzilla::Status" %] [% ELSIF class == "Bugzilla::Status" %]
status status
[% ELSIF class == "Bugzilla::Flag" %]
flag
[% ELSIF class == "Bugzilla::FlagType" %]
flagtype
[% ELSIF class == "Bugzilla::Field" %] [% ELSIF class == "Bugzilla::Field" %]
field field
[% ELSIF ( matches = class.match('^Bugzilla::Field::Choice::(.+)') ) %] [% ELSIF ( matches = class.match('^Bugzilla::Field::Choice::(.+)') ) %]
......
...@@ -24,28 +24,31 @@ ...@@ -24,28 +24,31 @@
[% bugidsummary = bug.bug_id _ ': ' _ bug.short_desc %] [% bugidsummary = bug.bug_id _ ': ' _ bug.short_desc %]
[% attidsummary = attachment.id _ ': ' _ attachment.description %] [% attidsummary = attachment.id _ ': ' _ attachment.description %]
[% flagtype_name = flag ? flag.type.name : old_flag.type.name %]
[% statuses = { '+' => "granted" , '-' => 'denied' , 'X' => "canceled" , [% statuses = { '+' => "granted" , '-' => 'denied' , 'X' => "canceled" ,
'?' => "asked" } %] '?' => "asked" } %]
[% to_identity = "" %] [% to_identity = "" %]
[% on_behalf_of = 0 %] [% on_behalf_of = 0 %]
[% IF flag.status == '?' %] [% action = flag.status || 'X' %]
[% IF flag && flag.status == '?' %]
[% subject_status = "requested" %] [% subject_status = "requested" %]
[% IF flag.setter.id == user.id %] [% IF flag.setter_id == user.id %]
[% to_identity = flag.requestee.identity _ " for" %] [% to_identity = flag.requestee.identity _ " for" %]
[% ELSE %] [% ELSE %]
[% on_behalf_of = 1 %] [% on_behalf_of = 1 %]
[% IF flag.requestee %][% to_identity = " to " _ flag.requestee.identity %][% END %] [% IF flag.requestee %][% to_identity = " to " _ flag.requestee.identity %][% END %]
[% END %] [% END %]
[% ELSE %] [% ELSE %]
[% IF flag.requester %] [% IF old_flag && old_flag.status == '?' %]
[% to_identity = flag.requester.identity _ "'s request for" %] [% to_identity = old_flag.setter.identity _ "'s request for" %]
[% END %] [% END %]
[% subject_status = statuses.${flag.status} %] [% subject_status = statuses.$action %]
[% END %] [% END %]
From: [% Param('mailfrom') %] From: [% Param('mailfrom') %]
To: [% to %] To: [% to %]
Subject: [% flag.type.name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %] Subject: [% flagtype_name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %]
[%- IF attachment %] : [%- IF attachment %] :
[Attachment [% attachment.id %]] [% attachment.description %][% END %] [Attachment [% attachment.id %]] [% attachment.description %][% END %]
X-Bugzilla-Type: request X-Bugzilla-Type: request
...@@ -55,10 +58,10 @@ X-Bugzilla-Type: request ...@@ -55,10 +58,10 @@ X-Bugzilla-Type: request
[%- FILTER bullet = wrap(80) -%] [%- FILTER bullet = wrap(80) -%]
[% IF on_behalf_of %] [% IF on_behalf_of %]
[% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flag.type.name %] [% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flagtype_name %]
[% to_identity %]: [% to_identity %]:
[% ELSE %] [% ELSE %]
[% user.identity %] has [% statuses.${flag.status} %] [%+ to_identity %] [%+ flag.type.name %]: [% user.identity %] has [% statuses.$action %] [%+ to_identity %] [%+ flagtype_name %]:
[% END %] [% END %]
[% terms.Bug %] [%+ bugidsummary %] [% terms.Bug %] [%+ bugidsummary %]
......
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