diff options
-rw-r--r-- | Bugzilla/Component.pm | 5 | ||||
-rw-r--r-- | Bugzilla/Version.pm | 9 | ||||
-rwxr-xr-x | editproducts.cgi | 27 | ||||
-rwxr-xr-x | sanitycheck.cgi | 20 | ||||
-rw-r--r-- | template/en/default/admin/components/edit-common.html.tmpl | 18 | ||||
-rw-r--r-- | template/en/default/admin/products/create.html.tmpl | 17 | ||||
-rw-r--r-- | template/en/default/admin/products/edit-common.html.tmpl | 36 | ||||
-rw-r--r-- | template/en/default/admin/sanitycheck/messages.html.tmpl | 7 | ||||
-rw-r--r-- | template/en/default/global/messages.html.tmpl | 4 | ||||
-rw-r--r-- | template/en/default/global/user-error.html.tmpl | 10 |
10 files changed, 120 insertions, 33 deletions
diff --git a/Bugzilla/Component.pm b/Bugzilla/Component.pm index 215119715..ceca7e794 100644 --- a/Bugzilla/Component.pm +++ b/Bugzilla/Component.pm @@ -155,6 +155,11 @@ sub remove_from_db { $dbh->bz_start_transaction(); + # Products must have at least one component. + if (scalar(@{$self->product->components}) == 1) { + ThrowUserError('component_is_last', { comp => $self }); + } + if ($self->bug_count) { if (Bugzilla->params->{'allowbugdeletion'}) { require Bugzilla::Bug; diff --git a/Bugzilla/Version.pm b/Bugzilla/Version.pm index 7f53add13..250c474ca 100644 --- a/Bugzilla/Version.pm +++ b/Bugzilla/Version.pm @@ -143,12 +143,21 @@ sub remove_from_db { my $self = shift; my $dbh = Bugzilla->dbh; + $dbh->bz_start_transaction(); + + # Products must have at least one version. + if (scalar(@{$self->product->versions}) == 1) { + ThrowUserError('version_is_last', { version => $self }); + } + # The version cannot be removed if there are bugs # associated with it. if ($self->bug_count) { ThrowUserError("version_has_bugs", { nb => $self->bug_count }); } $self->SUPER::remove_from_db(); + + $dbh->bz_commit_transaction(); } ############################### diff --git a/editproducts.cgi b/editproducts.cgi index 6d5c5e593..ed6596130 100755 --- a/editproducts.cgi +++ b/editproducts.cgi @@ -37,6 +37,7 @@ use Bugzilla::Util; use Bugzilla::Error; use Bugzilla::Group; use Bugzilla::Product; +use Bugzilla::Component; use Bugzilla::Classification; use Bugzilla::Token; @@ -176,7 +177,13 @@ if ($action eq 'new') { check_token_data($token, 'add_product'); - my %create_params = ( + Bugzilla::User::match_field ({ + 'initialowner' => { 'type' => 'single' }, + 'initialqacontact' => { 'type' => 'single' }, + 'initialcc' => { 'type' => 'multi' }, + }); + + my %product_create_params = ( classification => $classification_name, name => $product_name, description => scalar $cgi->param('description'), @@ -186,7 +193,23 @@ if ($action eq 'new') { create_series => scalar $cgi->param('createseries'), allows_unconfirmed => scalar $cgi->param('allows_unconfirmed'), ); - my $product = Bugzilla::Product->create(\%create_params); + + $dbh->bz_start_transaction(); + my $product = Bugzilla::Product->create(\%product_create_params); + + my @initial_cc = $cgi->param('initialcc'); + my %component_create_params = ( + product => $product, + name => trim($cgi->param('component') || ''), + description => scalar $cgi->param('comp_desc'), + initialowner => scalar $cgi->param('initialowner'), + initialqacontact => scalar $cgi->param('initialqacontact'), + initial_cc => \@initial_cc, + create_series => scalar $cgi->param('createseries'), + ); + + Bugzilla::Component->create(\%component_create_params); + $dbh->bz_commit_transaction(); delete_token($token); diff --git a/sanitycheck.cgi b/sanitycheck.cgi index da308aaeb..7b8177d83 100755 --- a/sanitycheck.cgi +++ b/sanitycheck.cgi @@ -748,6 +748,26 @@ if (scalar(@invalid_flags)) { } ########################################################################### +# Check for products with no component +########################################################################### + +Status('product_check_start'); + +my $products_missing_data = $dbh->selectcol_arrayref( + 'SELECT DISTINCT products.name + FROM products + LEFT JOIN components + ON components.product_id = products.id + LEFT JOIN versions + ON versions.product_id = products.id + WHERE components.id IS NULL + OR versions.id IS NULL'); + +if (scalar(@$products_missing_data)) { + Status('product_alert', { name => $_ }, 'alert') foreach @$products_missing_data; +} + +########################################################################### # General bug checks ########################################################################### diff --git a/template/en/default/admin/components/edit-common.html.tmpl b/template/en/default/admin/components/edit-common.html.tmpl index 069b56cfd..6f65095af 100644 --- a/template/en/default/admin/components/edit-common.html.tmpl +++ b/template/en/default/admin/components/edit-common.html.tmpl @@ -22,16 +22,20 @@ # comp: object; Bugzilla::Component object. #%] +[%# When called from the "New Product" page, the component description field + # must have a name different from the product description field. %] +[% DEFAULT desc_name = "description" %] + <tr> - <td valign="top">Component:</td> + <th align="right">Component:</th> <td><input size="64" maxlength="64" name="component" value="[%- comp.name FILTER html %]"></td> </tr> <tr> - <td valign="top">Component Description:</td> + <th align="right">Component Description:</th> <td> [% INCLUDE global/textarea.html.tmpl - name = 'description' + name = desc_name minrows = 4 cols = 64 wrap = 'virtual' @@ -40,7 +44,7 @@ </td> </tr> <tr> - <td valign="top"><label for="initialowner">Default Assignee:</label></td> + <th align="right"><label for="initialowner">Default Assignee:</label></th> <td> [% INCLUDE global/userselect.html.tmpl name => "initialowner" @@ -52,7 +56,7 @@ </tr> [% IF Param('useqacontact') %] <tr> - <td valign="top"><label for="initialqacontact">Default QA contact:</label></td> + <th align="right"><label for="initialqacontact">Default QA contact:</label></th> <td> [% INCLUDE global/userselect.html.tmpl name => "initialqacontact" @@ -65,9 +69,7 @@ </tr> [% END %] <tr> - <td valign="top"> - <label for="initialcc">Default CC List:</label> - </td> + <th align="right"><label for="initialcc">Default CC List:</label></th> <td> [% INCLUDE global/userselect.html.tmpl name => "initialcc" diff --git a/template/en/default/admin/products/create.html.tmpl b/template/en/default/admin/products/create.html.tmpl index 3af81fb23..2b60645ab 100644 --- a/template/en/default/admin/products/create.html.tmpl +++ b/template/en/default/admin/products/create.html.tmpl @@ -25,7 +25,8 @@ [% PROCESS global/header.html.tmpl title = title style_urls = ['skins/standard/admin.css'] - javascript_urls = ['js/util.js'] + javascript_urls = ['js/util.js', 'js/field.js'] + yui = [ 'autocomplete' ] %] [% DEFAULT @@ -42,7 +43,7 @@ <tr> <th align="right">Version:</th> - <td><input size="64" maxlength="255" name="version" + <td><input size="20" maxlength="64" name="version" value="[% version FILTER html %]"> </td> </tr> @@ -52,6 +53,18 @@ <input type="checkbox" name="createseries" value="1" checked="checked"> </td> </tr> + + <tr> + <td colspan="2"> </td> + </tr> + <tr> + <td colspan="2"> + This product must have at least one component. + You will be able to create additional components later: + </td> + </tr> + + [% PROCESS "admin/components/edit-common.html.tmpl" desc_name = "comp_desc" %] </table> <input type="submit" id="add-product" value="Add"> diff --git a/template/en/default/admin/products/edit-common.html.tmpl b/template/en/default/admin/products/edit-common.html.tmpl index 4812707cd..eac33ea9a 100644 --- a/template/en/default/admin/products/edit-common.html.tmpl +++ b/template/en/default/admin/products/edit-common.html.tmpl @@ -25,7 +25,7 @@ [% IF Param('useclassification') %] <tr> - <th align="right"><b>Classification:</b></th> + <th align="right">Classification:</th> <td><b>[% classification.name FILTER html %]</b></td> </tr> [% END %] @@ -43,6 +43,23 @@ </td> </tr> +<tr> + <th align="right">Open for [% terms.bug %] entry:</th> + <td><input type="checkbox" name="is_active" value="1" + [% ' checked="checked"' IF product.is_active %]> + </td> +</tr> +<tr> + <th align="right"> + <label for="allows_unconfirmed">Enable the + [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status + in this product:</label> + </th> + <td><input type="checkbox" id="allows_unconfirmed" name="allows_unconfirmed" + [% ' checked="checked"' IF product.allows_unconfirmed %]> + </td> +</tr> + [% IF Param('usetargetmilestone') -%] <tr> <th align="right">Default milestone:</th> @@ -63,21 +80,4 @@ </tr> [% END %] -<tr> - <th align="right">Open for [% terms.bug %] entry:</th> - <td><input type="checkbox" name="is_active" value="1" - [% ' checked="checked"' IF product.is_active %]> - </td> -</tr> -<tr> - <th align="right"> - <label for="allows_unconfirmed">Enable the - [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status - in this product:</label> - </th> - <td><input type="checkbox" id="allows_unconfirmed" name="allows_unconfirmed" - [% ' checked="checked"' IF product.allows_unconfirmed %]> - </td> -</tr> - [% Hook.process('rows') %] diff --git a/template/en/default/admin/sanitycheck/messages.html.tmpl b/template/en/default/admin/sanitycheck/messages.html.tmpl index 88264d820..494a8cdf0 100644 --- a/template/en/default/admin/sanitycheck/messages.html.tmpl +++ b/template/en/default/admin/sanitycheck/messages.html.tmpl @@ -229,6 +229,13 @@ [% ELSIF san_tag == "profile_login_start" %] Checking profile logins. + [% ELSIF san_tag == "product_alert" %] + Product <a href="editproducts.cgi?product=[% name FILTER html%]"> + [%- name FILTER html %]</a> has no components or no versions. + + [% ELSIF san_tag == "product_check_start" %] + Checking products with no components or versions. + [% ELSIF san_tag == "profile_login_alert" %] Bad profile email address, id=[% id FILTER html %], <[% email FILTER html %]>. diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl index 01eb32651..a57449d7c 100644 --- a/template/en/default/global/messages.html.tmpl +++ b/template/en/default/global/messages.html.tmpl @@ -796,9 +796,7 @@ [% ELSIF message_tag == "product_created" %] [% title = "Product Created" %] - The product <em>[% product.name FILTER html %]</em> has been created. You will need to - <a href="editcomponents.cgi?action=add&product=[% product.name FILTER uri %]"> - add at least one component</a> before anyone can enter [% terms.bugs %] against this product. + The product <em>[% product.name FILTER html %]</em> has been created. [% ELSIF message_tag == "product_deleted" %] [% title = "Product Deleted" %] diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl index 52c6156b6..7dac2ee55 100644 --- a/template/en/default/global/user-error.html.tmpl +++ b/template/en/default/global/user-error.html.tmpl @@ -373,6 +373,11 @@ You must reassign those [% terms.bugs %] to another component before you can delete this one. + [% ELSIF error == "component_is_last" %] + [% title = BLOCK %]Last Component in this Product[% END %] + '[% comp.name FILTER html %]' is the last component of the + '[% comp.product.name FILTER html %]' product. You cannot delete it. + [% ELSIF error == "component_name_too_long" %] [% title = "Component Name Is Too Long" %] The name of a component is limited to [% constants.MAX_COMPONENT_SIZE FILTER html %] @@ -1630,6 +1635,11 @@ version! You must reassign those [% terms.bugs %] to another version before you can delete this one. + [% ELSIF error == "version_is_last" %] + [% title = BLOCK %]Last Version in this Product[% END %] + '[% version.name FILTER html %]' is the last version of the + '[% version.product.name FILTER html %]' product. You cannot delete it. + [% ELSIF error == "users_deletion_disabled" %] [% title = "Deletion not activated" %] [% admindocslinks = {'useradmin.html' => 'User administration'} %] |