From: Kohei Yoshino Date: Tue, 6 Aug 2019 16:17:34 +0000 (-0400) Subject: Bug 1562364 - Enforce setting bug type when creating bug through API X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e72d023440c50f65a928bd3eead2ee35d60610cb;p=thirdparty%2Fbugzilla.git Bug 1562364 - Enforce setting bug type when creating bug through API --- diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index bc5416fc4..73d59e75f 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -121,7 +121,7 @@ sub VALIDATORS { bug_file_loc => \&_check_bug_file_loc, bug_severity => \&_check_select_field, bug_status => \&_check_bug_status, - bug_type => \&_check_select_field, + bug_type => \&_check_bug_type, cc => \&_check_cc, comment => \&_check_comment, component => \&_check_component, @@ -904,24 +904,6 @@ sub create { $params->{priority} = Bugzilla->params->{defaultpriority} unless defined $params->{priority}; - # Bug type can be defined at the component, product or instance level - unless (defined $params->{bug_type}) { - my $product - = (defined $params->{product}) - ? Bugzilla::Product->new({name => $params->{product}, cache => 1}) - : undef; - my $component - = ($product && defined $params->{component}) - ? Bugzilla::Component->new({name => $params->{component}, product => $product, cache => 1}) - : undef; - # The component's default bug type inherits or overrides the default bug - # type of the product or instance - $params->{bug_type} - = ($component) - ? $component->default_bug_type - : Bugzilla->params->{default_bug_type}; - } - # BMO - per-product hw/os defaults if (!defined $params->{rep_platform} || !defined $params->{op_sys}) { if (my $product @@ -1879,6 +1861,35 @@ sub _check_bug_status { return $new_status->name; } +sub _check_bug_type { + my ($invocant, $type, undef, $params) = @_; + + if (defined $type && trim($type)) { + return $invocant->_check_select_field($type, 'bug_type'); + } + + if (Bugzilla->params->{'require_bug_type'}) { + ThrowUserError('bug_type_required'); + } + + if (blessed $invocant) { + return $invocant->component_obj->default_bug_type; + } + + my $product + = (defined $params->{product}) + ? Bugzilla::Product->new({name => $params->{product}, cache => 1}) + : undef; + my $component + = ($product && defined $params->{component}) + ? Bugzilla::Component->new({name => $params->{component}, product => $product, cache => 1}) + : undef; + + return $component + ? $component->default_bug_type + : Bugzilla->params->{default_bug_type}; +} + sub _check_cc { my ($invocant, $ccs, undef, $params) = @_; my $component diff --git a/Bugzilla/Config/BugFields.pm b/Bugzilla/Config/BugFields.pm index 3100412d3..cd913e419 100644 --- a/Bugzilla/Config/BugFields.pm +++ b/Bugzilla/Config/BugFields.pm @@ -40,6 +40,8 @@ sub get_param_list { {name => 'use_see_also', type => 'b', default => 1}, + {name => 'require_bug_type', type => 'b', default => 1}, + { name => 'default_bug_type', type => 's', diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 503befdb9..271c19cc9 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -259,7 +259,6 @@ use constant DEFAULT_FIELDS => ( name => 'bug_type', desc => 'Type', in_new_bugmail => 1, - is_mandatory => 1, type => FIELD_TYPE_SINGLE_SELECT, buglist => 1 }, diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index 5b1dca146..6faaba147 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -3737,7 +3737,8 @@ in by the developer, compared to the developer's other bugs. =item C (string) B - How severe the bug is. -=item C (string) B - The basic category of the bug. +=item C (string) B - The basic category of the bug. Some +Bugzilla installations require this to be specified. =item C (string) - A brief alias for the bug that can be used instead of a bug number when accessing this bug. Must be unique in @@ -3873,6 +3874,10 @@ the type id value to update or add a flag. The flag type is inactive and cannot be used to create new flags. +=item 135 (Bug Type Required) + +You didn't specify a type for the bug. + =item 504 (Invalid User) Either the QA Contact, Assignee, or CC lists have some invalid user diff --git a/Bugzilla/WebService/Constants.pm b/Bugzilla/WebService/Constants.pm index 7198dac2c..92be21794 100644 --- a/Bugzilla/WebService/Constants.pm +++ b/Bugzilla/WebService/Constants.pm @@ -157,6 +157,9 @@ use constant WS_ERROR_CODE => { flag_type_not_unique => 133, flag_type_inactive => 134, + # Bug Type errors + bug_type_required => 135, + # Authentication errors are usually 300-400. invalid_username_or_password => 300, account_disabled => 301, diff --git a/docs/en/rst/administering/parameters.rst b/docs/en/rst/administering/parameters.rst index f30691aa3..50f09973a 100644 --- a/docs/en/rst/administering/parameters.rst +++ b/docs/en/rst/administering/parameters.rst @@ -257,6 +257,9 @@ use_see_also prevents addition of new relationships, but existing ones will continue to appear. +require_bug_type + If this is on, users are asked to choose a type when they file a new bug. + default_bug_type This is the type that newly entered bugs are set to. diff --git a/docs/en/rst/api/core/v1/bug.rst b/docs/en/rst/api/core/v1/bug.rst index f42e268cf..8945219d0 100644 --- a/docs/en/rst/api/core/v1/bug.rst +++ b/docs/en/rst/api/core/v1/bug.rst @@ -653,7 +653,8 @@ priority string (defaulted) What order the bug will be fixed in by the developer, compared to the developer's other bugs. severity string (defaulted) How severe the bug is. -type string (defaulted) The basic category of the bug. +type string (defaulted) The basic category of the bug. Some + Bugzilla installations require this to be specified. alias string The alias for the bug that can be used instead of a bug number when accessing this bug. Must be unique in all of this Bugzilla. @@ -762,6 +763,8 @@ id int This is the ID of the newly-filed bug. the type id value to update or add a flag. * 134 (Inactive Flag Type) The flag type is inactive and cannot be used to create new flags. +* 135 (Bug Type Required) + You didn't specify a type for the bug. * 504 (Invalid User) Either the QA Contact, Assignee, or CC lists have some invalid user in them. The error message will have more details. diff --git a/docs/en/rst/api/core/v1/bugzilla.rst b/docs/en/rst/api/core/v1/bugzilla.rst index c934d33ac..98ba80e5e 100644 --- a/docs/en/rst/api/core/v1/bugzilla.rst +++ b/docs/en/rst/api/core/v1/bugzilla.rst @@ -207,6 +207,7 @@ Example response for authenticated user: "noresolveonopenblockers" : "0", "password_complexity" : "no_constraints", "rememberlogin" : "on", + "require_bug_type" : "1", "requirelogin" : "0", "urlbase" : "http://bugzilla.example.com/", "use_regression_fields" : "1", @@ -247,6 +248,7 @@ A logged-in user can access the following parameters (listed alphabetically): * noresolveonopenblockers * password_complexity * rememberlogin +* require_bug_type * requirelogin * search_allow_no_criteria * urlbase diff --git a/extensions/BugModal/template/en/default/bug_modal/edit.html.tmpl b/extensions/BugModal/template/en/default/bug_modal/edit.html.tmpl index 9841d7f37..9bdd150ab 100644 --- a/extensions/BugModal/template/en/default/bug_modal/edit.html.tmpl +++ b/extensions/BugModal/template/en/default/bug_modal/edit.html.tmpl @@ -463,6 +463,7 @@ field = bug_fields.bug_type field_type = constants.FIELD_TYPE_SINGLE_SELECT use_buttons = 1 + required = Param('require_bug_type') help = "https://wiki.mozilla.org/BMO/UserGuide/BugFields#bug_type" %] diff --git a/extensions/BugModal/template/en/default/bug_modal/field.html.tmpl b/extensions/BugModal/template/en/default/bug_modal/field.html.tmpl index e3dedd685..fcaa08f23 100644 --- a/extensions/BugModal/template/en/default/bug_modal/field.html.tmpl +++ b/extensions/BugModal/template/en/default/bug_modal/field.html.tmpl @@ -29,7 +29,8 @@ # edit HTML instead of replacing it. forces edit_only (default: false); # default: (string) default value (e.g. used as a placeholder in user fields) # help: (string) optional URL that describes the field (requires a label to be defined and visible) - # required: (boolean) if the field is required. (At present, only implemented for FIELD_TYPE_FREETEXT) + # required: (boolean) if the field is required. (At present, only implemented for FIELD_TYPE_FREETEXT + # and FIELD_TYPE_SINGLE_SELECT) # action: (hash) show a button to the right of the edit field (user fields only currently). keys: # id: (string) optional button id # class: (string) optional button class @@ -191,12 +192,12 @@ END; [% IF use_buttons %]
+ [%= 'aria-required="true"' IF (field.is_mandatory || required) %] [%= aria_labelledby_html FILTER none %]> [% IF values.defined %] [% FOREACH v IN values %] [% NEXT IF NOT v.is_active AND NOT value.contains(v.name).size %] [% NEXT IF NOT bug.check_can_change_field(name, bug.${field_name}, v.name) %] - [% NEXT IF field.is_mandatory && v.name == '--' %] + [% NEXT IF (field.is_mandatory || required) && v.name == '--' %]
diff --git a/js/field.js b/js/field.js index ea738b6bf..b21704cd3 100644 --- a/js/field.js +++ b/js/field.js @@ -40,6 +40,8 @@ function validateEnterBug(theform) { var attach_data = theform.data; var attach_desc = theform.description; + const $bug_type_group = document.querySelector('#bug_type'); + var current_errors = YAHOO.util.Dom.getElementsByClassName( 'validation_error_text', null, theform); for (var i = 0; i < current_errors.length; i++) { @@ -77,8 +79,8 @@ function validateEnterBug(theform) { _errorFor(component); focus_me = component; } - if (!bug_type.value) { - _errorFor(document.querySelector('#bug_type')); + if ($bug_type_group.matches('[aria-required="true"]') && !bug_type.value) { + _errorFor($bug_type_group); focus_me = bug_type[0]; } diff --git a/qa/t/lib/QA/Tests.pm b/qa/t/lib/QA/Tests.pm index 3d53cefcc..92eb40bc1 100644 --- a/qa/t/lib/QA/Tests.pm +++ b/qa/t/lib/QA/Tests.pm @@ -22,6 +22,7 @@ use constant INVALID_BUG_ALIAS => 'aaaaaaa12345'; use constant PRIVATE_BUG_USER => 'QA_Selenium_TEST'; use constant CREATE_BUG => { + 'type' => 'defect', 'priority' => 'Highest', 'status' => 'CONFIRMED', 'version' => 'unspecified', diff --git a/qa/t/webservice_bug_create.t b/qa/t/webservice_bug_create.t index 34a03778a..c36aefb25 100644 --- a/qa/t/webservice_bug_create.t +++ b/qa/t/webservice_bug_create.t @@ -13,7 +13,7 @@ use strict; use warnings; use lib qw(lib ../../lib ../../local/lib/perl5); use Storable qw(dclone); -use Test::More tests => 293; +use Test::More tests => 311; use QA::Util; use QA::Tests qw(create_bug_fields PRIVATE_BUG_USER); @@ -71,6 +71,14 @@ my $fields = { }, }, + type => { + undefined => {faultstring => 'you must first choose a type', value => undef}, + invalid => { + faultstring => "There is no Type named 'does-not-exist'.", + value => 'does-not-exist' + }, + }, + severity => { undefined => {faultstring => 'You must select/enter a Severity.', value => ''}, invalid => { @@ -155,6 +163,7 @@ my @tests = ( user => PRIVATE_BUG_USER, args => { %$bug_fields, + type => 'defect', product => 'QA-Selenium-TEST', component => 'QA-Selenium-TEST', target_milestone => 'QAMilestone', diff --git a/qa/t/webservice_bug_fields.t b/qa/t/webservice_bug_fields.t index f0e280353..e60f76677 100644 --- a/qa/t/webservice_bug_fields.t +++ b/qa/t/webservice_bug_fields.t @@ -83,7 +83,7 @@ use constant ALL_SELECT_FIELDS => use constant PRODUCT_FIELDS => qw(version target_milestone component); use constant ALL_FIELDS => (GLOBAL_GENERAL_FIELDS, ALL_SELECT_FIELDS, PRODUCT_FIELDS); -use constant MANDATORY_FIELDS => qw(short_desc product version component bug_type); +use constant MANDATORY_FIELDS => qw(short_desc product version component); use constant PUBLIC_PRODUCT => 'Another Product'; use constant PRIVATE_PRODUCT => 'QA-Selenium-TEST'; diff --git a/qa/t/webservice_bug_get.t b/qa/t/webservice_bug_get.t index d4df37f17..5a6918a14 100644 --- a/qa/t/webservice_bug_get.t +++ b/qa/t/webservice_bug_get.t @@ -16,7 +16,7 @@ use Data::Dumper; use DateTime; use QA::Util; use QA::Tests qw(bug_tests PRIVATE_BUG_USER); -use Test::More tests => 1012; +use Test::More tests => 1036; my ($config, @clients) = get_rpc_clients(); my $xmlrpc = $clients[0]; diff --git a/qa/t/webservice_bug_get_bugs.t b/qa/t/webservice_bug_get_bugs.t index fae9d0842..cdb261f36 100644 --- a/qa/t/webservice_bug_get_bugs.t +++ b/qa/t/webservice_bug_get_bugs.t @@ -16,7 +16,7 @@ use Data::Dumper; use DateTime; use QA::Util; use QA::Tests qw(bug_tests PRIVATE_BUG_USER); -use Test::More tests => 1012; +use Test::More tests => 1036; my ($config, @clients) = get_rpc_clients(); my $xmlrpc = $clients[0]; diff --git a/qa/t/webservice_bug_search.t b/qa/t/webservice_bug_search.t index 7b6d7dade..c873c74e7 100644 --- a/qa/t/webservice_bug_search.t +++ b/qa/t/webservice_bug_search.t @@ -19,7 +19,7 @@ use List::MoreUtils qw(uniq); use Test::More; my ($config, @clients) = get_rpc_clients(); -plan tests => $config->{test_extensions} ? 515 : 506; +plan tests => $config->{test_extensions} ? 533 : 524; my ($public_bug, $private_bug) = $clients[0]->bz_create_test_bugs('private'); diff --git a/template/en/default/admin/params/bugfields.html.tmpl b/template/en/default/admin/params/bugfields.html.tmpl index 2052d48b3..bec6a61dd 100644 --- a/template/en/default/admin/params/bugfields.html.tmpl +++ b/template/en/default/admin/params/bugfields.html.tmpl @@ -66,6 +66,9 @@ default_bug_type => "This is the type that newly entered $terms.bugs are set to.", + require_bug_type => + "If this is on, users are asked to choose a type when they file a new ${terms.bug}.", + collapsed_comment_tags => "A comma separated list of tags which, when applied " _ "to comments, will cause them to be collapsed by default", } diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index 843da7360..9075b1c98 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -341,7 +341,7 @@ TUI_hide_default('expert_fields'); [% INCLUDE bug/field.html.tmpl bug = default, field = bug_fields.bug_type, editable = 1, use_buttons = 1, - value = default.bug_type %] + value = default.bug_type, required = Param('require_bug_type') %] [% needs_extra_tr = 1 %] diff --git a/template/en/default/bug/field-label.html.tmpl b/template/en/default/bug/field-label.html.tmpl index 5d5c5452c..2625c3707 100644 --- a/template/en/default/bug/field-label.html.tmpl +++ b/template/en/default/bug/field-label.html.tmpl @@ -25,11 +25,15 @@ # rowspan: a "rowspan" value for the label's . # tag_name: the tag to use to surround the label # accesskey: access key for the label + # required: Whether the field should be entered or selected. This can override + # the field definition's `is_mandatory` property. + # use_buttons: Whether the field should be displayed as rich radio buttons. + # Use this for a single-select field with a few options. #%] [% DEFAULT tag_name = "th" %] <[% tag_name FILTER html %] class="field_label [% ' bz_hidden_field' IF hidden %] - [%- ' required' IF field.is_mandatory && NOT bug.id; ' for-buttons' IF use_buttons %]" + [%- ' required' IF (field.is_mandatory || required) && NOT bug.id; ' for-buttons' IF use_buttons %]" id="field_label_[% field.name FILTER html %]" [% IF rowspan %] rowspan="[% rowspan FILTER html %]"[% END %]> diff --git a/template/en/default/bug/field.html.tmpl b/template/en/default/bug/field.html.tmpl index e47542ada..4aa4dddfc 100644 --- a/template/en/default/bug/field.html.tmpl +++ b/template/en/default/bug/field.html.tmpl @@ -28,6 +28,10 @@ # override_legal_values (optional): The list of legal values, for select fields. # editable: Whether the field should be displayed as an editable # or as just the plain text of its value. + # required: Whether the field should be entered or selected. This can override + # the field definition's `is_mandatory` property. + # use_buttons: Whether the field should be displayed as rich radio buttons. + # Use this for a single-select field with a few options. # allow_dont_change: display the --do_not_change-- option for select fields. # value_span: A colspan for the table cell containing # the field value. @@ -58,13 +62,13 @@ value="[% value FILTER html %]" size="40" maxlength="[% constants.MAX_FREETEXT_LENGTH FILTER none %]" [% IF field.type == constants.FIELD_TYPE_INTEGER %] pattern="\d+[% IF dontchange %]|[% dontchange FILTER html %][% END %]" [% END %] - [% ' aria-required="true"' IF field.is_mandatory %]> + [% ' aria-required="true"' IF (field.is_mandatory || required) %]> [% CASE [constants.FIELD_TYPE_DATETIME, constants.FIELD_TYPE_DATE] %] [% size = (field.type == constants.FIELD_TYPE_DATE) ? 10 : 20 %]