diff --git a/webtools/bugzilla/Bugzilla/Bug.pm b/webtools/bugzilla/Bugzilla/Bug.pm index d309d0bc22de..5ac2f2b0b6b9 100644 --- a/webtools/bugzilla/Bugzilla/Bug.pm +++ b/webtools/bugzilla/Bugzilla/Bug.pm @@ -115,7 +115,6 @@ sub VALIDATORS { alias => \&_check_alias, bug_file_loc => \&_check_bug_file_loc, bug_severity => \&_check_bug_severity, - cc => \&_check_cc, comment => \&_check_comment, commentprivacy => \&_check_commentprivacy, deadline => \&_check_deadline, @@ -353,6 +352,8 @@ sub run_create_validators { $class->_check_assigned_to($component, $params->{assigned_to}); $params->{qa_contact} = $class->_check_qa_contact($component, $params->{qa_contact}); + $params->{cc} = $class->_check_cc($component, $params->{cc}); + # Callers cannot set Reporter, currently. $params->{reporter} = Bugzilla->user->id; @@ -506,7 +507,7 @@ sub _check_bug_status { } sub _check_cc { - my ($invocant, $ccs) = @_; + my ($invocant, $component, $ccs) = @_; return [] unless $ccs; my %cc_ids; @@ -515,6 +516,10 @@ sub _check_cc { my $id = login_to_id($person, THROW_ERROR); $cc_ids{$id} = 1; } + + # Enforce Default CC + $cc_ids{$_->id} = 1 foreach (@{$component->initial_cc}); + return [keys %cc_ids]; } diff --git a/webtools/bugzilla/Bugzilla/Component.pm b/webtools/bugzilla/Bugzilla/Component.pm index abd3711f5ec9..4b9856feba4b 100644 --- a/webtools/bugzilla/Bugzilla/Component.pm +++ b/webtools/bugzilla/Bugzilla/Component.pm @@ -14,6 +14,8 @@ # # Contributor(s): Tiago R. Mello # Frédéric Buclin +# Max Kanat-Alexander +# Akamai Technologies use strict; @@ -154,6 +156,21 @@ sub flag_types { return $self->{'flag_types'}; } +sub initial_cc { + my $self = shift; + + my $dbh = Bugzilla->dbh; + + if (!defined $self->{'initial_cc'}) { + my $cc_ids = $dbh->selectcol_arrayref( + "SELECT user_id FROM component_cc WHERE component_id = ?", + undef, $self->id); + my $initial_cc = Bugzilla::User->new_from_list($cc_ids); + $self->{'initial_cc'} = $initial_cc; + } + return $self->{'initial_cc'}; +} + ############################### #### Accessors #### ############################### @@ -212,6 +229,7 @@ Bugzilla::Component - Bugzilla product component class. my $product_id = $component->product_id; my $default_assignee = $component->default_assignee; my $default_qa_contact = $component->default_qa_contact; + my $initial_cc = $component->initial_cc my $bug_flag_types = $component->flag_types->{'bug'}; my $attach_flag_types = $component->flag_types->{'attachment'}; @@ -273,6 +291,11 @@ Component.pm represents a Product Component object. Returns: A Bugzilla::User object. +=item C + +Returns an arrayref of L objects representing the +Initial CC List. + =item C Description: Returns all bug and attachment flagtypes available for diff --git a/webtools/bugzilla/Bugzilla/DB/Schema.pm b/webtools/bugzilla/Bugzilla/DB/Schema.pm index 938ef042ab46..4235be5add8f 100644 --- a/webtools/bugzilla/Bugzilla/DB/Schema.pm +++ b/webtools/bugzilla/Bugzilla/DB/Schema.pm @@ -22,6 +22,7 @@ # Max Kanat-Alexander # Lance Larsh # Dennis Melentyev +# Akamai Technologies package Bugzilla::DB::Schema; @@ -703,6 +704,18 @@ use constant ABSTRACT_SCHEMA => { ], }, + component_cc => { + + FIELDS => [ + user_id => {TYPE => 'INT3', NOTNULL => 1}, + component_id => {TYPE => 'INT2', NOTNULL => 1}, + ], + INDEXES => [ + component_cc_user_id_idx => {FIELDS => [qw(component_id user_id)], + TYPE => 'UNIQUE'}, + ], + }, + # Authentication # -------------- diff --git a/webtools/bugzilla/editcomponents.cgi b/webtools/bugzilla/editcomponents.cgi index c87bc0313cd9..cc81cece7073 100755 --- a/webtools/bugzilla/editcomponents.cgi +++ b/webtools/bugzilla/editcomponents.cgi @@ -21,6 +21,7 @@ # Contributor(s): Holger Schurig # Terry Weissman # Frédéric Buclin +# Akamai Technologies # # Direct any questions on this source code to # @@ -39,6 +40,26 @@ use Bugzilla::Product; use Bugzilla::Component; use Bugzilla::Bug; +############### +# Subroutines # +############### + +# Takes an arrayref of login names and returns an arrayref of user ids. +sub check_initial_cc { + my ($user_names) = @_; + + my %cc_ids; + foreach my $cc (@$user_names) { + my $id = login_to_id($cc, THROW_ERROR); + $cc_ids{$id} = 1; + } + return [keys %cc_ids]; +} + +############### +# Main Script # +############### + my $cgi = Bugzilla->cgi; my $dbh = Bugzilla->dbh; my $template = Bugzilla->template; @@ -129,11 +150,13 @@ if ($action eq 'new') { Bugzilla::User::match_field ($cgi, { 'initialowner' => { 'type' => 'single' }, 'initialqacontact' => { 'type' => 'single' }, + 'initialcc' => { 'type' => 'multi' }, }); my $default_assignee = trim($cgi->param('initialowner') || ''); my $default_qa_contact = trim($cgi->param('initialqacontact') || ''); my $description = trim($cgi->param('description') || ''); + my @initial_cc = $cgi->param('initialcc'); $comp_name || ThrowUserError('component_blank_name'); @@ -161,9 +184,13 @@ if ($action eq 'new') { my $default_qa_contact_id = Bugzilla->params->{'useqacontact'} ? (login_to_id($default_qa_contact) || undef) : undef; + my $initial_cc_ids = check_initial_cc(\@initial_cc); + trick_taint($comp_name); trick_taint($description); + $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE'); + $dbh->do("INSERT INTO components (product_id, name, description, initialowner, initialqacontact) @@ -171,6 +198,17 @@ if ($action eq 'new') { ($product->id, $comp_name, $description, $default_assignee_id, $default_qa_contact_id)); + $component = new Bugzilla::Component({ product_id => $product->id, + name => $comp_name }); + + my $sth = $dbh->prepare("INSERT INTO component_cc + (user_id, component_id) VALUES (?, ?)"); + foreach my $user_id (@$initial_cc_ids) { + $sth->execute($user_id, $component->id); + } + + $dbh->bz_unlock_tables; + # Insert default charting queries for this product. # If they aren't using charting, this won't do any harm. my @series; @@ -204,10 +242,6 @@ if ($action eq 'new') { $series->writeToDatabase(); } - $component = - new Bugzilla::Component({product_id => $product->id, - name => $comp_name}); - $vars->{'comp'} = $component; $vars->{'product'} = $product; $template->process("admin/components/created.html.tmpl", @@ -263,13 +297,15 @@ if ($action eq 'delete') { } } - $dbh->bz_lock_tables('components WRITE', 'flaginclusions WRITE', - 'flagexclusions WRITE'); + $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE', + 'flaginclusions WRITE', 'flagexclusions WRITE'); $dbh->do("DELETE FROM flaginclusions WHERE component_id = ?", undef, $component->id); $dbh->do("DELETE FROM flagexclusions WHERE component_id = ?", undef, $component->id); + $dbh->do("DELETE FROM component_cc WHERE component_id = ?", + undef, $component->id); $dbh->do("DELETE FROM components WHERE id = ?", undef, $component->id); @@ -292,8 +328,12 @@ if ($action eq 'delete') { if ($action eq 'edit') { - $vars->{'comp'} = + my $component = Bugzilla::Component::check_component($product, $comp_name); + $vars->{'comp'} = $component; + + $vars->{'initial_cc_names'} = + join(', ', map($_->login, @{$component->initial_cc})); $vars->{'product'} = $product; @@ -316,12 +356,14 @@ if ($action eq 'update') { Bugzilla::User::match_field ($cgi, { 'initialowner' => { 'type' => 'single' }, 'initialqacontact' => { 'type' => 'single' }, + 'initialcc' => { 'type' => 'multi' }, }); my $comp_old_name = trim($cgi->param('componentold') || ''); my $default_assignee = trim($cgi->param('initialowner') || ''); my $default_qa_contact = trim($cgi->param('initialqacontact') || ''); my $description = trim($cgi->param('description') || ''); + my @initial_cc = $cgi->param('initialcc'); my $component_old = Bugzilla::Component::check_component($product, $comp_old_name); @@ -352,7 +394,10 @@ if ($action eq 'update') { my $default_assignee_id = login_to_id($default_assignee); my $default_qa_contact_id = login_to_id($default_qa_contact) || undef; - $dbh->bz_lock_tables('components WRITE', 'profiles READ'); + my $initial_cc_ids = check_initial_cc(\@initial_cc); + + $dbh->bz_lock_tables('components WRITE', 'component_cc WRITE', + 'profiles READ'); if ($comp_name ne $component_old->name) { @@ -390,11 +435,29 @@ if ($action eq 'update') { $vars->{'updated_initialqacontact'} = 1; } + my @initial_cc_old = map($_->id, @{$component_old->initial_cc}); + my ($removed, $added) = diff_arrays(\@initial_cc_old, $initial_cc_ids); + + foreach my $user_id (@$removed) { + $dbh->do('DELETE FROM component_cc + WHERE component_id = ? AND user_id = ?', undef, + $component_old->id, $user_id); + $vars->{'updated_initialcc'} = 1; + } + + foreach my $user_id (@$added) { + $dbh->do("INSERT INTO component_cc (user_id, component_id) + VALUES (?, ?)", undef, $user_id, $component_old->id); + $vars->{'updated_initialcc'} = 1; + } + $dbh->bz_unlock_tables(); my $component = new Bugzilla::Component($component_old->id); $vars->{'comp'} = $component; + $vars->{'initial_cc_names'} = + join(', ', map($_->login, @{$component->initial_cc})); $vars->{'product'} = $product; $template->process("admin/components/updated.html.tmpl", $vars) diff --git a/webtools/bugzilla/process_bug.cgi b/webtools/bugzilla/process_bug.cgi index 1824dd7f34e7..e671b9d76eb5 100755 --- a/webtools/bugzilla/process_bug.cgi +++ b/webtools/bugzilla/process_bug.cgi @@ -26,6 +26,7 @@ # Jeff Hedlund # Frédéric Buclin # Lance Larsh +# Akamai Technologies # Implementation notes for this file: # @@ -1370,6 +1371,18 @@ foreach my $id (@idlist) { $query .= ", qa_contact = NULL"; } } + + + + # And add in the Default CC for the Component. + my $comp_obj = $component || new Bugzilla::Component($new_comp_id); + my @new_init_cc = @{$comp_obj->initial_cc}; + foreach my $cc (@new_init_cc) { + # NewCC must be defined or the code below won't insert + # any CCs. + $cgi->param('newcc') || $cgi->param('newcc', []); + $cc_add{$cc->id} = $cc->login; + } } my %dependencychanged; diff --git a/webtools/bugzilla/template/en/default/admin/components/create.html.tmpl b/webtools/bugzilla/template/en/default/admin/components/create.html.tmpl index 83c28ab85f64..013ee861e669 100644 --- a/webtools/bugzilla/template/en/default/admin/components/create.html.tmpl +++ b/webtools/bugzilla/template/en/default/admin/components/create.html.tmpl @@ -17,6 +17,7 @@ # Rights Reserved. # # Contributor(s): Gavin Shelley + # Akamai Technologies #%] [%# INTERFACE: @@ -76,6 +77,24 @@ [% END %] + + + + + + [% INCLUDE global/userselect.html.tmpl + name => "initialcc" + id => "initialcc" + value => "" + size => 64 + multiple => 5 + %] +
+ [% IF !Param("usemenuforusers") %] + Enter user names for the CC in a comma-separated list. + [% END %] + +
diff --git a/webtools/bugzilla/template/en/default/admin/components/edit.html.tmpl b/webtools/bugzilla/template/en/default/admin/components/edit.html.tmpl index 9392cfd69c8f..6ee3a69fe714 100644 --- a/webtools/bugzilla/template/en/default/admin/components/edit.html.tmpl +++ b/webtools/bugzilla/template/en/default/admin/components/edit.html.tmpl @@ -17,6 +17,7 @@ # Rights Reserved. # # Contributor(s): Gavin Shelley + # Akamai Technologies #%] [%# INTERFACE: @@ -81,6 +82,24 @@ [% END %] + + + + + + [% INCLUDE global/userselect.html.tmpl + name => "initialcc" + id => "initialcc" + value => initial_cc_names + size => 64 + multiple => 5 + %] +
+ [% IF !Param("usemenuforusers") %] + Enter user names for the CC in a comma-separated list. + [% END %] + + [% terms.Bugs %]: diff --git a/webtools/bugzilla/template/en/default/admin/components/updated.html.tmpl b/webtools/bugzilla/template/en/default/admin/components/updated.html.tmpl index 43214f979479..a6f2c8b9def0 100644 --- a/webtools/bugzilla/template/en/default/admin/components/updated.html.tmpl +++ b/webtools/bugzilla/template/en/default/admin/components/updated.html.tmpl @@ -17,6 +17,8 @@ # Rights Reserved. # # Contributor(s): Gavin Shelley + # Akamai Technologies + # Max Kanat-Alexander #%] [%# INTERFACE: @@ -32,10 +34,15 @@ # # updated_initialqacontact: the default qa contact updated # + # updated_initialcc: the default initial cc list + # # comp: object; Bugzilla::Component object representing the component # user updated. # product: object; Bugzilla::Product object representing the product to # which the component belongs. + # + # initial_cc_names: a comma-separated list of the login names of + # the Initial CC, if it was updated. #%] [% title = BLOCK %]Updating Component '[% comp.name FILTER html %]' of Product @@ -72,11 +79,20 @@

Updated Component name to: '[% comp.name FILTER html %]'.

[% END %] +[% IF updated_initialcc %] + [% IF initial_cc_names %] +

Updated Default CC list to: + '[% initial_cc_names FILTER html %]'.

+ [% ELSE %] +

Removed the Default CC list.

+ [% END %] +[% END %] + [% UNLESS updated_description || updated_initialowner || - updated_initialqacontact || updated_name %] + updated_initialqacontact || updated_name || + updated_initialcc %]

Nothing changed for component '[% comp.name FILTER html %]'. [% END %] - [% PROCESS admin/components/footer.html.tmpl %] diff --git a/webtools/bugzilla/template/en/default/bug/create/create.html.tmpl b/webtools/bugzilla/template/en/default/bug/create/create.html.tmpl index 26e95523b81b..eb3aea2e4b0c 100644 --- a/webtools/bugzilla/template/en/default/bug/create/create.html.tmpl +++ b/webtools/bugzilla/template/en/default/bug/create/create.html.tmpl @@ -20,6 +20,8 @@ # Ville Skyttä # Shane H. W. Travis # Marc Schumann + # Akamai Technologies + # Max Kanat-Alexander #%] [% PROCESS "global/field-descs.none.tmpl" %] @@ -28,7 +30,6 @@ title = "Enter $terms.Bug: $product.name" style_urls = [ 'skins/standard/create_attachment.css' ] javascript_urls = [ "js/attachment.js" ] - onload="set_assign_to();" %] + + +   diff --git a/webtools/bugzilla/template/en/default/bug/knob.html.tmpl b/webtools/bugzilla/template/en/default/bug/knob.html.tmpl index 36712911e012..00ffcb053c0e 100644 --- a/webtools/bugzilla/template/en/default/bug/knob.html.tmpl +++ b/webtools/bugzilla/template/en/default/bug/knob.html.tmpl @@ -104,8 +104,8 @@
[% IF bug.isunconfirmed && bug.user.canconfirm %]