Skip to content

Commit e0fbbde

Browse files
author
Simon Green
committed
Bug 281791 - Add ability to change flags in "change several bugs at once"
r=glob, a=sgreen
1 parent 92b5ff1 commit e0fbbde

6 files changed

Lines changed: 184 additions & 1 deletion

File tree

Bugzilla/Flag.pm

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,117 @@ sub extract_flags_from_cgi {
932932
933933
=over
934934
935+
=item C<multi_extract_flags_from_cgi($bug, $hr_vars)>
936+
937+
Checks whether or not there are new flags to create and returns an
938+
array of hashes. This array is then passed to Flag::create(). This differs
939+
from the previous sub-routine as it is called for changing multiple bugs
940+
941+
=back
942+
943+
=cut
944+
945+
sub multi_extract_flags_from_cgi {
946+
my ($class, $bug, $vars, $skip) = @_;
947+
my $cgi = Bugzilla->cgi;
948+
949+
my $match_status = Bugzilla::User::match_field({
950+
'^requestee(_type)?-(\d+)$' => { 'type' => 'multi' },
951+
}, undef, $skip);
952+
953+
$vars->{'match_field'} = 'requestee';
954+
if ($match_status == USER_MATCH_FAILED) {
955+
$vars->{'message'} = 'user_match_failed';
956+
}
957+
elsif ($match_status == USER_MATCH_MULTIPLE) {
958+
$vars->{'message'} = 'user_match_multiple';
959+
}
960+
961+
# Extract a list of flag type IDs from field names.
962+
my @flagtype_ids = map(/^flag_type-(\d+)$/ ? $1 : (), $cgi->param());
963+
964+
my (@new_flags, @flags);
965+
966+
# Get a list of active flag types available for this product/component.
967+
my $flag_types = Bugzilla::FlagType::match(
968+
{ 'product_id' => $bug->{'product_id'},
969+
'component_id' => $bug->{'component_id'},
970+
'is_active' => 1 });
971+
972+
foreach my $flagtype_id (@flagtype_ids) {
973+
# Checks if there are unexpected flags for the product/component.
974+
if (!scalar(grep { $_->id == $flagtype_id } @$flag_types)) {
975+
$vars->{'message'} = 'unexpected_flag_types';
976+
last;
977+
}
978+
}
979+
980+
foreach my $flag_type (@$flag_types) {
981+
my $type_id = $flag_type->id;
982+
983+
# Bug flags are only valid for bugs
984+
next unless ($flag_type->target_type eq 'bug');
985+
986+
# We are only interested in flags the user tries to create.
987+
next unless scalar(grep { $_ == $type_id } @flagtype_ids);
988+
989+
# Get the flags of this type already set for this bug.
990+
my $current_flags = $class->match(
991+
{ 'type_id' => $type_id,
992+
'target_type' => 'bug',
993+
'bug_id' => $bug->bug_id });
994+
995+
# We will update existing flags (instead of creating new ones)
996+
# if the flag exists and the user has not chosen the 'always add'
997+
# option
998+
my $update = scalar(@$current_flags) && ! $cgi->param("flags_add-$type_id");
999+
1000+
my $status = $cgi->param("flag_type-$type_id");
1001+
trick_taint($status);
1002+
1003+
my @logins = $cgi->param("requestee_type-$type_id");
1004+
if ($status eq "?" && scalar(@logins)) {
1005+
foreach my $login (@logins) {
1006+
if ($update) {
1007+
foreach my $current_flag (@$current_flags) {
1008+
push (@flags, { id => $current_flag->id,
1009+
status => $status,
1010+
requestee => $login,
1011+
skip_roe => $skip });
1012+
}
1013+
}
1014+
else {
1015+
push (@new_flags, { type_id => $type_id,
1016+
status => $status,
1017+
requestee => $login,
1018+
skip_roe => $skip });
1019+
}
1020+
1021+
last unless $flag_type->is_multiplicable;
1022+
}
1023+
}
1024+
else {
1025+
if ($update) {
1026+
foreach my $current_flag (@$current_flags) {
1027+
push (@flags, { id => $current_flag->id,
1028+
status => $status });
1029+
}
1030+
}
1031+
else {
1032+
push (@new_flags, { type_id => $type_id,
1033+
status => $status });
1034+
}
1035+
}
1036+
}
1037+
1038+
# Return the list of flags to update and/or to create.
1039+
return (\@flags, \@new_flags);
1040+
}
1041+
1042+
=pod
1043+
1044+
=over
1045+
9351046
=item C<notify($flag, $old_flag, $object, $timestamp)>
9361047
9371048
Sends an email notification about a flag being created, fulfilled

Bugzilla/Search.pm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ sub COLUMNS {
647647

648648
foreach my $col (@id_fields) {
649649
$special_sql{$col} = "map_${col}.name";
650+
$columns{"${col}_id"}{name} = "bugs.${col}_id";
650651
}
651652

652653
# Do the actual column-getting from fielddefs, now.

buglist.cgi

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,37 @@ if (grep('relevance', @displaycolumns) && !$fulltext) {
510510
@displaycolumns = grep($_ ne 'relevance', @displaycolumns);
511511
}
512512

513+
sub _get_common_flag_types {
514+
my $component_ids = shift;
515+
516+
# Get all the different components in the bug list
517+
my $components = Bugzilla::Component->new_from_list($component_ids);
518+
my %flag_types;
519+
my @flag_types_ids;
520+
foreach my $component (@$components) {
521+
foreach my $flag_type (@{$component->flag_types->{'bug'}}) {
522+
push @flag_types_ids, $flag_type->id;
523+
$flag_types{$flag_type->id} = $flag_type;
524+
}
525+
}
526+
527+
# We only want flags that appear in all components
528+
my %common_flag_types;
529+
foreach my $id (keys %flag_types) {
530+
my $flag_type_count = scalar grep { $_ == $id } @flag_types_ids;
531+
$common_flag_types{$id} = $flag_types{$id}
532+
if $flag_type_count == scalar @$components;
533+
}
534+
535+
# We only show flags that a user has request or set rights on
536+
my @show_flag_types
537+
= grep { $user->can_request_flag($_) || $user->can_set_flag($_) }
538+
values %common_flag_types;
539+
my $any_flags_requesteeble =
540+
grep($_->is_requesteeble, @show_flag_types);
541+
542+
return(\@show_flag_types, $any_flags_requesteeble);
543+
}
513544

514545
################################################################################
515546
# Select Column Determination
@@ -551,6 +582,7 @@ foreach my $col (@displaycolumns) {
551582
# has for modifying the bugs.
552583
if ($dotweak) {
553584
push(@selectcolumns, "bug_status") if !grep($_ eq 'bug_status', @selectcolumns);
585+
push(@selectcolumns, "component_id") if !grep($_ eq 'component_id', @selectcolumns);
554586
}
555587

556588
if ($format->{'extension'} eq 'ics') {
@@ -753,9 +785,10 @@ my $time_info = { 'estimated_time' => 0,
753785
'time_present' => ($estimated_time || $remaining_time ||
754786
$actual_time || $percentage_complete),
755787
};
756-
788+
757789
my $bugowners = {};
758790
my $bugproducts = {};
791+
my $bugcomponentids = {};
759792
my $bugcomponents = {};
760793
my $bugstatuses = {};
761794
my @bugidlist;
@@ -789,6 +822,7 @@ foreach my $row (@$data) {
789822
# Record the assignee, product, and status in the big hashes of those things.
790823
$bugowners->{$bug->{'assigned_to'}} = 1 if $bug->{'assigned_to'};
791824
$bugproducts->{$bug->{'product'}} = 1 if $bug->{'product'};
825+
$bugcomponentids->{$bug->{'component_id'}} = 1 if $bug->{'component_id'};
792826
$bugcomponents->{$bug->{'component'}} = 1 if $bug->{'component'};
793827
$bugstatuses->{$bug->{'bug_status'}} = 1 if $bug->{'bug_status'};
794828

@@ -956,6 +990,9 @@ if ($dotweak && scalar @bugs) {
956990
$vars->{'severities'} = get_legal_field_values('bug_severity');
957991
$vars->{'resolutions'} = get_legal_field_values('resolution');
958992

993+
($vars->{'flag_types'}, $vars->{any_flags_requesteeble})
994+
= _get_common_flag_types([keys %$bugcomponentids]);
995+
959996
# Convert bug statuses to their ID.
960997
my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses;
961998
my $bug_status_ids =

process_bug.cgi

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,17 @@ if (defined $cgi->param('id')) {
358358
$first_bug->add_tag($_) foreach @$tags_added;
359359
}
360360
}
361+
else {
362+
# Update flags on multiple bugs. The cgi params are slightly different
363+
# than on a single bug, so we need to call a different sub. We also
364+
# need to call this per bug, since we might be updating a flag in one
365+
# bug, but adding it to a second bug
366+
foreach my $b (@bug_objects) {
367+
my ($flags, $new_flags)
368+
= Bugzilla::Flag->multi_extract_flags_from_cgi($b, $vars);
369+
$b->set_flags($flags, $new_flags);
370+
}
371+
}
361372

362373
##############################
363374
# Do Actual Database Updates #

template/en/default/flag/list.html.tmpl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@
119119
class="flag_select flag_type-[% type.id %]"
120120
[% IF !can_edit_flag %] disabled="disabled"[% END %]>
121121
[%# Only display statuses the user is allowed to set. %]
122+
[% IF edit_multiple_bugs %]
123+
<option value="--do_not_change--">--do_not_change--</option>
124+
[% END %]
122125
[% IF !flag || (can_edit_flag && user.can_request_flag(type)) || flag.setter_id == user.id %]
123126
<option value="X"></option>
124127
[% END %]
@@ -168,6 +171,19 @@
168171
[% END %]
169172
</td>
170173
[% END %]
174+
<td>
175+
[% IF type.is_multiplicable && edit_multiple_bugs %]
176+
<input type="checkbox"
177+
name="flags_add-[% type.id %]"
178+
id="flags_add-[% type.id %]">
179+
<label for="flags_add-[% type.id %]">
180+
<a class="field_help_link"
181+
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">
182+
Always add?
183+
</a>
184+
</label>
185+
[% END %]
186+
<td>
171187
</tr>
172188
</tbody>
173189
[% END %]

template/en/default/list/edit-multiple.html.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@
321321
</script>
322322
[% END %]
323323

324+
[% IF flag_types %]
325+
<b><label for="flags">Flags:</label></b><br>
326+
[% PROCESS "flag/list.html.tmpl"
327+
edit_multiple_bugs = 1
328+
flag_no_header = 1 %]
329+
[% END %]
330+
324331
[% Hook.process('before_groups') %]
325332

326333
[% IF groups.size > 0 %]

0 commit comments

Comments
 (0)