2010-10-27 19:53:21 +04:00
|
|
|
#!/usr/bin/perl
|
|
|
|
# Bugzilla::WebService::Field - API for managing custom fields and values
|
2012-01-12 19:04:04 +04:00
|
|
|
# License: Dual-license GPL 3.0+ or MPL 1.1+
|
|
|
|
# Contributor(s): Vitaliy Filippov <vitalif@mail.ru>
|
2010-10-27 19:53:21 +04:00
|
|
|
|
|
|
|
package Bugzilla::WebService::Field;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use base qw(Bugzilla::WebService);
|
|
|
|
use Bugzilla::Field::Choice;
|
|
|
|
use Bugzilla::User;
|
2014-09-02 18:48:19 +04:00
|
|
|
use Bugzilla::Util;
|
2010-10-27 19:53:21 +04:00
|
|
|
use Bugzilla::WebService::Util qw(validate);
|
2012-05-03 19:19:30 +04:00
|
|
|
use Bugzilla::Error;
|
2010-10-27 19:53:21 +04:00
|
|
|
|
2012-05-03 19:19:30 +04:00
|
|
|
use constant READ_ONLY => qw(
|
|
|
|
get_values
|
|
|
|
);
|
|
|
|
|
|
|
|
# Get field and choice type by $params->{field}
|
|
|
|
# Throws 'field_not_found' for incorrect fields
|
|
|
|
sub _get_field
|
2010-10-27 19:53:21 +04:00
|
|
|
{
|
2012-05-03 19:19:30 +04:00
|
|
|
my ($params) = @_;
|
2010-10-27 19:53:21 +04:00
|
|
|
my $field = Bugzilla->get_field($params->{field});
|
2012-05-03 19:19:30 +04:00
|
|
|
ThrowUserError('account_disabled') if !$field;
|
2014-08-07 20:30:39 +04:00
|
|
|
my $type = $field->value_type;
|
2012-05-03 19:19:30 +04:00
|
|
|
return ($field, $type);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Get value by id=$params->{id} or name=$params->{value}
|
|
|
|
# Throws 'value_not_found' for incorrect values
|
|
|
|
sub _get_value
|
|
|
|
{
|
|
|
|
my ($type, $params, $value_param) = @_;
|
|
|
|
my $value;
|
2012-06-15 14:42:31 +04:00
|
|
|
$value_param ||= 'value';
|
2012-05-03 19:19:30 +04:00
|
|
|
if ($params->{id})
|
2010-10-27 19:53:21 +04:00
|
|
|
{
|
2012-05-03 19:19:30 +04:00
|
|
|
$value = $type->new({ id => $params->{id} });
|
2010-10-27 19:53:21 +04:00
|
|
|
}
|
2012-06-15 14:42:31 +04:00
|
|
|
elsif ($params->{$value_param})
|
2012-05-03 19:19:30 +04:00
|
|
|
{
|
2012-06-15 14:42:31 +04:00
|
|
|
$value = $type->new({ name => $params->{$value_param} });
|
2012-05-03 19:19:30 +04:00
|
|
|
}
|
|
|
|
ThrowUserError('value_not_found') if !$value;
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2014-09-02 18:48:19 +04:00
|
|
|
# Get all or some values for a field. Arguments:
|
|
|
|
# field => <field name>
|
|
|
|
# optional:
|
|
|
|
# name => <name(s) to search for exact match>
|
|
|
|
# match => <string(s) to search in the beginning of value name>
|
|
|
|
# visibility_value_ids => <ID(s) of controlling value in which returned ones should be visible>
|
|
|
|
# limit => maximum number of matches
|
2012-05-03 19:19:30 +04:00
|
|
|
sub get_values
|
|
|
|
{
|
|
|
|
my ($self, $params) = @_;
|
|
|
|
my ($field) = _get_field($params);
|
2010-10-27 19:53:21 +04:00
|
|
|
if (!$field->is_select)
|
|
|
|
{
|
|
|
|
return {status => 'field_not_select'};
|
|
|
|
}
|
2014-09-02 18:48:19 +04:00
|
|
|
my $join = '';
|
|
|
|
my $where = [];
|
|
|
|
my $bind = [];
|
|
|
|
my $type = $field->value_type;
|
|
|
|
my @vv = $field->value_field_id ? list $params->{visibility_value_ids} : ();
|
|
|
|
my @match = list $params->{match};
|
|
|
|
my @name = list $params->{name};
|
|
|
|
if (@match || @name)
|
|
|
|
{
|
|
|
|
my @m;
|
|
|
|
push @m, ('v.'.$type->NAME_FIELD.' LIKE ?') x @match;
|
|
|
|
push @m, 'v.'.$type->NAME_FIELD.' IN ('.join(', ', ('?') x @name).')' if @name;
|
|
|
|
push @$where, '('.join(' OR ', @m).')';
|
|
|
|
push @$bind, (map { $_.'%' } @match), @name;
|
|
|
|
}
|
|
|
|
if (@vv)
|
|
|
|
{
|
|
|
|
$join = " INNER JOIN fieldvaluecontrol fc ON fc.field_id=?".
|
|
|
|
" AND fc.value_id=v.id AND fc.visibility_value_id IN (".join(", ", ("?") x @vv).")";
|
|
|
|
unshift @$bind, $field->id, @vv;
|
|
|
|
}
|
|
|
|
$where = @$where ? join(' AND ', @$where) : '1=1';
|
|
|
|
my $order = $type->LIST_ORDER;
|
|
|
|
$order =~ s/(^|,)\s*(\S)/$1v.$2/gso;
|
|
|
|
trick_taint($_) for @$bind;
|
|
|
|
my $values = Bugzilla->dbh->selectall_arrayref(
|
|
|
|
"SELECT v.* FROM ".$type->DB_TABLE." v $join WHERE $where GROUP BY v.id".
|
|
|
|
" ORDER BY $order ".($params->{limit} ? Bugzilla->dbh->sql_limit(int($params->{limit})) : ''),
|
|
|
|
{Slice=>{}}, @$bind
|
|
|
|
);
|
|
|
|
bless $_, $type for @$values;
|
2010-10-27 19:53:21 +04:00
|
|
|
if ($field->value_field_id)
|
|
|
|
{
|
|
|
|
$values = [ map { {
|
|
|
|
id => $_->id,
|
|
|
|
name => $_->name,
|
|
|
|
visibility_value_ids => [ map { $_->id } @{$_->visibility_values} ],
|
2014-09-02 18:48:19 +04:00
|
|
|
} } @$values ];
|
2010-10-27 19:53:21 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-09-02 18:48:19 +04:00
|
|
|
$values = [ map { { id => $_->id, name => $_->name } } @$values ];
|
2010-10-27 19:53:21 +04:00
|
|
|
}
|
|
|
|
return {
|
|
|
|
status => 'ok',
|
|
|
|
values => $values,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-05-03 19:19:30 +04:00
|
|
|
# Add value for a field. Arguments:
|
|
|
|
# field => <field_name>
|
|
|
|
# value => <value_name>
|
|
|
|
# sortkey => <number_for_sorting>
|
|
|
|
# ...other columns from $type->DB_COLUMNS...
|
2010-10-27 19:53:21 +04:00
|
|
|
sub add_value
|
|
|
|
{
|
|
|
|
my ($self, $params) = @_;
|
2012-05-03 19:19:30 +04:00
|
|
|
my ($field, $type) = _get_field($params);
|
2012-05-03 16:31:28 +04:00
|
|
|
my $value = $type->new({ name => $params->{value} });
|
|
|
|
if ($value)
|
2010-10-27 19:53:21 +04:00
|
|
|
{
|
|
|
|
return {status => 'value_already_exists'};
|
|
|
|
}
|
2010-11-26 16:51:53 +03:00
|
|
|
my $row = {};
|
2012-05-03 19:19:30 +04:00
|
|
|
delete $params->{$type->ID_FIELD};
|
2010-11-26 16:51:53 +03:00
|
|
|
for ($type->DB_COLUMNS)
|
|
|
|
{
|
|
|
|
if ($_ eq $type->NAME_FIELD)
|
|
|
|
{
|
|
|
|
$row->{$_} = $params->{value};
|
|
|
|
}
|
|
|
|
elsif (exists $params->{$_})
|
|
|
|
{
|
|
|
|
$row->{$_} = $params->{$_};
|
|
|
|
}
|
|
|
|
}
|
2012-05-03 16:31:28 +04:00
|
|
|
$value = $type->create($row);
|
2010-10-27 19:53:21 +04:00
|
|
|
return {status => 'ok', id => $value->id};
|
|
|
|
}
|
|
|
|
|
2012-05-03 19:19:30 +04:00
|
|
|
# Update a value. Arguments:
|
|
|
|
# field => <field_name>
|
|
|
|
# old_value => <old_value_name> or id => <value_id>
|
|
|
|
# value => <new_value>
|
|
|
|
# sortkey => <new_sortkey>
|
|
|
|
# isactive => <new_isactive>
|
|
|
|
# ...other columns from $type->DB_COLUMNS...
|
2010-10-27 19:53:21 +04:00
|
|
|
sub update_value
|
|
|
|
{
|
|
|
|
my ($self, $params) = @_;
|
2012-06-15 14:42:31 +04:00
|
|
|
# Backwards compatibility (old version had value/new_value instead of old_value/value)
|
|
|
|
$params->{old_value} ||= $params->{value};
|
|
|
|
$params->{value} = delete $params->{new_value} if defined $params->{new_value};
|
2012-05-03 19:19:30 +04:00
|
|
|
my ($field, $type) = _get_field($params);
|
|
|
|
my $value = _get_value($type, $params, 'old_value') || return {status => 'value_not_found'};
|
|
|
|
if (defined $params->{value} && $params->{value} ne $value->name)
|
2012-05-03 16:31:28 +04:00
|
|
|
{
|
|
|
|
my $newvalue = $type->new({ name => $params->{value} });
|
2010-10-27 20:16:22 +04:00
|
|
|
if ($newvalue)
|
|
|
|
{
|
2012-05-24 15:54:20 +04:00
|
|
|
return {status => 'value_already_exists', other_id => $newvalue->id, my_id => $value->id};
|
2010-10-27 20:16:22 +04:00
|
|
|
}
|
2012-05-03 16:31:28 +04:00
|
|
|
$value->set_name($params->{value});
|
2010-10-27 20:16:53 +04:00
|
|
|
}
|
2012-05-03 19:19:30 +04:00
|
|
|
# Other columns
|
|
|
|
delete $params->{$type->ID_FIELD};
|
2010-11-26 16:51:53 +03:00
|
|
|
for ($type->DB_COLUMNS)
|
2010-10-27 20:16:53 +04:00
|
|
|
{
|
2010-11-26 16:51:53 +03:00
|
|
|
if ($_ ne $type->NAME_FIELD &&
|
|
|
|
exists $params->{$_})
|
|
|
|
{
|
|
|
|
my $m = "set_$_";
|
|
|
|
$value->$m($params->{$_});
|
|
|
|
}
|
2010-10-27 20:16:22 +04:00
|
|
|
}
|
2010-10-27 19:53:21 +04:00
|
|
|
$value->update;
|
|
|
|
return {status => 'ok', id => $value->id};
|
|
|
|
}
|
|
|
|
|
2012-05-03 19:19:30 +04:00
|
|
|
# Delete a value (by name or by id). Arguments:
|
|
|
|
# field => <field_name>
|
|
|
|
# value => <value_name> or id => <value_id>
|
2010-10-27 19:53:21 +04:00
|
|
|
sub delete_value
|
|
|
|
{
|
|
|
|
my ($self, $params) = @_;
|
2012-05-03 19:19:30 +04:00
|
|
|
my ($field, $type) = _get_field($params);
|
|
|
|
my $value = _get_value($type, $params) || return {status => 'value_not_found'};
|
2010-10-27 19:53:21 +04:00
|
|
|
$value->remove_from_db;
|
|
|
|
return {status => 'ok'};
|
|
|
|
}
|
|
|
|
|
2012-05-03 19:19:30 +04:00
|
|
|
# Set visibility values for a value. Arguments:
|
|
|
|
# field => <field_name>
|
|
|
|
# value => <value_name> or id => <value_id>
|
|
|
|
# ids => [ visibility_ID, visibility_ID, ... ]
|
2010-10-27 19:53:21 +04:00
|
|
|
sub set_visibility_values
|
|
|
|
{
|
|
|
|
my ($self, $params) = @_;
|
2012-05-03 19:19:30 +04:00
|
|
|
my ($field, $type) = _get_field($params);
|
2010-10-27 20:23:44 +04:00
|
|
|
if (!$field->value_field)
|
|
|
|
{
|
|
|
|
return {status => 'fieldvalues_not_controlled'};
|
|
|
|
}
|
2012-05-03 19:19:30 +04:00
|
|
|
my $value = _get_value($type, $params) || return {status => 'value_not_found'};
|
2010-10-27 20:23:44 +04:00
|
|
|
my $ids = $params->{ids} || [];
|
2010-11-22 16:51:55 +03:00
|
|
|
$ids = [ $ids ] unless ref $ids;
|
2014-08-07 20:30:39 +04:00
|
|
|
$ids = [ map { $_->id } @{ $field->value_field->value_type->new_from_list($ids) } ];
|
2010-11-22 16:51:55 +03:00
|
|
|
$value->set_visibility_values($ids);
|
2010-10-27 20:23:44 +04:00
|
|
|
return {status => 'ok', ids => $ids};
|
2010-10-27 19:53:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
__END__
|