Move data validation and update/insert code into Bugzilla::FlagType
parent
fed3567b82
commit
112eb10a5f
|
@ -30,6 +30,9 @@ use Bugzilla::Group;
|
|||
|
||||
use base qw(Bugzilla::Object);
|
||||
|
||||
use constant DB_TABLE => 'flagtypes';
|
||||
use constant LIST_ORDER => 'sortkey, name';
|
||||
|
||||
use constant DB_COLUMNS => qw(
|
||||
id
|
||||
name
|
||||
|
@ -43,9 +46,22 @@ use constant DB_COLUMNS => qw(
|
|||
grant_group_id
|
||||
request_group_id
|
||||
);
|
||||
use constant UPDATE_COLUMNS => grep { $_ ne 'id' } DB_COLUMNS;
|
||||
use constant REQUIRED_CREATE_FIELDS => UPDATE_COLUMNS;
|
||||
|
||||
use constant DB_TABLE => 'flagtypes';
|
||||
use constant LIST_ORDER => 'sortkey, name';
|
||||
use constant VALIDATORS => {
|
||||
name => \&_check_name,
|
||||
description => \&_check_description,
|
||||
target_type => \&_check_target_type,
|
||||
sortkey => \&_check_sortkey,
|
||||
is_active => \&Bugzilla::Object::check_boolean,
|
||||
is_requestable => \&Bugzilla::Object::check_boolean,
|
||||
is_requesteeble => \&Bugzilla::Object::check_boolean,
|
||||
is_multiplicable => \&Bugzilla::Object::check_boolean,
|
||||
grant_group_id => \&_check_group,
|
||||
request_group_id => \&_check_group,
|
||||
cc_list => \&_check_cc_list,
|
||||
};
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
@ -164,7 +180,7 @@ sub cc_list_obj
|
|||
sub cc_list_str
|
||||
{
|
||||
my $self = shift;
|
||||
return join(', ', map { $_->login } @{$self->cc_list});
|
||||
return join(', ', map { $_->login } @{$self->cc_list_obj});
|
||||
}
|
||||
|
||||
sub grant_group
|
||||
|
@ -232,6 +248,37 @@ Returns the total number of flag types matching the given criteria.
|
|||
|
||||
=cut
|
||||
|
||||
sub create
|
||||
{
|
||||
my ($class, $params) = @_;
|
||||
my $cc = $class->_check_cc_list(delete $params->{cc_list});
|
||||
my $self = $class->SUPER::create($params);
|
||||
$self->{cc_list} = $cc;
|
||||
$self->save_cc_list;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub update
|
||||
{
|
||||
my $self = shift;
|
||||
my $ch = $self->SUPER::update(@_);
|
||||
$self->save_cc_list;
|
||||
return $ch;
|
||||
}
|
||||
|
||||
sub save_cc_list
|
||||
{
|
||||
my $self = shift;
|
||||
Bugzilla->dbh->do("DELETE FROM flagtype_cc_list WHERE object_id=?", undef, $self->id);
|
||||
if (@{$self->{cc_list}})
|
||||
{
|
||||
Bugzilla->dbh->do(
|
||||
"INSERT INTO flagtype_cc_list (object_id, value_id) VALUES ".
|
||||
join(', ', map { "(?, ?)" } @{$self->{cc_list}}), undef, map { ($self->id, $_->id) } @{$self->{cc_list}}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub match
|
||||
{
|
||||
my ($criteria) = @_;
|
||||
|
@ -263,6 +310,72 @@ sub count
|
|||
return $count;
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Validators
|
||||
######################################################################
|
||||
|
||||
sub _check_name
|
||||
{
|
||||
my ($invocant, $name) = @_;
|
||||
($name && $name !~ /[ ,]/ && length($name) <= 255)
|
||||
|| ThrowUserError("flag_type_name_invalid", { name => $name });
|
||||
return $name;
|
||||
}
|
||||
|
||||
sub _check_description
|
||||
{
|
||||
my ($invocant, $description) = @_;
|
||||
$description = trim($description);
|
||||
length($description) < 2**16-1
|
||||
|| ThrowUserError("flag_type_description_invalid");
|
||||
return $description;
|
||||
}
|
||||
|
||||
sub _check_target_type
|
||||
{
|
||||
my ($invocant, $type) = @_;
|
||||
unless ($type eq 'bug' || $type eq 'attachment' || $type eq 'b' || $type eq 'a')
|
||||
{
|
||||
ThrowCodeError("flag_type_target_type_invalid", { target_type => $type });
|
||||
}
|
||||
return $type eq 'bug' || $type eq 'b' ? 'b' : 'a';
|
||||
}
|
||||
|
||||
sub _check_sortkey
|
||||
{
|
||||
my ($invocant, $sortkey) = @_;
|
||||
my $k = $sortkey;
|
||||
if (!detaint_natural($sortkey))
|
||||
{
|
||||
ThrowUserError("flag_type_sortkey_invalid", { sortkey => $k });
|
||||
}
|
||||
return $sortkey;
|
||||
}
|
||||
|
||||
sub _check_group
|
||||
{
|
||||
my ($invocant, $group, $field) = @_;
|
||||
# Convert group names to group IDs
|
||||
if ($group)
|
||||
{
|
||||
trick_taint($group);
|
||||
my $gid = Bugzilla->dbh->selectrow_array('SELECT id FROM groups WHERE name=?', undef, $group);
|
||||
$gid || ThrowUserError("group_unknown", { name => $group });
|
||||
$group = $gid;
|
||||
}
|
||||
else
|
||||
{
|
||||
$group = undef;
|
||||
}
|
||||
return $group;
|
||||
}
|
||||
|
||||
sub _check_cc_list
|
||||
{
|
||||
my ($invocant, $cc_list) = @_;
|
||||
return Bugzilla::User->match({ login_name => [ split /[\s,]*,[\s,]*/, $cc_list ] });
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Private Functions
|
||||
######################################################################
|
||||
|
|
|
@ -93,10 +93,22 @@ exit;
|
|||
# Functions
|
||||
################################################################################
|
||||
|
||||
sub get_prod_comp
|
||||
{
|
||||
my $product = scalar $cgi->param('product') || undef;
|
||||
my $component;
|
||||
if ($product)
|
||||
{
|
||||
$product = Bugzilla::Product::check_product($product);
|
||||
$component = scalar $cgi->param('component');
|
||||
$component = Bugzilla::Component->check({ product => $product, name => $component }) if $component;
|
||||
}
|
||||
return ($product, $component);
|
||||
}
|
||||
|
||||
sub ft_list
|
||||
{
|
||||
my $product = validateProduct(scalar $cgi->param('product'));
|
||||
my $component = validateComponent($product, scalar $cgi->param('component'));
|
||||
my ($product, $component) = get_prod_comp();
|
||||
my $product_id = $product ? $product->id : 0;
|
||||
my $component_id = $component ? $component->id : 0;
|
||||
my $show_flag_counts = (defined $cgi->param('show_flag_counts')) ? 1 : 0;
|
||||
|
@ -168,9 +180,10 @@ sub edit
|
|||
{
|
||||
my ($action) = @_;
|
||||
my $flag_type;
|
||||
my $target_type;
|
||||
if ($action eq 'enter')
|
||||
{
|
||||
validateTargetType();
|
||||
$target_type = scalar $cgi->param('target_type') eq 'attachment' ? 'attachment' : 'bug';
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -202,7 +215,7 @@ sub edit
|
|||
my %inclusions;
|
||||
$inclusions{"__Any__:__Any__"} = "0:0";
|
||||
$vars->{type} = {
|
||||
target_type => scalar $cgi->param('target_type'),
|
||||
target_type => $target_type,
|
||||
inclusions => \%inclusions,
|
||||
};
|
||||
}
|
||||
|
@ -218,24 +231,18 @@ sub edit
|
|||
sub processCategoryChange
|
||||
{
|
||||
my ($categoryAction, $token) = @_;
|
||||
validateIsActive();
|
||||
validateIsRequestable();
|
||||
validateIsRequesteeble();
|
||||
validateAllowMultiple();
|
||||
|
||||
my @inclusions = $cgi->param('inclusions');
|
||||
my @exclusions = $cgi->param('exclusions');
|
||||
if ($categoryAction eq 'include')
|
||||
{
|
||||
my $product = validateProduct(scalar $cgi->param('product'));
|
||||
my $component = validateComponent($product, scalar $cgi->param('component'));
|
||||
my ($product, $component) = get_prod_comp();
|
||||
my $category = ($product ? $product->id : 0) . ":" . ($component ? $component->id : 0);
|
||||
push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
|
||||
}
|
||||
elsif ($categoryAction eq 'exclude')
|
||||
{
|
||||
my $product = validateProduct(scalar $cgi->param('product'));
|
||||
my $component = validateComponent($product, scalar $cgi->param('component'));
|
||||
my ($product, $component) = get_prod_comp();
|
||||
my $category = ($product ? $product->id : 0) . ":" . ($component ? $component->id : 0);
|
||||
push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
|
||||
}
|
||||
|
@ -314,43 +321,19 @@ sub insert
|
|||
{
|
||||
my $token = shift;
|
||||
check_token_data($token, 'add_flagtype');
|
||||
my $name = validateName();
|
||||
my $description = validateDescription();
|
||||
validateTargetType();
|
||||
validateSortKey();
|
||||
validateIsActive();
|
||||
validateIsRequestable();
|
||||
validateIsRequesteeble();
|
||||
validateAllowMultiple();
|
||||
validateGroups();
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
Bugzilla->dbh->bz_start_transaction;
|
||||
|
||||
my $target_type = $cgi->param('target_type') eq "bug" ? "b" : "a";
|
||||
|
||||
$dbh->bz_start_transaction();
|
||||
|
||||
# Insert a record for the new flag type into the database.
|
||||
$dbh->do(
|
||||
'INSERT INTO flagtypes (name, description, target_type, sortkey, is_active, is_requestable,'.
|
||||
' is_requesteeble, is_multiplicable, grant_group_id, request_group_id)'.
|
||||
' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', undef,
|
||||
$name, $description, $target_type,
|
||||
scalar $cgi->param('sortkey'), scalar $cgi->param('is_active'),
|
||||
scalar $cgi->param('is_requestable'), scalar $cgi->param('is_requesteeble'),
|
||||
scalar $cgi->param('is_multiplicable'), scalar $cgi->param('grant_gid'),
|
||||
scalar $cgi->param('request_gid')
|
||||
);
|
||||
|
||||
# Get the ID of the new flag type.
|
||||
my $id = $dbh->bz_last_key('flagtypes', 'id');
|
||||
my $ft = Bugzilla::FlagType->create({
|
||||
map { ($_ => scalar $cgi->param($_)) } (Bugzilla::FlagType->UPDATE_COLUMNS, 'cc_list')
|
||||
});
|
||||
|
||||
# Populate the list of inclusions/exclusions for this flag type.
|
||||
validateAndSubmit($id);
|
||||
validateAndSubmit($ft->id);
|
||||
|
||||
$dbh->bz_commit_transaction();
|
||||
Bugzilla->dbh->bz_commit_transaction;
|
||||
|
||||
$vars->{name} = $name;
|
||||
$vars->{name} = $ft->name;
|
||||
$vars->{message} = "flag_type_created";
|
||||
delete_token($token);
|
||||
|
||||
|
@ -365,32 +348,20 @@ sub update
|
|||
{
|
||||
my $token = shift;
|
||||
check_token_data($token, 'edit_flagtype');
|
||||
my $flag_type = validateID();
|
||||
my $id = $flag_type->id;
|
||||
my $name = validateName();
|
||||
my $description = validateDescription();
|
||||
validateTargetType();
|
||||
validateSortKey();
|
||||
validateIsActive();
|
||||
validateIsRequestable();
|
||||
validateIsRequesteeble();
|
||||
validateAllowMultiple();
|
||||
validateGroups();
|
||||
|
||||
my $dbh = Bugzilla->dbh;
|
||||
my $user = Bugzilla->user;
|
||||
|
||||
$dbh->bz_start_transaction();
|
||||
$dbh->do(
|
||||
'UPDATE flagtypes SET name = ?, description = ?, sortkey = ?, is_active = ?, is_requestable = ?,'.
|
||||
' is_requesteeble = ?, is_multiplicable = ?, grant_group_id = ?, request_group_id = ?'.
|
||||
' WHERE id = ?', undef,
|
||||
$name, $description, scalar $cgi->param('sortkey'), scalar $cgi->param('is_active'),
|
||||
scalar $cgi->param('is_requestable'), scalar $cgi->param('is_requesteeble'), scalar $cgi->param('is_multiplicable'),
|
||||
scalar $cgi->param('grant_gid'), scalar $cgi->param('request_gid'), $id
|
||||
);
|
||||
|
||||
my $flag_type = validateID();
|
||||
for (Bugzilla::FlagType->UPDATE_COLUMNS, 'cc_list')
|
||||
{
|
||||
$flag_type->set($_, scalar $cgi->param($_));
|
||||
}
|
||||
$flag_type->update;
|
||||
|
||||
# Update the list of inclusions/exclusions for this flag type.
|
||||
validateAndSubmit($id);
|
||||
validateAndSubmit($flag_type->id);
|
||||
|
||||
$dbh->bz_commit_transaction();
|
||||
|
||||
|
@ -403,7 +374,7 @@ sub update
|
|||
' AND (bugs.product_id = i.product_id OR i.product_id IS NULL)'.
|
||||
' AND (bugs.component_id = i.component_id OR i.component_id IS NULL))'.
|
||||
' WHERE flags.type_id = ? AND i.type_id IS NULL',
|
||||
undef, $id
|
||||
undef, $flag_type->id
|
||||
);
|
||||
Bugzilla::Flag->force_retarget($flag_ids);
|
||||
|
||||
|
@ -414,23 +385,23 @@ sub update
|
|||
' WHERE flags.type_id = ?'.
|
||||
' AND (bugs.product_id = e.product_id OR e.product_id IS NULL)'.
|
||||
' AND (bugs.component_id = e.component_id OR e.component_id IS NULL)',
|
||||
undef, $id
|
||||
undef, $flag_type->id
|
||||
);
|
||||
Bugzilla::Flag->force_retarget($flag_ids);
|
||||
|
||||
# Now silently remove requestees from flags which are no longer
|
||||
# specifically requestable.
|
||||
if (!$cgi->param('is_requesteeble'))
|
||||
if (!$flag_type->is_requesteeble)
|
||||
{
|
||||
$dbh->do('UPDATE flags SET requestee_id = NULL WHERE type_id = ?', undef, $id);
|
||||
$dbh->do('UPDATE flags SET requestee_id = NULL WHERE type_id = ?', undef, $flag_type->id);
|
||||
}
|
||||
|
||||
$vars->{name} = $name;
|
||||
$vars->{name} = $flag_type->name;
|
||||
$vars->{message} = "flag_type_changes_saved";
|
||||
delete_token($token);
|
||||
|
||||
$vars->{bug_types} = Bugzilla::FlagType::match({'target_type' => 'bug'});
|
||||
$vars->{attachment_types} = Bugzilla::FlagType::match({'target_type' => 'attachment'});
|
||||
$vars->{bug_types} = Bugzilla::FlagType::match({ target_type => 'bug' });
|
||||
$vars->{attachment_types} = Bugzilla::FlagType::match({ target_type => 'attachment' });
|
||||
|
||||
$template->process("admin/flag-type/list.html.tmpl", $vars)
|
||||
|| ThrowTemplateError($template->error());
|
||||
|
@ -533,97 +504,6 @@ sub validateID
|
|||
return $flag_type;
|
||||
}
|
||||
|
||||
sub validateName
|
||||
{
|
||||
my $name = $cgi->param('name');
|
||||
($name && $name !~ /[ ,]/ && length($name) <= 50)
|
||||
|| ThrowUserError("flag_type_name_invalid", { name => $name });
|
||||
trick_taint($name);
|
||||
return $name;
|
||||
}
|
||||
|
||||
sub validateDescription
|
||||
{
|
||||
my $description = $cgi->param('description');
|
||||
length($description) < 2**16-1
|
||||
|| ThrowUserError("flag_type_description_invalid");
|
||||
trick_taint($description);
|
||||
return $description;
|
||||
}
|
||||
|
||||
sub validateProduct
|
||||
{
|
||||
my $product_name = shift;
|
||||
return unless $product_name;
|
||||
|
||||
my $product = Bugzilla::Product::check_product($product_name);
|
||||
return $product;
|
||||
}
|
||||
|
||||
sub validateComponent
|
||||
{
|
||||
my ($product, $component_name) = @_;
|
||||
return unless $component_name;
|
||||
|
||||
($product && $product->id)
|
||||
|| ThrowUserError("flag_type_component_without_product");
|
||||
|
||||
my $component = Bugzilla::Component->check({ product => $product, name => $component_name });
|
||||
return $component;
|
||||
}
|
||||
|
||||
sub validateSortKey
|
||||
{
|
||||
# $sortkey is destroyed if detaint_natural fails.
|
||||
my $sortkey = $cgi->param('sortkey');
|
||||
detaint_natural($sortkey)
|
||||
|| ThrowUserError("flag_type_sortkey_invalid", { sortkey => scalar $cgi->param('sortkey') });
|
||||
$cgi->param('sortkey', $sortkey);
|
||||
}
|
||||
|
||||
sub validateTargetType
|
||||
{
|
||||
grep($cgi->param('target_type') eq $_, ("bug", "attachment"))
|
||||
|| ThrowCodeError("flag_type_target_type_invalid", { target_type => scalar $cgi->param('target_type') });
|
||||
}
|
||||
|
||||
sub validateIsActive
|
||||
{
|
||||
$cgi->param('is_active', $cgi->param('is_active') ? 1 : 0);
|
||||
}
|
||||
|
||||
sub validateIsRequestable
|
||||
{
|
||||
$cgi->param('is_requestable', $cgi->param('is_requestable') ? 1 : 0);
|
||||
}
|
||||
|
||||
sub validateIsRequesteeble
|
||||
{
|
||||
$cgi->param('is_requesteeble', $cgi->param('is_requesteeble') ? 1 : 0);
|
||||
}
|
||||
|
||||
sub validateAllowMultiple
|
||||
{
|
||||
$cgi->param('is_multiplicable', $cgi->param('is_multiplicable') ? 1 : 0);
|
||||
}
|
||||
|
||||
sub validateGroups
|
||||
{
|
||||
my $dbh = Bugzilla->dbh;
|
||||
# Convert group names to group IDs
|
||||
foreach my $col ('grant', 'request')
|
||||
{
|
||||
my $name = $cgi->param($col . '_group');
|
||||
if ($name)
|
||||
{
|
||||
trick_taint($name);
|
||||
my $gid = $dbh->selectrow_array('SELECT id FROM groups WHERE name = ?', undef, $name);
|
||||
$gid || ThrowUserError("group_unknown", { name => $name });
|
||||
$cgi->param($col . '_gid', $gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# At this point, values either come the DB itself or have been recently
|
||||
# added by the user and have passed all validation tests.
|
||||
# The only way to have invalid product/component combinations is to
|
||||
|
@ -666,16 +546,6 @@ sub validateAndSubmit
|
|||
$sth->execute($id, $product_id, $component_id);
|
||||
}
|
||||
}
|
||||
|
||||
my $cc_list = Bugzilla::User->match({ login_name => [ split /[\s,]*,[\s,]*/, scalar $cgi->param('cc_list') ] });
|
||||
$dbh->do("DELETE FROM flagtype_cc_list WHERE object_id=?", undef, $id);
|
||||
if (@$cc_list)
|
||||
{
|
||||
$dbh->do(
|
||||
"INSERT INTO flagtype_cc_list (object_id, value_id) VALUES ".
|
||||
join(', ', map { "(?, ?)" } @$cc_list), undef, map { ($id, $_->id) } @$cc_list
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub filter_group
|
||||
|
|
|
@ -203,7 +203,7 @@
|
|||
<td>
|
||||
the group allowed to grant/deny flags of this type
|
||||
(to allow all users to grant/deny these flags, select no group)<br>
|
||||
[% PROCESS select selname = "grant_group" %]
|
||||
[% PROCESS select selname = "grant_group_id" %]
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -213,7 +213,7 @@
|
|||
if flags of this type are requestable, the group allowed to request them
|
||||
(to allow all users to request these flags, select no group)<br>
|
||||
Note that the request group alone has no effect if the grant group is not defined!<br>
|
||||
[% PROCESS select selname = "request_group" %]
|
||||
[% PROCESS select selname = "request_group_id" %]
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
|
Loading…
Reference in New Issue