Commit 6c0b6e11 authored by jouni%heikniemi.net's avatar jouni%heikniemi.net

Bug 223878: Flag system dies when changing a deleted flag.

r=joel, justdave a=justdave
parent 73fd49ff
...@@ -90,7 +90,8 @@ sub query ...@@ -90,7 +90,8 @@ sub query
$a{'datasize'}) = &::FetchSQLData(); $a{'datasize'}) = &::FetchSQLData();
# Retrieve a list of flags for this attachment. # Retrieve a list of flags for this attachment.
$a{'flags'} = Bugzilla::Flag::match({ 'attach_id' => $a{'attachid'} }); $a{'flags'} = Bugzilla::Flag::match({ 'attach_id' => $a{'attachid'},
'is_active' => 1 });
# We will display the edit link if the user can edit the attachment; # We will display the edit link if the user can edit the attachment;
# ie the are the submitter, or they have canedit. # ie the are the submitter, or they have canedit.
......
...@@ -226,7 +226,8 @@ sub initBug { ...@@ -226,7 +226,8 @@ sub initBug {
$flag_type->{'flags'} = $flag_type->{'flags'} =
Bugzilla::Flag::match({ 'bug_id' => $self->{bug_id}, Bugzilla::Flag::match({ 'bug_id' => $self->{bug_id},
'type_id' => $flag_type->{'id'}, 'type_id' => $flag_type->{'id'},
'target_type' => 'bug' }); 'target_type' => 'bug',
'is_active' => 1 });
} }
$self->{'flag_types'} = $flag_types; $self->{'flag_types'} = $flag_types;
$self->{'any_flags_requesteeble'} = grep($_->{'is_requesteeble'}, @$flag_types); $self->{'any_flags_requesteeble'} = grep($_->{'is_requesteeble'}, @$flag_types);
...@@ -238,11 +239,11 @@ sub initBug { ...@@ -238,11 +239,11 @@ sub initBug {
my $num_attachment_flag_types = my $num_attachment_flag_types =
Bugzilla::FlagType::count({ 'target_type' => 'attachment', Bugzilla::FlagType::count({ 'target_type' => 'attachment',
'product_id' => $self->{'product_id'}, 'product_id' => $self->{'product_id'},
'component_id' => $self->{'component_id'}, 'component_id' => $self->{'component_id'} });
'is_active' => 1 });
my $num_attachment_flags = my $num_attachment_flags =
Bugzilla::Flag::count({ 'target_type' => 'attachment', Bugzilla::Flag::count({ 'target_type' => 'attachment',
'bug_id' => $self->{bug_id} }); 'bug_id' => $self->{bug_id},
'is_active' => 1 });
$self->{'show_attachment_flags'} $self->{'show_attachment_flags'}
= $num_attachment_flag_types || $num_attachment_flags; = $num_attachment_flag_types || $num_attachment_flags;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# Rights Reserved. # Rights Reserved.
# #
# Contributor(s): Myk Melez <myk@mozilla.org> # Contributor(s): Myk Melez <myk@mozilla.org>
# Jouni Heikniemi <jouni@heikniemi.net>
################################################################################ ################################################################################
# Module Initialization # Module Initialization
...@@ -52,8 +53,8 @@ use vars qw($template $vars); ...@@ -52,8 +53,8 @@ use vars qw($template $vars);
# basic sets of columns and tables for getting flags from the database # basic sets of columns and tables for getting flags from the database
my @base_columns = my @base_columns =
("1", "id", "type_id", "bug_id", "attach_id", "requestee_id", "setter_id", ("is_active", "id", "type_id", "bug_id", "attach_id", "requestee_id",
"status"); "setter_id", "status");
# Note: when adding tables to @base_tables, make sure to include the separator # Note: when adding tables to @base_tables, make sure to include the separator
# (i.e. a comma or words like "LEFT OUTER JOIN") before the table name, # (i.e. a comma or words like "LEFT OUTER JOIN") before the table name,
...@@ -154,6 +155,11 @@ sub validate { ...@@ -154,6 +155,11 @@ sub validate {
my $flag = get($id); my $flag = get($id);
$flag || ThrowCodeError("flag_nonexistent", { id => $id }); $flag || ThrowCodeError("flag_nonexistent", { id => $id });
# Note that the deletedness of the flag (is_active or not) is not
# checked here; we do want to allow changes to deleted flags in
# certain cases. Flag::modify() will revive the modified flags.
# See bug 223878 for details.
# Make sure the user chose a valid status. # Make sure the user chose a valid status.
grep($status eq $_, qw(X + - ?)) grep($status eq $_, qw(X + - ?))
|| ThrowCodeError("flag_status_invalid", || ThrowCodeError("flag_status_invalid",
...@@ -226,7 +232,8 @@ sub process { ...@@ -226,7 +232,8 @@ sub process {
# Take a snapshot of flags before any changes. # Take a snapshot of flags before any changes.
my $flags = match({ 'bug_id' => $target->{'bug'}->{'id'} , my $flags = match({ 'bug_id' => $target->{'bug'}->{'id'} ,
'attach_id' => $target->{'attachment'}->{'id'} }); 'attach_id' => $target->{'attachment'}->{'id'} ,
'is_active' => 1 });
my @old_summaries; my @old_summaries;
foreach my $flag (@$flags) { foreach my $flag (@$flags) {
my $summary = $flag->{'type'}->{'name'} . $flag->{'status'}; my $summary = $flag->{'type'}->{'name'} . $flag->{'status'};
...@@ -249,6 +256,7 @@ sub process { ...@@ -249,6 +256,7 @@ sub process {
AND (bugs.product_id = i.product_id OR i.product_id IS NULL) AND (bugs.product_id = i.product_id OR i.product_id IS NULL)
AND (bugs.component_id = i.component_id OR i.component_id IS NULL)) AND (bugs.component_id = i.component_id OR i.component_id IS NULL))
WHERE bugs.bug_id = $target->{'bug'}->{'id'} WHERE bugs.bug_id = $target->{'bug'}->{'id'}
AND flags.is_active = 1
AND i.type_id IS NULL AND i.type_id IS NULL
"); ");
clear(&::FetchOneColumn()) while &::MoreSQLData(); clear(&::FetchOneColumn()) while &::MoreSQLData();
...@@ -257,7 +265,8 @@ sub process { ...@@ -257,7 +265,8 @@ sub process {
FROM flags, bugs, flagexclusions e FROM flags, bugs, flagexclusions e
WHERE bugs.bug_id = $target->{'bug'}->{'id'} WHERE bugs.bug_id = $target->{'bug'}->{'id'}
AND flags.bug_id = bugs.bug_id AND flags.bug_id = bugs.bug_id
AND flags.type_id = e.type_id AND flags.type_id = e.type_id
AND flags.is_active = 1
AND (bugs.product_id = e.product_id OR e.product_id IS NULL) AND (bugs.product_id = e.product_id OR e.product_id IS NULL)
AND (bugs.component_id = e.component_id OR e.component_id IS NULL) AND (bugs.component_id = e.component_id OR e.component_id IS NULL)
"); ");
...@@ -265,7 +274,8 @@ sub process { ...@@ -265,7 +274,8 @@ sub process {
# Take a snapshot of flags after changes. # Take a snapshot of flags after changes.
$flags = match({ 'bug_id' => $target->{'bug'}->{'id'} , $flags = match({ 'bug_id' => $target->{'bug'}->{'id'} ,
'attach_id' => $target->{'attachment'}->{'id'} }); 'attach_id' => $target->{'attachment'}->{'id'} ,
'is_active' => 1 });
my @new_summaries; my @new_summaries;
foreach my $flag (@$flags) { foreach my $flag (@$flags) {
my $summary = $flag->{'type'}->{'name'} . $flag->{'status'}; my $summary = $flag->{'type'}->{'name'} . $flag->{'status'};
...@@ -340,6 +350,9 @@ sub migrate { ...@@ -340,6 +350,9 @@ sub migrate {
sub modify { sub modify {
# Modifies flags in the database when a user changes them. # Modifies flags in the database when a user changes them.
# Note that modified flags are always set active (is_active = 1) -
# this will revive deleted flags that get changed through
# attachment.cgi midairs. See bug 223878 for details.
my ($data, $timestamp) = @_; my ($data, $timestamp) = @_;
...@@ -385,7 +398,8 @@ sub modify { ...@@ -385,7 +398,8 @@ sub modify {
SET setter_id = $::userid , SET setter_id = $::userid ,
requestee_id = NULL , requestee_id = NULL ,
status = '$status' , status = '$status' ,
modification_date = $timestamp modification_date = $timestamp ,
is_active = 1
WHERE id = $flag->{'id'}"); WHERE id = $flag->{'id'}");
# Send an email notifying the relevant parties about the fulfillment. # Send an email notifying the relevant parties about the fulfillment.
...@@ -409,7 +423,8 @@ sub modify { ...@@ -409,7 +423,8 @@ sub modify {
SET setter_id = $::userid , SET setter_id = $::userid ,
requestee_id = $requestee_id , requestee_id = $requestee_id ,
status = '$status' , status = '$status' ,
modification_date = $timestamp modification_date = $timestamp ,
is_active = 1
WHERE id = $flag->{'id'}"); WHERE id = $flag->{'id'}");
# Send an email notifying the relevant parties about the request. # Send an email notifying the relevant parties about the request.
...@@ -420,7 +435,7 @@ sub modify { ...@@ -420,7 +435,7 @@ sub modify {
notify($flag, "request/email.txt.tmpl"); notify($flag, "request/email.txt.tmpl");
} }
} }
# The user unset the flag, so delete it from the database. # The user unset the flag; set is_active = 0
elsif ($status eq 'X') { elsif ($status eq 'X') {
clear($flag->{'id'}); clear($flag->{'id'});
} }
...@@ -437,9 +452,10 @@ sub clear { ...@@ -437,9 +452,10 @@ sub clear {
my $flag = get($id); my $flag = get($id);
&::PushGlobalSQLState(); &::PushGlobalSQLState();
&::SendSQL("DELETE FROM flags WHERE id = $id"); &::SendSQL("UPDATE flags SET is_active = 0 WHERE id = $id");
&::PopGlobalSQLState(); &::PopGlobalSQLState();
$flag->{'exists'} = 0;
# Set the flag's status to "cleared" so the email template # Set the flag's status to "cleared" so the email template
# knows why email is being sent about the request. # knows why email is being sent about the request.
$flag->{'status'} = "X"; $flag->{'status'} = "X";
...@@ -625,6 +641,7 @@ sub sqlify_criteria { ...@@ -625,6 +641,7 @@ sub sqlify_criteria {
elsif ($field eq 'requestee_id') { push(@criteria, "requestee_id = $value") } elsif ($field eq 'requestee_id') { push(@criteria, "requestee_id = $value") }
elsif ($field eq 'setter_id') { push(@criteria, "setter_id = $value") } elsif ($field eq 'setter_id') { push(@criteria, "setter_id = $value") }
elsif ($field eq 'status') { push(@criteria, "status = '$value'") } elsif ($field eq 'status') { push(@criteria, "status = '$value'") }
elsif ($field eq 'is_active') { push(@criteria, "is_active = $value") }
} }
return @criteria; return @criteria;
...@@ -635,6 +652,8 @@ sub perlify_record { ...@@ -635,6 +652,8 @@ sub perlify_record {
my ($exists, $id, $type_id, $bug_id, $attach_id, my ($exists, $id, $type_id, $bug_id, $attach_id,
$requestee_id, $setter_id, $status) = @_; $requestee_id, $setter_id, $status) = @_;
return undef unless defined($exists);
my $flag = my $flag =
{ {
exists => $exists , exists => $exists ,
......
...@@ -270,6 +270,7 @@ sub normalize { ...@@ -270,6 +270,7 @@ sub normalize {
AND (bugs.product_id = i.product_id OR i.product_id IS NULL) AND (bugs.product_id = i.product_id OR i.product_id IS NULL)
AND (bugs.component_id = i.component_id OR i.component_id IS NULL)) AND (bugs.component_id = i.component_id OR i.component_id IS NULL))
WHERE flags.type_id IN ($ids) WHERE flags.type_id IN ($ids)
AND flags.is_active = 1
AND i.type_id IS NULL AND i.type_id IS NULL
"); ");
Bugzilla::Flag::clear(&::FetchOneColumn()) while &::MoreSQLData(); Bugzilla::Flag::clear(&::FetchOneColumn()) while &::MoreSQLData();
...@@ -280,6 +281,7 @@ sub normalize { ...@@ -280,6 +281,7 @@ sub normalize {
WHERE flags.type_id IN ($ids) WHERE flags.type_id IN ($ids)
AND flags.bug_id = bugs.bug_id AND flags.bug_id = bugs.bug_id
AND flags.type_id = e.type_id AND flags.type_id = e.type_id
AND flags.is_active = 1
AND (bugs.product_id = e.product_id OR e.product_id IS NULL) AND (bugs.product_id = e.product_id OR e.product_id IS NULL)
AND (bugs.component_id = e.component_id OR e.component_id IS NULL) AND (bugs.component_id = e.component_id OR e.component_id IS NULL)
"); ");
......
...@@ -586,7 +586,8 @@ sub init { ...@@ -586,7 +586,8 @@ sub init {
# negative conditions (f.e. "flag isn't review+"). # negative conditions (f.e. "flag isn't review+").
my $flags = "flags_$chartid"; my $flags = "flags_$chartid";
push(@supptables, "LEFT JOIN flags $flags " . push(@supptables, "LEFT JOIN flags $flags " .
"ON bugs.bug_id = $flags.bug_id"); "ON bugs.bug_id = $flags.bug_id " .
"AND $flags.is_active = 1");
my $flagtypes = "flagtypes_$chartid"; my $flagtypes = "flagtypes_$chartid";
push(@supptables, "LEFT JOIN flagtypes $flagtypes " . push(@supptables, "LEFT JOIN flagtypes $flagtypes " .
"ON $flags.type_id = $flagtypes.id"); "ON $flags.type_id = $flagtypes.id");
......
...@@ -768,7 +768,8 @@ sub viewall ...@@ -768,7 +768,8 @@ sub viewall
$a{'description'}, $a{'ispatch'}, $a{'isobsolete'}, $a{'isprivate'}, $a{'description'}, $a{'ispatch'}, $a{'isobsolete'}, $a{'isprivate'},
$a{'datasize'}) = FetchSQLData(); $a{'datasize'}) = FetchSQLData();
$a{'isviewable'} = isViewable($a{'contenttype'}); $a{'isviewable'} = isViewable($a{'contenttype'});
$a{'flags'} = Bugzilla::Flag::match({ 'attach_id' => $a{'attachid'} }); $a{'flags'} = Bugzilla::Flag::match({ 'attach_id' => $a{'attachid'},
'is_active' => 1 });
# Add the hash representing the attachment to the array of attachments. # Add the hash representing the attachment to the array of attachments.
push @attachments, \%a; push @attachments, \%a;
...@@ -880,7 +881,9 @@ sub insert ...@@ -880,7 +881,9 @@ sub insert
SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added) SendSQL("INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when, fieldid, removed, added)
VALUES ($::FORM{'bugid'}, $obsolete_id, $::userid, NOW(), $fieldid, '0', '1')"); VALUES ($::FORM{'bugid'}, $obsolete_id, $::userid, NOW(), $fieldid, '0', '1')");
# If the obsolete attachment has pending flags, migrate them to the new attachment. # If the obsolete attachment has pending flags, migrate them to the new attachment.
if (Bugzilla::Flag::count({ 'attach_id' => $obsolete_id , 'status' => 'pending' })) { if (Bugzilla::Flag::count({ 'attach_id' => $obsolete_id ,
'status' => 'pending',
'is_active' => 1 })) {
Bugzilla::Flag::migrate($obsolete_id, $attachid); Bugzilla::Flag::migrate($obsolete_id, $attachid);
} }
} }
...@@ -984,7 +987,8 @@ sub edit ...@@ -984,7 +987,8 @@ sub edit
'component_id' => $component_id }); 'component_id' => $component_id });
foreach my $flag_type (@$flag_types) { foreach my $flag_type (@$flag_types) {
$flag_type->{'flags'} = Bugzilla::Flag::match({ 'type_id' => $flag_type->{'id'}, $flag_type->{'flags'} = Bugzilla::Flag::match({ 'type_id' => $flag_type->{'id'},
'attach_id' => $::FORM{'id'} }); 'attach_id' => $::FORM{'id'},
'is_active' => 1 });
} }
$vars->{'flag_types'} = $flag_types; $vars->{'flag_types'} = $flag_types;
$vars->{'any_flags_requesteeble'} = grep($_->{'is_requesteeble'}, @$flag_types); $vars->{'any_flags_requesteeble'} = grep($_->{'is_requesteeble'}, @$flag_types);
......
...@@ -1609,6 +1609,8 @@ $table{flags} = ...@@ -1609,6 +1609,8 @@ $table{flags} =
setter_id MEDIUMINT NULL , setter_id MEDIUMINT NULL ,
requestee_id MEDIUMINT NULL , requestee_id MEDIUMINT NULL ,
is_active TINYINT NOT NULL DEFAULT 1,
INDEX(bug_id, attach_id) , INDEX(bug_id, attach_id) ,
INDEX(setter_id) , INDEX(setter_id) ,
...@@ -3935,6 +3937,11 @@ if (GetFieldDef("user_group_map", "isderived")) { ...@@ -3935,6 +3937,11 @@ if (GetFieldDef("user_group_map", "isderived")) {
} }
} }
# 2004-07-03 - Make it possible to disable flags without deleting them
# from the database. Bug 223878, jouni@heikniemi.net
AddField('flags', 'is_active', 'tinyint not null default 1');
# If you had to change the --TABLE-- definition in any way, then add your # If you had to change the --TABLE-- definition in any way, then add your
......
...@@ -308,6 +308,7 @@ sub update { ...@@ -308,6 +308,7 @@ sub update {
AND (bugs.component_id = i.component_id OR i.component_id IS NULL)) AND (bugs.component_id = i.component_id OR i.component_id IS NULL))
WHERE flags.type_id = $::FORM{'id'} WHERE flags.type_id = $::FORM{'id'}
AND flags.bug_id = bugs.bug_id AND flags.bug_id = bugs.bug_id
AND flags.is_active = 1
AND i.type_id IS NULL AND i.type_id IS NULL
"); ");
Bugzilla::Flag::clear(FetchOneColumn()) while MoreSQLData(); Bugzilla::Flag::clear(FetchOneColumn()) while MoreSQLData();
...@@ -318,6 +319,7 @@ sub update { ...@@ -318,6 +319,7 @@ sub update {
WHERE flags.type_id = $::FORM{'id'} WHERE flags.type_id = $::FORM{'id'}
AND flags.bug_id = bugs.bug_id AND flags.bug_id = bugs.bug_id
AND flags.type_id = e.type_id AND flags.type_id = e.type_id
AND flags.is_active = 1
AND (bugs.product_id = e.product_id OR e.product_id IS NULL) AND (bugs.product_id = e.product_id OR e.product_id IS NULL)
AND (bugs.component_id = e.component_id OR e.component_id IS NULL) AND (bugs.component_id = e.component_id OR e.component_id IS NULL)
"); ");
...@@ -340,7 +342,8 @@ sub confirmDelete ...@@ -340,7 +342,8 @@ sub confirmDelete
validateID(); validateID();
# check if we need confirmation to delete: # check if we need confirmation to delete:
my $count = Bugzilla::Flag::count({ 'type_id' => $::FORM{'id'} }); my $count = Bugzilla::Flag::count({ 'type_id' => $::FORM{'id'},
'is_active' => 1 });
if ($count > 0) { if ($count > 0) {
$vars->{'flag_type'} = Bugzilla::FlagType::get($::FORM{'id'}); $vars->{'flag_type'} = Bugzilla::FlagType::get($::FORM{'id'});
......
...@@ -116,6 +116,9 @@ sub queue { ...@@ -116,6 +116,9 @@ sub queue {
AND flags.bug_id = bugs.bug_id AND flags.bug_id = bugs.bug_id
"; ";
# Non-deleted flags only
$query .= " AND flags.is_active = 1 ";
# Limit query to pending requests. # Limit query to pending requests.
$query .= " AND flags.status = '?' " unless $cgi->param('status'); $query .= " AND flags.status = '?' " unless $cgi->param('status');
......
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