diff options
-rw-r--r-- | Bugzilla/Flag.pm | 111 | ||||
-rw-r--r-- | Bugzilla/Search.pm | 1 | ||||
-rwxr-xr-x | buglist.cgi | 39 | ||||
-rwxr-xr-x | process_bug.cgi | 11 | ||||
-rw-r--r-- | template/en/default/flag/list.html.tmpl | 16 | ||||
-rw-r--r-- | template/en/default/list/edit-multiple.html.tmpl | 7 |
6 files changed, 184 insertions, 1 deletions
diff --git a/Bugzilla/Flag.pm b/Bugzilla/Flag.pm index 381cc1174..6e2096729 100644 --- a/Bugzilla/Flag.pm +++ b/Bugzilla/Flag.pm @@ -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 diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index b2e8da096..2a13969cc 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -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. diff --git a/buglist.cgi b/buglist.cgi index eeea3bdf5..5106f8dc2 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -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 = diff --git a/process_bug.cgi b/process_bug.cgi index 6ae5c54d6..4b35bf432 100755 --- a/process_bug.cgi +++ b/process_bug.cgi @@ -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 # diff --git a/template/en/default/flag/list.html.tmpl b/template/en/default/flag/list.html.tmpl index 47406d6c0..455238cfc 100644 --- a/template/en/default/flag/list.html.tmpl +++ b/template/en/default/flag/list.html.tmpl @@ -119,6 +119,9 @@ 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 %] @@ -168,6 +171,19 @@ [% 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 %] diff --git a/template/en/default/list/edit-multiple.html.tmpl b/template/en/default/list/edit-multiple.html.tmpl index 144ae10c9..e581f0892 100644 --- a/template/en/default/list/edit-multiple.html.tmpl +++ b/template/en/default/list/edit-multiple.html.tmpl @@ -321,6 +321,13 @@ </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 %] |