Bug 53617
Restricting custom field values to more than one value of controlling field git-svn-id: svn://svn.office.custis.ru/3rdparty/bugzilla.org/trunk@389 6955db30-a419-402b-8a0d-67ecbb4d7f56master
parent
b553c8b25b
commit
ed774aaf5f
|
@ -218,14 +218,12 @@ use constant FIELD_TABLE_SCHEMA => {
|
|||
sortkey => {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0},
|
||||
isactive => {TYPE => 'BOOLEAN', NOTNULL => 1,
|
||||
DEFAULT => 'TRUE'},
|
||||
visibility_value_id => {TYPE => 'INT2'},
|
||||
],
|
||||
# Note that bz_add_field_table should prepend the table name
|
||||
# to these index names.
|
||||
INDEXES => [
|
||||
value_idx => {FIELDS => ['value'], TYPE => 'UNIQUE'},
|
||||
sortkey_idx => ['sortkey', 'value'],
|
||||
visibility_value_id_idx => ['visibility_value_id'],
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -17,9 +17,14 @@
|
|||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
# Vitaliy Filippov <vitalif@mail.ru>
|
||||
|
||||
use strict;
|
||||
|
||||
##############################################
|
||||
# Class representing single value of a field #
|
||||
##############################################
|
||||
|
||||
package Bugzilla::Field::Choice;
|
||||
|
||||
use base qw(Bugzilla::Object);
|
||||
|
@ -28,7 +33,7 @@ use Bugzilla::Config qw(SetParam write_params);
|
|||
use Bugzilla::Constants;
|
||||
use Bugzilla::Error;
|
||||
use Bugzilla::Field;
|
||||
use Bugzilla::Util qw(trim detaint_natural);
|
||||
use Bugzilla::Util qw(trim detaint_natural trick_taint diff_arrays);
|
||||
|
||||
use Scalar::Util qw(blessed);
|
||||
|
||||
|
@ -40,13 +45,11 @@ use constant DB_COLUMNS => qw(
|
|||
id
|
||||
value
|
||||
sortkey
|
||||
visibility_value_id
|
||||
);
|
||||
|
||||
use constant UPDATE_COLUMNS => qw(
|
||||
value
|
||||
sortkey
|
||||
visibility_value_id
|
||||
);
|
||||
|
||||
use constant NAME_FIELD => 'value';
|
||||
|
@ -57,7 +60,6 @@ use constant REQUIRED_CREATE_FIELDS => qw(value);
|
|||
use constant VALIDATORS => {
|
||||
value => \&_check_value,
|
||||
sortkey => \&_check_sortkey,
|
||||
visibility_value_id => \&_check_visibility_value_id,
|
||||
};
|
||||
|
||||
use constant CLASS_MAP => {
|
||||
|
@ -191,6 +193,7 @@ sub remove_from_db {
|
|||
{ field => $self->field, value => $self });
|
||||
}
|
||||
$self->_check_if_controller();
|
||||
$self->set_visibility_values([]);
|
||||
$self->SUPER::remove_from_db();
|
||||
}
|
||||
|
||||
|
@ -269,45 +272,85 @@ sub is_static {
|
|||
sub controls_visibility_of_fields {
|
||||
my $self = shift;
|
||||
$self->{controls_visibility_of_fields} ||= Bugzilla::Field->match(
|
||||
{ visibility_field_id => $self->field->id,
|
||||
{ visibility_field_id => $self->field->id,
|
||||
visibility_value_id => $self->id });
|
||||
return $self->{controls_visibility_of_fields};
|
||||
}
|
||||
|
||||
sub visibility_value {
|
||||
my $self = shift;
|
||||
if ($self->{visibility_value_id}) {
|
||||
$self->{visibility_value} ||=
|
||||
Bugzilla::Field::Choice->type($self->field->value_field)->new(
|
||||
$self->{visibility_value_id});
|
||||
}
|
||||
return $self->{visibility_value};
|
||||
}
|
||||
|
||||
sub controlled_values {
|
||||
sub controlled_values
|
||||
{
|
||||
my $self = shift;
|
||||
return $self->{controlled_values} if defined $self->{controlled_values};
|
||||
my $fields = $self->field->controls_values_of;
|
||||
my %controlled_values;
|
||||
# TODO move this into Bugzilla::Field::Choice::match() with MATCH_JOIN
|
||||
# but no MATCH_JOIN by now is available
|
||||
foreach my $field (@$fields) {
|
||||
$controlled_values{$field->name} =
|
||||
Bugzilla::Field::Choice->type($field)
|
||||
->match({ visibility_value_id => $self->id });
|
||||
my $type = Bugzilla::Field::Choice->type($field);
|
||||
my $sql =
|
||||
"SELECT f.".join(", f.", @{$type->DB_COLUMNS}).
|
||||
" FROM fieldvaluecontrol c, ".$type->DB_TABLE." f".
|
||||
" WHERE c.field_id=? AND c.visibility_value_id=? AND c.value_id=f.id";
|
||||
# Обходим самозарождение греха при конкатенации DB_COLUMNS и DB_TABLE
|
||||
trick_taint($sql);
|
||||
my $f = Bugzilla->dbh->selectall_arrayref($sql, {Slice=>{}}, $field->id, $self->id) || [];
|
||||
$f = [ map { bless $_, $type } @$f ];
|
||||
$controlled_values{$field->name} = $f;
|
||||
}
|
||||
$self->{controlled_values} = \%controlled_values;
|
||||
return $self->{controlled_values};
|
||||
}
|
||||
|
||||
sub visibility_values
|
||||
{
|
||||
my $self = shift;
|
||||
my $f;
|
||||
unless ($f = $self->{visibility_values})
|
||||
{
|
||||
# TODO move this into Bugzilla::Field::Choice::match() with MATCH_JOIN
|
||||
# but no MATCH_JOIN by now is available
|
||||
my $type = Bugzilla::Field::Choice->type($self->field->value_field);
|
||||
my $sql =
|
||||
"SELECT f.".join(", f.", $type->DB_COLUMNS).
|
||||
" FROM fieldvaluecontrol c, ".$type->DB_TABLE." f".
|
||||
" WHERE c.field_id=? AND c.visibility_value_id=f.id AND c.value_id=?";
|
||||
# Обходим самозарождение греха при конкатенации DB_COLUMNS и DB_TABLE
|
||||
trick_taint($sql);
|
||||
$f = Bugzilla->dbh->selectall_arrayref($sql, {Slice=>{}}, $self->field->id, $self->id) || [];
|
||||
$f = [ map { bless $_, $type } @$f ];
|
||||
$self->{visibility_values} = $f;
|
||||
}
|
||||
return $f;
|
||||
}
|
||||
|
||||
############
|
||||
# Mutators #
|
||||
############
|
||||
|
||||
sub set_name { $_[0]->set('value', $_[1]); }
|
||||
sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
|
||||
sub set_visibility_value {
|
||||
my ($self, $value) = @_;
|
||||
$self->set('visibility_value_id', $value);
|
||||
delete $self->{visibility_value};
|
||||
|
||||
sub set_visibility_values
|
||||
{
|
||||
my $self = shift;
|
||||
my ($value_ids) = @_;
|
||||
return undef if !ref $value_ids || $value_ids !~ 'ARRAY';
|
||||
my $type = Bugzilla::Field::Choice->type($self->field->value_field);
|
||||
@$value_ids = map { $_ ? $type->check({ id => $_ }) : () } @$value_ids;
|
||||
my ($a, $r) = diff_arrays([map { $_->id } @$value_ids], [map { $_->id } @{$self->visibility_values}]);
|
||||
return undef unless @$a || @$r;
|
||||
Bugzilla->dbh->do(
|
||||
"DELETE FROM fieldvaluecontrol WHERE field_id=? AND value_id=?",
|
||||
undef, $self->field->id, $self->id);
|
||||
if (@$value_ids)
|
||||
{
|
||||
Bugzilla->dbh->do(
|
||||
"INSERT INTO fieldvaluecontrol (field_id, value_id, visibility_value_id) VALUES ".
|
||||
join(",", ("(?,?,?)") x @$value_ids),
|
||||
undef, map { ($self->field->id, $self->id, $_->id) } @$value_ids);
|
||||
}
|
||||
delete $self->{visibility_values};
|
||||
return @$value_ids;
|
||||
}
|
||||
|
||||
##############
|
||||
|
@ -355,16 +398,6 @@ sub _check_sortkey {
|
|||
return $value;
|
||||
}
|
||||
|
||||
sub _check_visibility_value_id {
|
||||
my ($invocant, $value_id) = @_;
|
||||
$value_id = trim($value_id);
|
||||
my $field = $invocant->field->value_field;
|
||||
return undef if !$field || !$value_id;
|
||||
my $value_obj = Bugzilla::Field::Choice->type($field)
|
||||
->check({ id => $value_id });
|
||||
return $value_obj->id;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
|
|
@ -553,8 +553,6 @@ sub update_table_definitions {
|
|||
# 2008-09-07 LpSolit@gmail.com - Bug 452893
|
||||
_fix_illegal_flag_modification_dates();
|
||||
|
||||
_add_visiblity_value_to_value_tables();
|
||||
|
||||
# 2009-03-02 arbingersys@gmail.com - Bug 423613
|
||||
$dbh->bz_add_index('profiles', 'profiles_extern_id_idx',
|
||||
{TYPE => 'UNIQUE', FIELDS => [qw(extern_id)]});
|
||||
|
@ -3218,20 +3216,6 @@ sub _fix_illegal_flag_modification_dates {
|
|||
print "$rows flags had an illegal modification date. Fixed!\n" if ($rows =~ /^\d+$/);
|
||||
}
|
||||
|
||||
sub _add_visiblity_value_to_value_tables {
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my @standard_fields =
|
||||
qw(bug_status resolution priority bug_severity op_sys rep_platform);
|
||||
my $custom_fields = $dbh->selectcol_arrayref(
|
||||
'SELECT name FROM fielddefs WHERE custom = 1 AND type IN(?,?)',
|
||||
undef, FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT);
|
||||
foreach my $field (@standard_fields, @$custom_fields) {
|
||||
$dbh->bz_add_column($field, 'visibility_value_id', {TYPE => 'INT2'});
|
||||
$dbh->bz_add_index($field, "${field}_visibility_value_id_idx",
|
||||
['visibility_value_id']);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
|
|
@ -119,11 +119,11 @@ if ($action eq 'new') {
|
|||
check_token_data($token, 'add_field_value');
|
||||
|
||||
my $created_value = Bugzilla::Field::Choice->type($field)->create({
|
||||
value => scalar $cgi->param('value'),
|
||||
value => scalar $cgi->param('value'),
|
||||
sortkey => scalar $cgi->param('sortkey'),
|
||||
is_open => scalar $cgi->param('is_open'),
|
||||
visibility_value_id => scalar $cgi->param('visibility_value_id'),
|
||||
});
|
||||
$created_value->set_visibility_values([ $cgi->param('visibility_value_id') ]);
|
||||
|
||||
delete_token($token);
|
||||
|
||||
|
@ -188,8 +188,9 @@ if ($action eq 'update') {
|
|||
$vars->{'value_old'} = $value->name;
|
||||
$value->set_name($cgi->param('value_new'));
|
||||
$value->set_sortkey($cgi->param('sortkey'));
|
||||
$value->set_visibility_value($cgi->param('visibility_value_id'));
|
||||
$vars->{'changes'} = $value->update();
|
||||
my $ch = $value->set_visibility_values([ $cgi->param('visibility_value_id') ]);
|
||||
$vars->{'changes'}->{'visibility_values'} = $ch if defined $ch;
|
||||
delete_token($token);
|
||||
$vars->{'message'} = 'field_value_updated';
|
||||
display_field_values($vars);
|
||||
|
|
|
@ -44,3 +44,17 @@ push @{$schema->{products}->{FIELDS}}, wiki_url => {TYPE => 'varchar(255)', NOTN
|
|||
|
||||
# Bug 53725 - Версия по умолчанию
|
||||
push @{$schema->{components}->{FIELDS}}, default_version => {TYPE => 'varchar(64)', NOTNULL => 1, DEFAULT => "''"};
|
||||
|
||||
# Bug 53617 - Ограничение Custom Fields двумя и более значениями контролирующего поля
|
||||
$schema->{fieldvaluecontrol} = {
|
||||
FIELDS => [
|
||||
field_id => {TYPE => 'INT3', NOTNULL => 1},
|
||||
value_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
visibility_value_id => {TYPE => 'INT2', NOTNULL => 1},
|
||||
],
|
||||
INDEXES => [
|
||||
fieldvaluecontrol_primary_idx =>
|
||||
{FIELDS => ['field_id', 'visibility_value_id', 'value_id'],
|
||||
TYPE => 'UNIQUE'},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -103,3 +103,24 @@ if (!$dbh->bz_column_info('components', 'default_version'))
|
|||
{
|
||||
$dbh->bz_add_column('components', default_version => {TYPE => 'varchar(64)', NOTNULL => 1, DEFAULT => "''"});
|
||||
}
|
||||
|
||||
# Bug 53617 - Ограничение Custom Fields двумя и более значениями контролирующего поля
|
||||
my @standard_fields =
|
||||
qw(bug_status resolution priority bug_severity op_sys rep_platform);
|
||||
my $custom_fields = $dbh->selectcol_arrayref(
|
||||
'SELECT name FROM fielddefs WHERE custom = 1 AND type IN (?,?)',
|
||||
undef, FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT);
|
||||
foreach my $field (@standard_fields, @$custom_fields)
|
||||
{
|
||||
next unless $dbh->bz_table_info($field);
|
||||
if ($dbh->bz_column_info($field, 'visibility_value_id'))
|
||||
{
|
||||
print "Migrating $field visibility_value_id into fieldvaluecontrol\n";
|
||||
$dbh->do(
|
||||
"REPLACE INTO fieldvaluecontrol (field_id, visibility_value_id, value_id)".
|
||||
" SELECT f.id, v.visibility_value_id, v.id FROM fielddefs f, $field v".
|
||||
" WHERE f.name=? AND v.visibility_value_id IS NOT NULL", undef, $field);
|
||||
# Пока не удаляем никаких колонок
|
||||
#$dbh->bz_drop_column($field, 'visibility_value_id');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -524,3 +524,5 @@ table.alcontent { width: 100%; }
|
|||
|
||||
#field_container_see_also #see_also { max-width: 500px; }
|
||||
table.flag_table select { max-width: 400px; }
|
||||
|
||||
#visibility_values_td select { margin-bottom: 2px; }
|
||||
|
|
|
@ -70,7 +70,13 @@
|
|||
</label>
|
||||
</th>
|
||||
<td>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<input type="button" onclick="add_visibility_value()" value="Add an option" />
|
||||
(Leave unset to have this value always appear.)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td><td id="visibility_values_td">
|
||||
<select name="visibility_value_id" id="visibility_value_id_0">
|
||||
<option></option>
|
||||
[% FOREACH field_value = field.value_field.legal_values %]
|
||||
[% NEXT IF field_value.name == '' %]
|
||||
|
@ -79,9 +85,31 @@
|
|||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<small>(Leave unset to have this value always appear.)</small>
|
||||
</td>
|
||||
</tr>
|
||||
<script language="JavaScript">
|
||||
<!--
|
||||
function add_visibility_value()
|
||||
{
|
||||
var td = document.getElementById('visibility_values_td');
|
||||
var sel = document.getElementById('visibility_value_id_0');
|
||||
var o;
|
||||
var n = document.createElement('span');
|
||||
n.innerHTML = ' or <br>';
|
||||
td.appendChild(n);
|
||||
n = document.createElement('select');
|
||||
n.name = "visibility_value_id";
|
||||
for (var i = 0; i < sel.options.length; i++)
|
||||
{
|
||||
o = document.createElement('option');
|
||||
o.value = sel.options[i].value;
|
||||
o.text = sel.options[i].text;
|
||||
n.options.add(o);
|
||||
}
|
||||
td.appendChild(n);
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
</table>
|
||||
<input type="submit" id="create" value="Add">
|
||||
|
|
|
@ -61,25 +61,58 @@
|
|||
[% IF field.value_field %]
|
||||
<tr>
|
||||
<th align="right">
|
||||
<label for="visibility_value_id">Only appears when
|
||||
[%+ field.value_field.description FILTER html %] is set to:
|
||||
</label>
|
||||
Only appears when [%+ field.value_field.description FILTER html %] is set to:
|
||||
</th>
|
||||
<td>
|
||||
<select name="visibility_value_id" id="visibility_value_id">
|
||||
<input type="button" onclick="add_visibility_value()" value="Add an option" />
|
||||
(Leave unset to have this value always appear.)
|
||||
</td>
|
||||
</tr>
|
||||
[% vis_values = value.visibility_values %]
|
||||
[% SET vis_values = [{ id => -1 }] IF !vis_values OR vis_values.size <= 0 %]
|
||||
[% SET vv_i = 0 %]
|
||||
<tr>
|
||||
<td></td><td id="visibility_values_td">
|
||||
[% FOR vv = vis_values %]
|
||||
[% " or <br>" IF vv_i %]
|
||||
<select name="visibility_value_id" id="visibility_value_id_[% vv_i %]">
|
||||
<option></option>
|
||||
[% FOREACH field_value = field.value_field.legal_values %]
|
||||
[% NEXT IF field_value.name == '' %]
|
||||
<option value="[% field_value.id FILTER none %]"
|
||||
[% ' selected="selected"'
|
||||
IF field_value.id == value.visibility_value.id %]>
|
||||
IF field_value.id == vv.id %]>
|
||||
[%- field_value.name FILTER html -%]
|
||||
</option>
|
||||
[% END %]
|
||||
</select>
|
||||
<small>(Leave unset to have this value always appear.)</small>
|
||||
[% SET vv_i = vv_i + 1 %]
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
<script language="JavaScript">
|
||||
<!--
|
||||
function add_visibility_value()
|
||||
{
|
||||
var td = document.getElementById('visibility_values_td');
|
||||
var sel = document.getElementById('visibility_value_id_0');
|
||||
var o;
|
||||
var n = document.createElement('span');
|
||||
n.innerHTML = ' or <br>';
|
||||
td.appendChild(n);
|
||||
n = document.createElement('select');
|
||||
n.name = "visibility_value_id";
|
||||
for (var i = 0; i < sel.options.length; i++)
|
||||
{
|
||||
o = document.createElement('option');
|
||||
o.value = sel.options[i].value;
|
||||
o.text = sel.options[i].text;
|
||||
n.options.add(o);
|
||||
}
|
||||
td.appendChild(n);
|
||||
}
|
||||
//-->
|
||||
</script>
|
||||
[% END %]
|
||||
</table>
|
||||
|
||||
|
|
|
@ -328,11 +328,17 @@
|
|||
<li>Sortkey updated to
|
||||
<em>[% changes.sortkey.1 FILTER html %]</em>.</li>
|
||||
[% END %]
|
||||
[% IF changes.visibility_value_id %]
|
||||
[% IF value.visibility_value.defined %]
|
||||
[% IF changes.visibility_values.defined %]
|
||||
[% IF value.visibility_values.size > 0 %]
|
||||
<li>It only appears when
|
||||
[%+ value.field.value_field.description FILTER html %] is set to
|
||||
'[%+ value.visibility_value.name FILTER html %]'.</li>
|
||||
[% SET vv_i = 0 %]
|
||||
[% FOR vv = value.visibility_values %]
|
||||
[% IF vv_i %] or [% END %]
|
||||
'[%+ vv.name FILTER html %]'
|
||||
[% SET vv_i = vv_i+1 %]
|
||||
[% END %]
|
||||
</li>
|
||||
[% ELSE %]
|
||||
<li>It now always appears, no matter what
|
||||
[%+ value.field.value_field.description FILTER html %] is set to.
|
||||
|
|
Loading…
Reference in New Issue