]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 38922: Default (Initial) CC list for each component
authormkanat%bugzilla.org <>
Thu, 21 Sep 2006 04:57:57 +0000 (04:57 +0000)
committermkanat%bugzilla.org <>
Thu, 21 Sep 2006 04:57:57 +0000 (04:57 +0000)
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=myk

Bugzilla/Bug.pm
Bugzilla/Component.pm
Bugzilla/DB/Schema.pm
editcomponents.cgi
process_bug.cgi
template/en/default/admin/components/create.html.tmpl
template/en/default/admin/components/edit.html.tmpl
template/en/default/admin/components/updated.html.tmpl
template/en/default/bug/create/create.html.tmpl
template/en/default/bug/knob.html.tmpl

index d309d0bc22de3136865fb0f0a7326269d7019dbf..5ac2f2b0b6b98f8d542cc06c5d4e4a67ef39a8d5 100755 (executable)
@@ -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];
 }
 
index abd3711f5ec9765c08f98da273a464d96ee44376..4b9856feba4bff1fbc4d8a6fc70530c0ee57567d 100644 (file)
@@ -14,6 +14,8 @@
 #
 # Contributor(s): Tiago R. Mello <timello@async.com.br>
 #                 Frédéric Buclin <LpSolit@gmail.com>
+#                 Max Kanat-Alexander <mkanat@bugzilla.org>
+#                 Akamai Technologies <bugzilla-dev@akamai.com>
 
 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<initial_cc>
+
+Returns an arrayref of L<Bugzilla::User> objects representing the
+Initial CC List.
+
 =item C<flag_types()>
 
   Description: Returns all bug and attachment flagtypes available for
index 938ef042ab46966b70ed7a43f632b8227b0aacc8..4235be5add8fac2329c6da9139eca03c927d3c93 100644 (file)
@@ -22,6 +22,7 @@
 #                 Max Kanat-Alexander <mkanat@bugzilla.org>
 #                 Lance Larsh <lance.larsh@oracle.com>
 #                 Dennis Melentyev <dennis.melentyev@infopulse.com.ua>
+#                 Akamai Technologies <bugzilla-dev@akamai.com>
 
 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
     # --------------
 
index c87bc0313cd9a8aec0aadd5b12c1622e1648f3d3..cc81cece7073c9357a7039dc7e03a531ff05743a 100755 (executable)
@@ -21,6 +21,7 @@
 # Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
 #                 Terry Weissman <terry@mozilla.org>
 #                 Frédéric Buclin <LpSolit@gmail.com>
+#                 Akamai Technologies <bugzilla-dev@akamai.com>
 #
 # 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)
index 1824dd7f34e798efa0f7b96cbdf33ed563d5bfb7..e671b9d76eb54706cf362fc7ce87a95b1bb09625 100755 (executable)
@@ -26,6 +26,7 @@
 #                 Jeff Hedlund <jeff.hedlund@matrixsi.com>
 #                 Frédéric Buclin <LpSolit@gmail.com>
 #                 Lance Larsh <lance.larsh@oracle.com>
+#                 Akamai Technologies <bugzilla-dev@akamai.com>
 
 # 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;
index 83c28ab85f64926dfb4852d8c21cd838de885a10..013ee861e669193294fc923808ff1878a854f49d 100644 (file)
@@ -17,6 +17,7 @@
   # Rights Reserved.
   #
   # Contributor(s): Gavin Shelley <bugzilla@chimpychompy.org>
+  #                 Akamai Technologies <bugzilla-dev@akamai.com>
   #%]
 
 [%# INTERFACE:
       </td>
     </tr>
 [% END %]
+    <tr>
+      <th align="right">
+        <label for="initialcc">Default CC List:</label>
+      </th>
+      <td>
+        [% INCLUDE global/userselect.html.tmpl
+           name => "initialcc"
+           id => "initialcc"
+           value => ""
+           size => 64
+           multiple => 5
+        %]
+        <br>
+        [% IF !Param("usemenuforusers") %]
+          <em>Enter user names for the CC in a comma-separated list.</em>
+        [% END %]
+      </td>
+    </tr>
   </table>
   <hr>
   <input type="submit" id="create" value="Add">
index 9392cfd69c8f3a71361c3a2a3fd2b87c66de1563..6ee3a69fe714fbfcd66ffaeceda3593d8997c372 100644 (file)
@@ -17,6 +17,7 @@
   # Rights Reserved.
   #
   # Contributor(s): Gavin Shelley <bugzilla@chimpychompy.org>
+  #                 Akamai Technologies <bugzilla-dev@akamai.com>
   #%]
 
 [%# INTERFACE:
 [% END %]
   
     </tr>
+    <tr>
+      <td valign="top">
+        <label for="initialcc">Default CC List:</label>
+      </td>
+      <td>
+        [% INCLUDE global/userselect.html.tmpl
+           name     => "initialcc"
+           id       => "initialcc"
+           value    => initial_cc_names
+           size     => 64
+           multiple => 5
+        %]
+        <br>
+        [% IF !Param("usemenuforusers") %]
+          <em>Enter user names for the CC in a comma-separated list.</em>
+        [% END %]
+      </td>
+    </tr>
     <tr>
       <td>[% terms.Bugs %]:</td>
       <td>
index 43214f97947935fceec30aceafb90f4aaa744641..a6f2c8b9def0b18fc2e73bf12da423dec40991b3 100644 (file)
@@ -17,6 +17,8 @@
   # Rights Reserved.
   #
   # Contributor(s): Gavin Shelley <bugzilla@chimpychompy.org>
+  #                 Akamai Technologies <bugzilla-dev@akamai.com>
+  #                 Max Kanat-Alexander <mkanat@bugzilla.org>
   #%]
 
 [%# INTERFACE:
   #
   # 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
   <p>Updated Component name to: '[% comp.name FILTER html %]'.</p>
 [% END %]
 
+[% IF updated_initialcc %]
+  [% IF initial_cc_names %]
+    <p>Updated Default CC list to:
+      '[% initial_cc_names FILTER html %]'.</p>
+  [% ELSE %]
+    <p>Removed the Default CC list.</p>
+  [% END %]
+[% END %]
+
 [% UNLESS updated_description || updated_initialowner || 
-          updated_initialqacontact || updated_name %]
+          updated_initialqacontact || updated_name  ||
+          updated_initialcc %]
   <p>Nothing changed for component '[% comp.name FILTER html %]'.
 [% END %]
-   
 
 [% PROCESS admin/components/footer.html.tmpl %]
 
index 26e95523b81bf67dadb799ccf3da0a0042009f55..eb3aea2e4b0cc1651e0cb81538e9a0457bb84c8f 100644 (file)
@@ -20,6 +20,8 @@
   #                 Ville Skyttä <ville.skytta@iki.fi>
   #                 Shane H. W. Travis <travis@sedsystems.ca>
   #                 Marc Schumann <wurblzap@gmail.com>
+  #                 Akamai Technologies <bugzilla-dev@akamai.com>
+  #                 Max Kanat-Alexander <mkanat@bugzilla.org>
   #%]
 
 [% 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();"
 %]
 
 <script type="text/javascript">
@@ -36,6 +37,7 @@
 
 var initialowners = new Array([% product.components.size %]);
 var last_initialowner;
+var initialccs = new Array([% product.components.size %]);
 var components = new Array([% product.components.size %]);
 var flags = new Array([% product.components.size %]);
 [% IF Param("useqacontact") %]
@@ -60,6 +62,13 @@ var flags = new Array([% product.components.size %]);
     [% IF Param("useqacontact") %]
         initialqacontacts[[% count %]] = "[% c.default_qa_contact.login FILTER js %]";
     [% END %]
+
+    [% SET initial_cc_list = [] %]
+    [% FOREACH cc_user = c.initial_cc %]
+      [% initial_cc_list.push(cc_user.login) %]
+    [% END %]
+    initialccs[[% count %]] = "[% initial_cc_list.join(', ') FILTER js %]";
+
     [% count = count + 1 %]
 [%- END %]
 
@@ -90,6 +99,9 @@ function set_assign_to() {
             form.assigned_to.value = owner;
             last_initialowner = owner;
         }
+
+        document.getElementById('initial_cc').innerHTML = initialccs[index];
+
         [% IF Param("useqacontact") %]
             var contact = initialqacontacts[index];
             if (qa_contact == last_initialqacontact
@@ -317,6 +329,18 @@ function handleWantsAttachment(wants_attachment) {
        %]
     </td>
   </tr>
+
+  <tr>
+    <th align="right">Default CC:</th>
+    <td colspan="2">
+      <div id="initial_cc">
+          <!-- This has to happen after everything above renders,
+               and onload doesn't work. So this is as good a place
+               as any to put it. -->
+          <script type="text/javascript">set_assign_to();</script>
+      </div>
+   </td>
+  </tr>
   
   <tr>
     <td>&nbsp;</td>
index 36712911e012b3e629b7aca7d55de6f3ebc47030..00ffcb053c0e433191f17cc98d23afdeb2740081 100644 (file)
         <input type="radio" id="knob-reassign-cmp" name="knob" value="reassignbycomponent">
         <label for="knob-reassign-cmp">
           Reassign [% terms.bug %] to default assignee
-          [% " and QA contact" IF Param('useqacontact') %]
-          of selected component
+          [% " and QA contact" IF Param('useqacontact') %],
+          and add Default CC, of selected component
         </label>
         <br>
         [% IF bug.isunconfirmed && bug.user.canconfirm %]