]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 281791 - Add ability to change flags in "change several bugs at once"
authorSimon Green <sgreen@redhat.com>
Tue, 2 Sep 2014 00:26:42 +0000 (10:26 +1000)
committerSimon Green <sgreen@redhat.com>
Tue, 2 Sep 2014 00:26:42 +0000 (10:26 +1000)
r=glob, a=sgreen

Bugzilla/Flag.pm
Bugzilla/Search.pm
buglist.cgi
process_bug.cgi
template/en/default/flag/list.html.tmpl
template/en/default/list/edit-multiple.html.tmpl

index 381cc1174e688ecb3536052eb54868170e5b4ff9..6e20967292a4cb8f13595e3d82287f1019067a7a 100644 (file)
@@ -932,6 +932,117 @@ sub extract_flags_from_cgi {
 
 =over
 
+=item C<multi_extract_flags_from_cgi($bug, $hr_vars)>
+
+Checks whether or not there are new flags to create and returns an
+array of hashes. This array is then passed to Flag::create(). This differs
+from the previous sub-routine as it is called for changing multiple bugs
+
+=back
+
+=cut
+
+sub multi_extract_flags_from_cgi {
+    my ($class, $bug, $vars, $skip) = @_;
+    my $cgi = Bugzilla->cgi;
+
+    my $match_status = Bugzilla::User::match_field({
+        '^requestee(_type)?-(\d+)$' => { 'type' => 'multi' },
+    }, undef, $skip);
+
+    $vars->{'match_field'} = 'requestee';
+    if ($match_status == USER_MATCH_FAILED) {
+        $vars->{'message'} = 'user_match_failed';
+    }
+    elsif ($match_status == USER_MATCH_MULTIPLE) {
+        $vars->{'message'} = 'user_match_multiple';
+    }
+
+    # Extract a list of flag type IDs from field names.
+    my @flagtype_ids = map(/^flag_type-(\d+)$/ ? $1 : (), $cgi->param());
+
+    my (@new_flags, @flags);
+
+    # Get a list of active flag types available for this product/component.
+    my $flag_types = Bugzilla::FlagType::match(
+        { 'product_id'   => $bug->{'product_id'},
+          'component_id' => $bug->{'component_id'},
+          'is_active'    => 1 });
+
+    foreach my $flagtype_id (@flagtype_ids) {
+        # Checks if there are unexpected flags for the product/component.
+        if (!scalar(grep { $_->id == $flagtype_id } @$flag_types)) {
+            $vars->{'message'} = 'unexpected_flag_types';
+            last;
+        }
+    }
+
+    foreach my $flag_type (@$flag_types) {
+        my $type_id = $flag_type->id;
+
+        # Bug flags are only valid for bugs
+        next unless ($flag_type->target_type eq 'bug');
+
+        # We are only interested in flags the user tries to create.
+        next unless scalar(grep { $_ == $type_id } @flagtype_ids);
+
+        # Get the flags of this type already set for this bug.
+        my $current_flags = $class->match(
+            { 'type_id'     => $type_id,
+              'target_type' => 'bug',
+              'bug_id'      => $bug->bug_id });
+
+        # We will update existing flags (instead of creating new ones)
+        # if the flag exists and the user has not chosen the 'always add'
+        # option
+        my $update = scalar(@$current_flags) && ! $cgi->param("flags_add-$type_id");
+
+        my $status = $cgi->param("flag_type-$type_id");
+        trick_taint($status);
+
+        my @logins = $cgi->param("requestee_type-$type_id");
+        if ($status eq "?" && scalar(@logins)) {
+            foreach my $login (@logins) {
+                if ($update) {
+                foreach my $current_flag (@$current_flags) {
+                    push (@flags, { id        => $current_flag->id,
+                                    status    => $status,
+                                    requestee => $login,
+                                    skip_roe  => $skip });
+                    }
+                }
+                else {
+                    push (@new_flags, { type_id   => $type_id,
+                                        status    => $status,
+                                        requestee => $login,
+                                        skip_roe  => $skip });
+                }
+
+                last unless $flag_type->is_multiplicable;
+            }
+        }
+        else {
+            if ($update) {
+                foreach my $current_flag (@$current_flags) {
+                    push (@flags, { id      => $current_flag->id,
+                                    status  => $status });
+                }
+            }
+            else {
+                push (@new_flags, { type_id => $type_id,
+                                    status  => $status });
+            }
+        }
+    }
+
+    # Return the list of flags to update and/or to create.
+    return (\@flags, \@new_flags);
+}
+
+=pod
+
+=over
+
 =item C<notify($flag, $old_flag, $object, $timestamp)>
 
 Sends an email notification about a flag being created, fulfilled
index b2e8da0967d445f24630589d93d3b224e6f0e236..2a13969ccb70c27582dbb9c2c03844ddf9588c3d 100644 (file)
@@ -647,6 +647,7 @@ sub COLUMNS {
 
     foreach my $col (@id_fields) {
         $special_sql{$col} = "map_${col}.name";
+        $columns{"${col}_id"}{name} = "bugs.${col}_id";
     }
 
     # Do the actual column-getting from fielddefs, now.
index eeea3bdf56fdc17dba7368c30d7d0ec68715ed67..5106f8dc27bf1fa060ebf133fe67c26409f4fc39 100755 (executable)
@@ -510,6 +510,37 @@ if (grep('relevance', @displaycolumns) && !$fulltext) {
     @displaycolumns = grep($_ ne 'relevance', @displaycolumns);
 }
 
+sub _get_common_flag_types {
+    my $component_ids = shift;
+
+    # Get all the different components in the bug list
+    my $components = Bugzilla::Component->new_from_list($component_ids);
+    my %flag_types;
+    my @flag_types_ids;
+    foreach my $component (@$components) {
+        foreach my $flag_type (@{$component->flag_types->{'bug'}}) {
+            push @flag_types_ids, $flag_type->id;
+            $flag_types{$flag_type->id} = $flag_type;
+        }
+    }
+
+    # We only want flags that appear in all components
+    my %common_flag_types;
+    foreach my $id (keys %flag_types) {
+        my $flag_type_count = scalar grep { $_ == $id } @flag_types_ids;
+        $common_flag_types{$id} = $flag_types{$id}
+            if $flag_type_count == scalar @$components;
+    }
+
+    # We only show flags that a user has request or set rights on
+    my @show_flag_types
+        = grep { $user->can_request_flag($_) || $user->can_set_flag($_) }
+        values %common_flag_types;
+    my $any_flags_requesteeble =
+        grep($_->is_requesteeble, @show_flag_types);
+
+    return(\@show_flag_types, $any_flags_requesteeble);
+}
 
 ################################################################################
 # Select Column Determination
@@ -551,6 +582,7 @@ foreach my $col (@displaycolumns) {
 # has for modifying the bugs.
 if ($dotweak) {
     push(@selectcolumns, "bug_status") if !grep($_ eq 'bug_status', @selectcolumns);
+    push(@selectcolumns, "component_id") if !grep($_ eq 'component_id', @selectcolumns);
 }
 
 if ($format->{'extension'} eq 'ics') {
@@ -753,9 +785,10 @@ my $time_info = { 'estimated_time' => 0,
                   'time_present' => ($estimated_time || $remaining_time ||
                                      $actual_time || $percentage_complete),
                 };
-    
+
 my $bugowners = {};
 my $bugproducts = {};
+my $bugcomponentids = {};
 my $bugcomponents = {};
 my $bugstatuses = {};
 my @bugidlist;
@@ -789,6 +822,7 @@ foreach my $row (@$data) {
     # Record the assignee, product, and status in the big hashes of those things.
     $bugowners->{$bug->{'assigned_to'}} = 1 if $bug->{'assigned_to'};
     $bugproducts->{$bug->{'product'}} = 1 if $bug->{'product'};
+    $bugcomponentids->{$bug->{'component_id'}} = 1 if $bug->{'component_id'};
     $bugcomponents->{$bug->{'component'}} = 1 if $bug->{'component'};
     $bugstatuses->{$bug->{'bug_status'}} = 1 if $bug->{'bug_status'};
 
@@ -956,6 +990,9 @@ if ($dotweak && scalar @bugs) {
     $vars->{'severities'} = get_legal_field_values('bug_severity');
     $vars->{'resolutions'} = get_legal_field_values('resolution');
 
+    ($vars->{'flag_types'}, $vars->{any_flags_requesteeble})
+        = _get_common_flag_types([keys %$bugcomponentids]);
+
     # Convert bug statuses to their ID.
     my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses;
     my $bug_status_ids =
index 6ae5c54d66eba832c33b5d1ee1c8af5d7c87b60e..4b35bf432b192de612ab0bc94fcb0889e9dfc9f2 100755 (executable)
@@ -358,6 +358,17 @@ if (defined $cgi->param('id')) {
         $first_bug->add_tag($_) foreach @$tags_added;
     }
 }
+else {
+    # Update flags on multiple bugs. The cgi params are slightly different
+    # than on a single bug, so we need to call a different sub. We also
+    # need to call this per bug, since we might be updating a flag in one
+    # bug, but adding it to a second bug
+    foreach my $b (@bug_objects) {
+        my ($flags, $new_flags)
+            = Bugzilla::Flag->multi_extract_flags_from_cgi($b, $vars);
+        $b->set_flags($flags, $new_flags);
+    }
+}
 
 ##############################
 # Do Actual Database Updates #
index 47406d6c035b7e39106aa279b11373fdad31b88c..455238cfc8931fe276be80e1a62b4086ad2d848e 100644 (file)
                 class="flag_select flag_type-[% type.id %]"
                 [% IF !can_edit_flag %] disabled="disabled"[% END %]>
         [%# Only display statuses the user is allowed to set. %]
+        [% IF edit_multiple_bugs %]
+          <option value="--do_not_change--">--do_not_change--</option>
+        [% END %]
         [% IF !flag || (can_edit_flag && user.can_request_flag(type)) || flag.setter_id == user.id %]
           <option value="X"></option>
         [% END %]
           [% END %]
         </td>
       [% END %]
+      <td>
+        [% IF type.is_multiplicable && edit_multiple_bugs %]
+          <input type="checkbox"
+                 name="flags_add-[% type.id %]"
+                 id="flags_add-[% type.id %]">
+          <label for="flags_add-[% type.id %]">
+            <a class="field_help_link"
+               title="If ticked, always create a new flag. Leaving it unchecked will update existing flag(s) and add a new flag if it does not exist">
+               Always add?
+            </a>
+          </label>
+        [% END %]
+      <td>
     </tr>
   </tbody>
 [% END %]
index 144ae10c93aa5c9e2256d7a192a361d810a5e326..e581f0892ddc2c8c937a230f4dc5e6b9a82e83d3 100644 (file)
   </script>
 [% END %]
 
+[% IF flag_types %]
+<b><label for="flags">Flags:</label></b><br>
+[% PROCESS "flag/list.html.tmpl"
+           edit_multiple_bugs = 1
+           flag_no_header = 1 %]
+[% END %]
+
 [% Hook.process('before_groups') %]
 
 [% IF groups.size > 0 %]