summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/RuleEngine/lib/RuleGroup.pm')
-rw-r--r--extensions/RuleEngine/lib/RuleGroup.pm861
1 files changed, 861 insertions, 0 deletions
diff --git a/extensions/RuleEngine/lib/RuleGroup.pm b/extensions/RuleEngine/lib/RuleGroup.pm
new file mode 100644
index 000000000..65d9b1809
--- /dev/null
+++ b/extensions/RuleEngine/lib/RuleGroup.pm
@@ -0,0 +1,861 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package Bugzilla::Extension::RuleEngine::RuleGroup;
+
+use strict;
+use warnings;
+use 5.10.1;
+use base qw(Bugzilla::Object Exporter);
+@Bugzilla::Extension::RuleEngine::RuleGroup::EXPORT = qw(sort_rules_by_group);
+
+use Bugzilla::Constants;
+use Bugzilla::Field;
+use Bugzilla::Util;
+use Bugzilla::Error;
+use Bugzilla::Group;
+use Bugzilla::Product;
+use Bugzilla::User;
+use Scalar::Util qw(blessed);
+use List::MoreUtils qw(any none);
+use Bugzilla::Extension::RuleEngine::RuleState;
+
+###############################
+#### Initialization ####
+###############################
+
+use constant DB_TABLE => 'rh_rule_group';
+use constant LIST_ORDER => 'name';
+
+use constant DB_COLUMNS => qw(
+ id
+ name
+ description
+ isactive
+ user_id
+);
+
+use constant UPDATE_COLUMNS => qw(
+ name
+ description
+ isactive
+ user_id
+);
+
+use constant VALIDATORS => {
+ name => \&_check_name,
+ description => \&_check_description,
+ isactive => \&Bugzilla::Object::check_boolean,
+ user_id => \&_check_user_id
+};
+
+###############################
+#### Validators ####
+###############################
+
+sub _check_name {
+ my ($invocant, $name) = @_;
+
+ $name = trim($name);
+ $name || ThrowUserError('rule_group_not_specified');
+
+ if (length($name) > 64) {
+ ThrowUserError('rule_group_name_too_long', {'name' => $name});
+ }
+
+ my $rule_group
+ = Bugzilla::Extension::RuleEngine::RuleGroup->new({name => $name});
+ if ($rule_group && (!ref $invocant || $rule_group->id != $invocant->id)) {
+ ThrowUserError("rule_group_already_exists", {name => $rule_group->name});
+ }
+ return $name;
+}
+
+sub _check_description {
+ my ($invocant, $description) = @_;
+
+ $description = trim($description || '');
+ return $description;
+}
+
+sub _check_user_id {
+ my ($invocant, $id) = @_;
+
+ my $user;
+
+ if ($id && $id ne '') {
+ $user = get_user($id);
+ }
+
+ return ($user ? $user->id : undef);
+}
+
+###############################
+#### Methods ####
+###############################
+
+sub set_name { $_[0]->set('name', $_[1]); return; }
+sub set_description { $_[0]->set('description', $_[1]); return; }
+sub set_is_active { $_[0]->set('isactive', $_[1]); return; }
+sub set_user_id { $_[0]->set('user_id', $_[1]); return; }
+
+sub set_maintainers {
+ my ($self, $names) = @_;
+
+ $self->{'_old_maintainers'} = $self->maintainers;
+ $self->{maintainers} = undef;
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->do("DELETE FROM rh_rule_group_maintainers WHERE rule_group_id = ?",
+ undef, ($self->id));
+
+ foreach my $name (@$names) {
+ next unless ($name);
+ my $user = get_user($name);
+ next unless ($user);
+ $dbh->do(
+ "INSERT INTO rh_rule_group_maintainers (rule_group_id, user_id) VALUES (?, ?)",
+ undef,
+ ($self->id, $user->id)
+ );
+ }
+
+ $self->maintainers;
+
+ return;
+}
+
+sub rule_count {
+ my $self = shift;
+ my $dbh = Bugzilla->dbh;
+
+ if (!defined $self->{'rule_count'}) {
+ $self->{'rule_count'} = $dbh->selectrow_array(
+ q{
+ SELECT COUNT(*) FROM rh_rule
+ WHERE rule_group_id = ?}, undef, $self->id
+ ) || 0;
+ }
+ return $self->{'rule_count'};
+}
+
+###############################
+#### Accessors ####
+###############################
+
+sub description { return $_[0]->{'description'}; }
+sub is_active { return $_[0]->{'isactive'}; }
+sub user_id { return $_[0]->{'user_id'}; }
+
+sub user_name {
+ my $self = shift;
+ my $name = '';
+ if ($self->user_id()) {
+ my $user = get_user($self->user_id());
+ $name = $user->login;
+ }
+
+ return ($name);
+}
+
+sub maintainer_names {
+ my $self = shift;
+ my $str = '';
+ my $maintainers = $self->maintainers;
+
+ $str = join(', ', map { $_->login } @$maintainers);
+
+ return ($str);
+}
+
+sub maintainers {
+ my $self = shift;
+ my @users = ();
+
+ if (!defined $self->{maintainers}) {
+ my $ids = Bugzilla->dbh->selectcol_arrayref(
+ "SELECT user_id FROM rh_rule_group_maintainers
+ WHERE rule_group_id = ?", undef, $self->id
+ );
+
+ if (@$ids) {
+ $self->{maintainers} = Bugzilla::User->new_from_list($ids);
+ }
+ }
+
+ return $self->{maintainers};
+}
+
+###############################
+#### Helpers ####
+###############################
+
+# This function is a helper to sort rules to be listed
+# in global/choose-rule.html.tmpl.
+
+sub sort_rules_by_group {
+ my ($self, $rules) = @_;
+
+ my $group = {};
+
+ # Get all rule groups with at least one rule.
+ foreach my $rule (@$rules) {
+ $group->{$rule->rule_group_id}->{'object'}
+ ||= new Bugzilla::Extension::RuleEngine::RuleGroup($rule->rule_group_id);
+
+ # Nice way to group rules per rule group, without querying
+ # the DB again.
+ push(@{$group->{$rule->rule_group_id}->{'rules'}}, $rule);
+ }
+ return [sort { lc($a->{'object'}->name) cmp lc($b->{'object'}->name) }
+ (values %$group)];
+
+}
+
+## RED HAT EXTENSION START 1291476
+
+sub get_group {
+ my $group = shift;
+ if (!blessed $group) {
+ if ($group =~ /^\d+$/) {
+ $group = Bugzilla::Group->check({id => $group});
+ }
+ else {
+ $group = Bugzilla::Group->check({name => $group});
+ }
+ }
+ return $group;
+}
+
+sub get_user {
+ my $user = shift;
+ if (!blessed $user) {
+ if ($user =~ /^\d+$/) {
+ $user = Bugzilla::User->check({id => $user});
+ }
+ else {
+ $user = Bugzilla::User->check($user);
+ }
+ }
+
+ return $user;
+}
+
+sub view_groups {
+ my $self = shift;
+ return [] unless $self->id;
+ if (!defined $self->{view_groups}) {
+ my $gids = Bugzilla->dbh->selectcol_arrayref(
+ "SELECT group_id FROM rh_rule_group_view_groups
+ WHERE rule_group_id = ?", undef, $self->id
+ );
+
+ if (@$gids) {
+ $self->{view_groups} = Bugzilla::Group->new_from_list($gids);
+ }
+ }
+ return $self->{view_groups};
+}
+
+sub add_view_group {
+ my ($self, $group) = @_;
+
+ $group = get_group($group);
+
+ return unless ($self->user_can_edit);
+
+ return
+ if (
+ $self->view_groups && any { $_->id == $group->id }
+ @{$self->view_groups}
+ );
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->do(
+ "INSERT INTO rh_rule_group_view_groups (rule_group_id, group_id) VALUES (?, ?)",
+ undef,
+ ($self->id, $group->id)
+ );
+
+ return;
+}
+
+sub remove_view_group {
+ my ($self, $group) = @_;
+ $group = get_group($group);
+
+ return unless ($self->user_can_edit);
+ return if (!view_groups || none { $_->id == $group->id } @{$self->view_groups});
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->do(
+ "DELETE FROM rh_rule_group_view_groups WHERE rule_group_id = ? AND group_id = ?",
+ undef,
+ ($self->id, $group->id)
+ );
+
+ return;
+}
+
+sub _set_groups {
+ my ($self, $type, $groups) = @_;
+
+ my $old_key = "_old_${type}_groups";
+ my $new_key = "${type}_groups";
+
+ unless (defined($self->{$old_key})) {
+ my $method = "${type}_groups";
+ my $rc = $self->$method;
+ $self->{$old_key} = $self->$method // [];
+ }
+
+ $self->{$new_key} = undef;
+
+ my $dbh = Bugzilla->dbh;
+
+ $dbh->do("DELETE FROM rh_rule_group_${type}_groups WHERE rule_group_id = ?",
+ undef, ($self->id));
+
+ my $add_method = "add_${type}_group";
+ foreach my $grp (@$groups) {
+ $self->$add_method($grp);
+ }
+
+ $self->{$new_key} = $groups;
+
+ return;
+}
+
+sub set_view_groups {
+ my ($self, $groups) = @_;
+
+ $groups //= [];
+
+ $self->_set_groups('view', $groups);
+
+ return;
+}
+
+sub set_edit_groups {
+ my ($self, $groups) = @_;
+
+ $groups //= [];
+
+ $self->_set_groups('edit', $groups);
+
+ return;
+}
+
+sub edit_groups {
+ my $self = shift;
+
+ return [] unless $self->id;
+ if (!defined $self->{edit_groups}) {
+ my $gids = Bugzilla->dbh->selectcol_arrayref(
+ "SELECT group_id FROM rh_rule_group_edit_groups
+ WHERE rule_group_id = ?", undef, $self->id
+ );
+
+ if (@$gids) {
+ $self->{edit_groups} = Bugzilla::Group->new_from_list($gids);
+ }
+ }
+ return $self->{edit_groups};
+}
+
+sub add_edit_group {
+ my ($self, $group) = @_;
+ $group = get_group($group);
+
+ return unless ($self->user_can_edit);
+
+ return
+ if (
+ $self->edit_groups && any { $_->id == $group->id }
+ @{$self->edit_groups}
+ );
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->do(
+ "INSERT INTO rh_rule_group_edit_groups (rule_group_id, group_id) VALUES (?, ?)",
+ undef,
+ ($self->id, $group->id)
+ );
+
+ return;
+}
+
+sub remove_edit_group {
+ my ($self, $group) = @_;
+ $group = get_group($group);
+
+ return unless ($self->user_can_edit);
+ return
+ if (!$self->edit_groups
+ || none { $_->id == $group->id } @{$self->edit_groups});
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->do(
+ "DELETE FROM rh_rule_group_edit_groups WHERE rule_group_id = ? AND group_id = ?",
+ undef,
+ ($self->id, $group->id)
+ );
+
+ return;
+}
+
+sub user_can_view {
+ my ($self, $user) = @_;
+
+ $user //= Bugzilla->user;
+ $user = get_user($user);
+
+ return 0 unless $user->id;
+
+ $self->{user_can_view} = {} unless defined $self->{user_can_view};
+
+ if (!defined $self->{user_can_view}->{$user->id}) {
+ my $can_view = 0;
+ if ($self->user_can_edit($user)) {
+ $can_view = 1;
+ }
+ elsif (
+ $self->view_groups && any { $user->in_group_id($_->id) }
+ @{$self->view_groups}
+ )
+ {
+ $can_view = 1;
+ }
+ $self->{user_can_view}->{$user->id} = $can_view;
+ }
+ return $self->{user_can_view}->{$user->id};
+}
+
+sub user_can_edit {
+ my ($self, $user) = @_;
+
+ $user //= Bugzilla->user;
+ $user = get_user($user);
+
+ return 0 unless $user->id;
+
+ $self->{user_can_edit} = {} unless defined $self->{user_can_edit};
+
+ if (!defined $self->{user_can_edit}->{$user->id}) {
+ my $can_edit = 0;
+ if ($user->in_group("admin")) {
+ $can_edit = 1;
+ }
+ elsif (
+ $self->edit_groups && any { $user->in_group_id($_->id) }
+ @{$self->edit_groups}
+ )
+ {
+ $can_edit = 1;
+ }
+
+ $self->{user_can_edit}->{$user->id} = $can_edit;
+ }
+
+ return $self->{user_can_edit}->{$user->id};
+}
+
+sub products {
+ my ($self) = @_;
+
+ my $products = [];
+
+ return $products unless $self->id;
+
+ my $ids
+ = Bugzilla->dbh->selectcol_arrayref(
+ "SELECT id FROM products WHERE rule_group = ?",
+ undef, $self->id);
+
+ if (@$ids) {
+ $products = Bugzilla::Product->new_from_list($ids);
+ }
+ return $products;
+}
+
+sub classifications {
+ my ($self) = @_;
+
+ my $classifications = [];
+ return $classifications unless $self->id;
+
+ my $ids
+ = Bugzilla->dbh->selectcol_arrayref(
+ "SELECT DISTINCT classification_id FROM products WHERE rule_group = ?",
+ undef, $self->id);
+
+ if (@$ids) {
+ $classifications = Bugzilla::Classification->new_from_list($ids);
+ }
+
+ return $classifications;
+}
+
+sub all_user_can_edit {
+ my ($invocant, $user) = @_;
+
+ $user //= Bugzilla->user;
+ my @rule_groups;
+
+ foreach my $rg (Bugzilla::Extension::RuleEngine::RuleGroup->get_all()) {
+ push(@rule_groups, $rg) if ($rg->user_can_edit($user));
+ }
+
+ return (@rule_groups);
+}
+
+sub all_user_can_view {
+ my ($invocant, $user) = @_;
+
+ $user //= Bugzilla->user;
+ my @rule_groups = ();
+
+ foreach my $rg (Bugzilla::Extension::RuleEngine::RuleGroup->get_all()) {
+ push(@rule_groups, $rg)
+ if ($rg->user_can_edit($user) || $rg->user_can_view($user));
+ }
+
+ return (@rule_groups);
+}
+
+## RED HAT EXTENSION END 1291476
+
+sub disabled_count {
+ my ($self) = @_;
+
+ return (Bugzilla::Extension::RuleEngine::RuleState->disabled_count($self->id));
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Extension::RuleEngine::RuleGroup - Bugzilla Rule Group class.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Extension::RuleEngine::RuleGroup;
+
+ my $rule_group = new Bugzilla::Extension::RuleEngine::RuleGroup(1);
+ my $rule_group = new Bugzilla::Extension::RuleEngine::RuleGroup({name => 'Acme'});
+
+ my $id = $rule_group->id;
+ my $name = $rule_group->name;
+ my $description = $rule_group->description;
+ my $is_active = $rule_group->is_active;
+
+=head1 DESCRIPTION
+
+Bugzilla::Extension::RuleEngine::RuleGroup represents a rule group object. It is an
+implementation of L<Bugzilla::Object>, and thus provides all methods
+that L<Bugzilla::Object> provides.
+
+The methods that are specific to C<Bugzilla::Extension::RuleEngine::RuleGroup> are listed
+below.
+
+A Rule Group is a higher-level grouping of Rule (from the Bugzilla Rules Engine).
+
+=head1 METHODS
+
+=over
+
+=item C<rule_count>
+
+=over
+
+=item B<Description>
+
+Returns the total number of rules that belong to the rule group.
+
+=item B<Params>
+
+none.
+
+=item B<Returns>
+
+Integer - The total of rules inside the rule group.
+
+=back
+
+=item C<sort_rules_by_group>
+
+=over
+
+=item B<Description>
+
+This is a helper which returns a list of rules sorted
+by rule group in a form suitable to be passed to the
+main rules page template.
+
+=item B<Params>
+
+An arrayref of rule objects.
+
+=item B<Returns>
+
+An arrayref of hashes suitable to be passed to template.
+
+Each arrayref has two keys, object is the
+Bugzilla::Extension::RuleEngine::RuleGroup object, and
+rules are the list of rules (Bugzilla::Extension::RuleEngine::Rule
+object)
+
+=back
+
+=item C<user_can_edit>
+
+=over
+
+=item B<Description>
+
+can the specified user edit this RuleGroup?
+
+=item B<Params>
+
+=over
+
+=item C<$user> (optional) L<Bugzilla::User> object.
+
+Current logged in user is used if not given.
+
+=back
+
+=item B<Returns>
+
+Boolean, true if user is allowed to edit the team.
+
+=back
+
+=item C<classifications>
+
+=over
+
+=item B<Description>
+
+What classifications are using this BRE group?
+
+=item B<Params>
+
+None.
+
+=item B<Returns>
+
+An arrayref of L<Bugzilla::Classification> objects.
+
+=back
+
+=item C<remove_edit_group>
+
+=over
+
+=item B<Description>
+
+Removes a edit group from the team.
+
+=item B<Params>
+
+=over
+
+=item C<$group> Group object, name or id
+
+=back
+
+=item B<Returns>
+
+Nothing.
+
+=back
+
+=item C<add_edit_group>
+
+=over
+
+=item B<Description>
+
+Adds a new edit_group to the team.
+
+=item B<Params>
+
+=over
+
+=item C<$group> Group object, name or id
+
+=back
+
+=item B<Returns>
+
+Nothing.
+
+=back
+
+=item C<edit_groups>
+
+=over
+
+=item B<Description>
+
+
+List all edit groups for thie RuleGroup.
+
+=item B<Params>
+
+None.
+
+=item B<Returns>
+
+Array ref of L<Bugzilla::Group> objects containing all edit groups.
+
+=back
+
+=item C<view_groups>
+
+=over
+
+=item B<Description>
+
+List view groups for this RuleGroup.
+
+=item B<Params>
+
+None.
+
+=item B<Returns>
+
+An array ref of L<Bugzilla::Group> objects.
+
+=back
+
+=item C<add_view_group>
+
+=over
+
+=item B<Description>
+
+Adds a new view_group to the team.
+
+=item B<Params>
+
+=over
+
+=item C<$group> Group object, name or id
+
+=back
+
+=item B<Returns>
+
+Nothing.
+
+=back
+
+=item C<remove_view_group>
+
+=over
+
+=item B<Description>
+
+Removes a view group from the team.
+
+=item B<Params>
+
+=over
+
+=item C<$group> Group object, name or id
+
+=back
+
+=item B<Returns>
+
+Nothing.
+
+=back
+
+=item C<get_user>
+
+=over
+
+=item B<Description>
+
+Gets user object or throws error if user is not found. Without
+parameters returns the logged in user
+
+=item B<Params>
+
+$user -> User ID or login name
+
+=item B<Returns>
+
+L<Bugzilla::User> object
+
+=back
+
+=item C<get_group>
+
+=over
+
+=item B<Description>
+
+Gets group object or throws error if group is not found.
+
+=item B<Params>
+
+$group -> Group ID or name
+
+=item B<Returns>
+
+L<Bugzilla::Group> object
+
+=back
+
+=item C<products>
+
+=over
+
+=item B<Description>
+
+What products are using this BRE group?
+
+=item B<Params>
+
+None.
+
+=item B<Returns>
+
+An array ref of L<Bugzilla::Product> objects.
+
+=back
+
+=item C<user_can_view>
+
+=over
+
+=item B<Description>
+
+Can the user view the RuleGroup and it's Rules?
+
+=item B<Params>
+
+=over
+
+=item C<$user> (optional) L<Bugzilla::User> object.
+
+Current logged in user is used if not given.
+
+=back
+
+=item B<Returns>
+
+Boolean, true if user can view RuleGroup.
+
+=back
+
+=back
+
+=cut