diff --git a/Bugzilla/Config/BugFields.pm b/Bugzilla/Config/BugFields.pm index ca1ef6230..8afd71b33 100644 --- a/Bugzilla/Config/BugFields.pm +++ b/Bugzilla/Config/BugFields.pm @@ -102,9 +102,10 @@ sub get_param_list my $legal = {}; for (qw(priority bug_severity platform op_sys)) { - $legal->{$_} = [ Bugzilla->get_field($_)->legal_value_names ]; + # Ignore evaluation errors - this piece of code may be called in checksetup.pl, + # fielddefs table may not be created at that time... + $legal->{$_} = eval { Bugzilla->get_field($_)->legal_value_names } || []; } - my @param_list = ( { name => 'useclassification', diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 1774527cd..ce1c91659 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -541,6 +541,7 @@ use constant ABSTRACT_SCHEMA => { mailhead => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, sortkey => {TYPE => 'INT2', NOTNULL => 1}, obsolete => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, + nullable => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, enter_bug => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, buglist => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}, visibility_field_id => {TYPE => 'INT4', REFERENCES => {TABLE => 'fielddefs', COLUMN => 'id'}}, diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 9ae9675eb..8afc76754 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -102,6 +102,7 @@ use constant DB_COLUMNS => qw( mailhead sortkey obsolete + nullable enter_bug clone_bug buglist @@ -123,6 +124,7 @@ use constant VALIDATORS => { buglist => \&Bugzilla::Object::check_boolean, mailhead => \&Bugzilla::Object::check_boolean, obsolete => \&Bugzilla::Object::check_boolean, + nullable => \&Bugzilla::Object::check_boolean, sortkey => \&_check_sortkey, type => \&_check_type, visibility_field_id => \&_check_visibility_field_id, @@ -138,6 +140,7 @@ use constant UPDATE_COLUMNS => qw( mailhead sortkey obsolete + nullable enter_bug clone_bug buglist @@ -168,7 +171,7 @@ use constant SQL_DEFINITIONS => { # These are used by populate_field_definitions to populate # the fielddefs table. use constant DEFAULT_FIELDS => ( - {name => 'bug_id', desc => 'Bug ID', buglist => 1, in_new_bugmail => 1}, + {name => 'bug_id', desc => 'Bug ID', buglist => 1, in_new_bugmail => 1}, {name => 'short_desc', desc => 'Summary', buglist => 1, in_new_bugmail => 1}, {name => 'classification', desc => 'Classification', buglist => 1, in_new_bugmail => 1}, {name => 'product', desc => 'Product', buglist => 1, in_new_bugmail => 1, type => FIELD_TYPE_SINGLE_SELECT}, @@ -426,10 +429,21 @@ sub obsolete { return $_[0]->{obsolete} } =over +=item C + +a boolean specifying whether NULL value is allowed for this field + +=back + +=cut + +sub nullable { return $_[0]->{nullable} } + +=over + =item C -A boolean specifying whether or not this field should appear on -enter_bug.cgi +A boolean specifying whether this field should appear on enter_bug.cgi =back @@ -736,6 +750,8 @@ They will throw an error if you try to set the values to something invalid. =item C +=item C + =item C =item C @@ -754,6 +770,7 @@ sub set_description { $_[0]->set('description', $_[1]); } sub set_enter_bug { $_[0]->set('enter_bug', $_[1]); } sub set_clone_bug { $_[0]->set('clone_bug', $_[1]); } sub set_obsolete { $_[0]->set('obsolete', $_[1]); } +sub set_nullable { $_[0]->set('nullable', $_[1]); } sub set_sortkey { $_[0]->set('sortkey', $_[1]); } sub set_in_new_bugmail { $_[0]->set('mailhead', $_[1]); } sub set_buglist { $_[0]->set('buglist', $_[1]); } diff --git a/Bugzilla/Field/Choice.pm b/Bugzilla/Field/Choice.pm index 314bd6892..971c19487 100644 --- a/Bugzilla/Field/Choice.pm +++ b/Bugzilla/Field/Choice.pm @@ -1,31 +1,10 @@ -# -*- Mode: perl; indent-tabs-mode: nil -*- -# -# The contents of this file are subject to the Mozilla Public -# License Version 1.1 (the "License"); you may not use this file -# except in compliance with the License. You may obtain a copy of -# the License at http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS -# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -# implied. See the License for the specific language governing -# rights and limitations under the License. -# -# The Initial Developer of the Original Code is NASA. -# Portions created by NASA are Copyright (C) 2006 San Jose State -# University Foundation. All Rights Reserved. -# -# The Original Code is the Bugzilla Bug Tracking System. -# -# Contributor(s): Max Kanat-Alexander -# Greg Hendricks -# Vitaliy Filippov +# Class representing single value of a field +# Nearly 100% refactored +# Author(s): Vitaliy Filippov , Max Kanat-Alexander , Greg Hendricks +# License: Dual-license GPL 3.0+ or MPL 1.1+ use strict; -############################################## -# Class representing single value of a field # -############################################## - package Bugzilla::Field::Choice; use base qw(Bugzilla::Object); @@ -139,9 +118,11 @@ EOC # We just make new() enforce this, which should give developers # the understanding that you can't use Bugzilla::Field::Choice # without calling type(). -sub new { +sub new +{ my $class = shift; - if ($class eq 'Bugzilla::Field::Choice') { + if ($class eq 'Bugzilla::Field::Choice') + { ThrowCodeError('field_choice_must_use_type'); } $class->SUPER::new(@_); @@ -164,7 +145,8 @@ sub create return $self; } -sub update { +sub update +{ my $self = shift; my $dbh = Bugzilla->dbh; my $fname = $self->field->name; @@ -172,7 +154,8 @@ sub update { $dbh->bz_start_transaction(); my ($changes, $old_self) = $self->SUPER::update(@_); - if (exists $changes->{$self->NAME_FIELD}) { + if (exists $changes->{$self->NAME_FIELD}) + { my ($old, $new) = @{ $changes->{$self->NAME_FIELD} }; if ($self->field->type != FIELD_TYPE_MULTI_SELECT) { @@ -185,8 +168,8 @@ sub update { $dbh->do("UPDATE bugs SET $fname = ?, lastdiffed = NOW() WHERE $fname = ?", undef, $new, $old); } - - if ($old_self->is_default) { + if ($old_self->is_default) + { my $param = $self->DEFAULT_MAP->{$self->field->name}; SetParam($param, $self->name); write_params(); @@ -198,21 +181,30 @@ sub update { return wantarray ? ($changes, $old_self) : $changes; } -sub remove_from_db { +sub remove_from_db +{ my $self = shift; - if ($self->is_default) { - ThrowUserError('fieldvalue_is_default', - { field => $self->field, value => $self, - param_name => $self->DEFAULT_MAP->{$self->field->name}, - }); + if ($self->is_default) + { + ThrowUserError('fieldvalue_is_default', { + field => $self->field, + value => $self, + param_name => $self->DEFAULT_MAP->{$self->field->name}, + }); } - if ($self->is_static) { - ThrowUserError('fieldvalue_not_deletable', - { field => $self->field, value => $self }); + if ($self->is_static) + { + ThrowUserError('fieldvalue_not_deletable', { + field => $self->field, + value => $self, + }); } - if ($self->bug_count) { - ThrowUserError('fieldvalue_still_has_bugs', - { field => $self->field, value => $self }); + if ($self->bug_count) + { + ThrowUserError('fieldvalue_still_has_bugs', { + field => $self->field, + value => $self, + }); } $self->_check_if_controller(); $self->set_visibility_values(undef); @@ -353,20 +345,20 @@ sub _check_if_controller sub is_active { return $_[0]->{'isactive'}; } sub sortkey { return $_[0]->{'sortkey'}; } -sub bug_count { +sub bug_count +{ my $self = shift; return $self->{bug_count} if defined $self->{bug_count}; my $dbh = Bugzilla->dbh; my $fname = $self->field->name; my $count; - if ($self->field->type == FIELD_TYPE_MULTI_SELECT) { - $count = $dbh->selectrow_array("SELECT COUNT(*) FROM bug_$fname - WHERE value_id = ?", undef, $self->id); + if ($self->field->type == FIELD_TYPE_MULTI_SELECT) + { + $count = $dbh->selectrow_array("SELECT COUNT(*) FROM bug_$fname WHERE value_id = ?", undef, $self->id); } - else { - $count = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs - WHERE $fname = ?", - undef, $self->name); + else + { + $count = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs WHERE $fname = ?", undef, $self->id); } $self->{bug_count} = $count; return $count; @@ -378,7 +370,8 @@ sub field return Bugzilla->get_field($invocant->FIELD_NAME); } -sub is_default { +sub is_default +{ my $self = shift; my $name = $self->DEFAULT_MAP->{$self->field->name}; # If it doesn't exist in DEFAULT_MAP, then there is no parameter @@ -389,14 +382,6 @@ sub is_default { sub is_static { - my $self = shift; - # If we need to special-case Resolution for *anything* else, it should - # get its own subclass. - if ($self->field->name eq 'resolution') - { - return grep($_ eq $self->name, ('', 'FIXED', 'MOVED', 'DUPLICATE')) - ? 1 : 0; - } return 0; } @@ -529,14 +514,15 @@ sub set_visibility_values my ($value_ids) = @_; update_visibility_values($self->field, $self->id, $value_ids); delete $self->{visibility_values}; - return 1; + return $value_ids; } ############## # Validators # ############## -sub _check_value { +sub _check_value +{ my ($invocant, $value) = @_; my $field = $invocant->field; @@ -544,11 +530,9 @@ sub _check_value { $value = trim($value); # Make sure people don't rename static values - if (blessed($invocant) && $value ne $invocant->name - && $invocant->is_static) + if (blessed($invocant) && $value ne $invocant->name && $invocant->is_static) { - ThrowUserError('fieldvalue_not_editable', - { field => $field, old_value => $invocant }); + ThrowUserError('fieldvalue_not_editable', { field => $field, old_value => $invocant }); } ThrowUserError('fieldvalue_undefined') if !defined $value || $value eq ""; @@ -556,24 +540,25 @@ sub _check_value { if length($value) > MAX_FIELD_VALUE_SIZE; my $exists = $invocant->type($field)->new({ name => $value }); - if ($exists && (!blessed($invocant) || $invocant->id != $exists->id)) { - ThrowUserError('fieldvalue_already_exists', - { field => $field, value => $exists }); + if ($exists && (!blessed($invocant) || $invocant->id != $exists->id)) + { + ThrowUserError('fieldvalue_already_exists', { field => $field, value => $exists }); } return $value; } -sub _check_sortkey { +sub _check_sortkey +{ my ($invocant, $value) = @_; $value = trim($value); return 0 if !$value; # Store for the error message in case detaint_natural clears it. my $orig_value = $value; - detaint_natural($value) - || ThrowUserError('fieldvalue_sortkey_invalid', - { sortkey => $orig_value, - field => $invocant->field }); + detaint_natural($value) || ThrowUserError('fieldvalue_sortkey_invalid', { + sortkey => $orig_value, + field => $invocant->field, + }); return $value; } diff --git a/editvalues.cgi b/editvalues.cgi index 573ac5e93..264edb08e 100755 --- a/editvalues.cgi +++ b/editvalues.cgi @@ -215,24 +215,27 @@ if ($action eq 'edit') { # # action='update' -> update the field value # -if ($action eq 'update') { +if ($action eq 'update') +{ check_token_data($token, 'edit_field_value'); - $vars->{'value_old'} = $value->name; - my $visibility_values; - if (!($value->is_static || $value->is_default)) { - $value->set_is_active($cgi->param('is_active')); - $value->set_name($cgi->param('value_new')); - $visibility_values = [ $cgi->param('visibility_value_id') ]; - } - if ($value->can('set_timetracking')) { + $vars->{value_old} = $value->name; + if ($value->can('set_timetracking')) + { $value->set_timetracking($cgi->param('timetracking') ? 1 : 0); } $value->set_sortkey($cgi->param('sortkey')); - $vars->{'changes'} = $value->update(); - my $ch = $value->set_visibility_values($visibility_values); - $vars->{'changes'}->{'visibility_values'} = $ch if $visibility_values && $ch; + if (!($value->is_static || $value->is_default)) + { + $value->set_is_active($cgi->param('is_active')); + $value->set_name($cgi->param('value_new')); + if ($value->field->value_field) + { + $vars->{changes}->{visibility_values} = $value->set_visibility_values([ $cgi->param('visibility_value_id') ]); + } + } delete_token($token); - $vars->{'message'} = 'field_value_updated'; + $vars->{changes} = $value->update; + $vars->{message} = 'field_value_updated'; display_field_values($vars); } diff --git a/enter_bug.cgi b/enter_bug.cgi index 74a93758b..4c90c9fe1 100755 --- a/enter_bug.cgi +++ b/enter_bug.cgi @@ -401,11 +401,6 @@ $vars->{'product'} = $product; $vars->{product_flag_types} = $types; } -$vars->{'priority'} = Bugzilla->get_field('priority')->legal_value_names; -$vars->{'bug_severity'} = Bugzilla->get_field('bug_severity')->legal_value_names; -$vars->{'rep_platform'} = Bugzilla->get_field('rep_platform')->legal_value_names if Bugzilla->params->{useplatform}; -$vars->{'op_sys'} = Bugzilla->get_field('op_sys')->legal_value_names if Bugzilla->params->{useopsys}; - $vars->{'assigned_to'} = formvalue('assigned_to'); $vars->{'assigned_to_disabled'} = !$has_editbugs; $vars->{'cc_disabled'} = 0; @@ -615,7 +610,6 @@ unless ($has_editbugs || $has_canconfirm) { } $vars->{bug_status} = \@status; -$vars->{resolution} = [ grep ($_, @{Bugzilla->get_field('resolution')->legal_value_names}) ]; # Get the default from a template value if it is legitimate. # Otherwise, and only if the user has privs, set the default diff --git a/extensions/custis/lib/CustisDBHooks.pm b/extensions/custis/lib/CustisDBHooks.pm index 5e81de472..637dd6619 100644 --- a/extensions/custis/lib/CustisDBHooks.pm +++ b/extensions/custis/lib/CustisDBHooks.pm @@ -424,6 +424,9 @@ sub install_update_fielddefs # Bug 90854 - Тип поля "ссылка во внешнюю систему по ID" $dbh->bz_add_column('fielddefs', url => {TYPE => 'VARCHAR(255)'}); + # Nullable field property + $dbh->bz_add_column('fielddefs', nullable => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'}); + # Bug 70605 - Кэширование зависимостей полей для поиска и формы бага на клиентской стороне if (!$dbh->bz_column_info('fielddefs', 'delta_ts')) { diff --git a/template/en/default/bug/create/create.html.tmpl b/template/en/default/bug/create/create.html.tmpl index 4a05ee6eb..fe8b9c81b 100644 --- a/template/en/default/bug/create/create.html.tmpl +++ b/template/en/default/bug/create/create.html.tmpl @@ -397,8 +397,8 @@ function checkWorktime(inp) [% IF Param('useopsys') %] [% INCLUDE bug/field.html.tmpl - bug = default, field = select_fields.op_sys, editable = 1, - value = default.op_sys %] + bug = default, field = select_fields.op_sys, editable = 1, + value = default.op_sys %] [% END %] @@ -406,8 +406,9 @@ function checkWorktime(inp) [% IF Param('usetargetmilestone') && Param('letsubmitterchoosemilestone') %] - [% sel = { description => 'Target Milestone', name => 'target_milestone' } %] - [% INCLUDE select %] + [% INCLUDE bug/field.html.tmpl + bug = default, field = select_fields.target_milestone, editable = 1, + value = default.target_milestone %] [% ELSE %]   [% END %] @@ -445,8 +446,7 @@ function checkWorktime(inp) [% IF bug_status.size <= 1 %] - + Initial State: [% default.bug_status FILTER html %] [% ELSE %] @@ -461,15 +461,8 @@ function checkWorktime(inp) - Resolution: - - - + [% INCLUDE bug/field.html.tmpl + bug = default, field = select_fields.resolution, editable = 1 %]
diff --git a/template/en/default/bug/field.html.tmpl b/template/en/default/bug/field.html.tmpl index 946d08e50..c3ee8a9e7 100644 --- a/template/en/default/bug/field.html.tmpl +++ b/template/en/default/bug/field.html.tmpl @@ -29,13 +29,13 @@ # allow_dont_change: display the --do_not_change-- option for select fields. # value_span: A colspan for the table cell containing # the field value. - # no_tds: boolean; if true, don't display the label or the + # no_tds: boolean; if true, don't display the label or the # wrapping for the field. # desc_url: string; Normally the label of a non-custom field links to # fields.html. If you want it to link elsewhere, specify the # relative URL you want to link to, here. Remember to call # url_quote on any query string arguments. - # bug: (optional) The current Bugzilla::Bug being displayed, or a hash + # bug: (optional) The current Bugzilla::Bug being displayed, or a hash # with default field values being displayed on a page. # tabindex: (optional) HTML tabindex. #%] @@ -57,14 +57,10 @@ [%- '' IF (!field.custom || desc_url) %] [% '' IF editable %] -[% END %] - -[% IF NOT no_tds %] - [% END %] -[% Hook.process('start_field_column') %] [% IF editable %] [% SWITCH field.type %] [% CASE constants.FIELD_TYPE_FREETEXT %] @@ -131,11 +127,11 @@ '[% field.name FILTER js %]', "[% bug.${field.name} FILTER js %]"); - [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT + [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT constants.FIELD_TYPE_MULTI_SELECT ] %] -