summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/ListOfBugs/lib/BugList.pm')
-rw-r--r--extensions/ListOfBugs/lib/BugList.pm404
1 files changed, 404 insertions, 0 deletions
diff --git a/extensions/ListOfBugs/lib/BugList.pm b/extensions/ListOfBugs/lib/BugList.pm
new file mode 100644
index 000000000..2bdec78f5
--- /dev/null
+++ b/extensions/ListOfBugs/lib/BugList.pm
@@ -0,0 +1,404 @@
+# 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::ListOfBugs::BugList;
+
+use strict;
+use warnings;
+use 5.10.1;
+
+use List::MoreUtils qw(any);
+
+use Bugzilla;
+use Bugzilla::Util qw(trim trick_taint diff_arrays);
+use Bugzilla::Error;
+use Bugzilla::Constants;
+
+use base qw(Bugzilla::Object);
+
+
+use constant DB_TABLE => 'lob';
+use constant LIST_ORDER => 'name';
+
+use constant DB_COLUMNS => qw(
+ id
+ name
+ description
+ owner
+ lastused
+ updated
+);
+
+use constant VALIDATORS => {
+ name => \&_check_name,
+ owner => \&_check_owner,
+ lastused => \&_check_lastused,
+ updated => \&_check_updated,
+};
+
+use constant UPDATE_COLUMNS => qw(
+ name
+ owner
+ description
+ lastused
+);
+
+##### SETTERS #####
+
+sub set_name { $_[0]->{name} = $_[1]; return; }
+sub set_owner { $_[0]->{owner} = $_[1]; return; }
+sub set_lastused { $_[0]->{lastused} = $_[1]; return; }
+sub set_updated { $_[0]->{updated} = $_[1]; return; }
+sub set_description { $_[0]->{description} = $_[1]; return; }
+
+sub _set_groups {
+ my ($self, $type, $groups) = @_;
+
+ my $old_key = "_old_${type}_groups";
+ my $new_key = "${type}_groups";
+
+ foreach my $group (@$groups) {
+ $self->_validate_group($group);
+ }
+
+ unless (defined($self->{$old_key})) {
+ my $method = "${type}_groups";
+ my $rc = $self->$method;
+ $self->{$old_key} = $self->$method;
+ }
+
+ $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;
+}
+
+##### GETTERS #####
+
+sub owner_id { return $_[0]->{owner}; }
+sub owner { return Bugzilla::User->new($_[0]->owner_id); }
+sub updated { return $_[0]->{updated}; }
+sub lastused { return $_[0]->{lastused}; }
+sub description { return $_[0]->{description}; }
+
+sub _get_groups {
+ my ($self, $is_view_group) = @_;
+
+ my $sql
+ = 'SELECT group_id FROM lob_group_map WHERE lob_id = ? AND is_view_group = ?';
+
+ my $ids
+ = Bugzilla->dbh->selectcol_arrayref($sql, undef, $self->id, $is_view_group);
+
+ my $groups = Bugzilla::Group->new_from_list($ids) // [];
+
+ return $groups;
+}
+
+sub view_groups {
+ my ($self) = @_;
+
+ if (defined $self->{view_groups}) {
+ return $self->{view_groups};
+ }
+
+ my $groups = $self->_get_groups(1);
+
+ $self->{view_groups} = $groups;
+
+ return $groups;
+}
+
+sub edit_groups {
+ my ($self) = @_;
+
+ if (defined $self->{edit_groups}) {
+ return $self->{edit_groups};
+ }
+
+ my $groups = $self->_get_groups(0);
+
+ $self->{edit_groups} = $groups;
+
+ return $groups;
+}
+
+##### VALIDATORS #####
+
+sub _check_name {
+ my ($invocant, $name) = @_;
+
+ $name = trim($name);
+
+ if (Bugzilla::Extension::ListOfBugs::BugList->new({name => $name})) {
+ ThrowUserError('buglist_already_exists', {name => $name});
+ }
+
+ return $name;
+}
+
+sub _check_owner {
+ my ($invocant, $owner) = @_;
+
+ return Bugzilla->user->id;
+}
+
+sub _localtimestamp {
+ return Bugzilla->dbh->selectrow_array('SELECT CURRENT_TIMESTAMP');
+}
+
+sub _check_lastused {
+ return _localtimestamp();
+}
+
+sub _check_updated {
+ return _localtimestamp();
+}
+
+#### Functions ####
+
+sub update_used {
+ my ($self) = @_;
+
+ $self->set_lastused(_localtimestamp());
+ $self->update;
+
+ return;
+}
+
+# Return a list of integer bug ids that comprise this list of bugs.
+# This may include bugs that the user is not entitled to see.
+sub bug_ids {
+ my ($self) = @_;
+
+ if (defined($self->{bug_id_list})) {
+ return $self->{bug_id_list};
+ }
+
+ my $query = 'SELECT bug_id FROM lob_bugs WHERE lob_id = ?';
+
+ my $result = Bugzilla->dbh->selectcol_arrayref($query, undef, $self->id);
+
+ $self->{bug_id_list} = $result;
+
+ return $result;
+}
+
+sub set_bug_ids {
+ my ($self, $bug_list) = @_;
+
+ unless (defined($self->{_old_bug_id_list})) {
+ $self->{_old_bug_id_list} = $self->bug_ids;
+ }
+ $self->{bug_id_list} = $bug_list;
+
+ return;
+}
+
+# Set a new list of bug ids for this search, replacing the old list.
+sub _update_bug_ids {
+ my ($self) = @_;
+
+ return unless defined $self->{_old_bug_id_list};
+
+ my ($removed, $added) = diff_arrays($self->{_old_bug_id_list}, $self->bug_ids);
+
+ my $delete_sql = 'DELETE FROM lob_bugs WHERE lob_id = ?';
+ my $insert_sql = 'INSERT INTO lob_bugs (lob_id, bug_id) VALUES (?, ?)';
+
+ if (scalar(@$removed) == 0 && scalar(@$added) == 0) {
+ return;
+ }
+
+ my $dbh = Bugzilla->dbh;
+
+ $dbh->bz_start_transaction;
+ $dbh->do($delete_sql, undef, $self->id);
+
+ my $stmt = $dbh->prepare($insert_sql);
+ foreach my $bug_id (@{$self->bug_ids}) {
+ $stmt->execute($self->id, int $bug_id);
+ }
+
+ if ($self->AUDIT_UPDATES) {
+ my $removed_str = join(',', @$removed);
+ my $added_str = join(',', @$added);
+ $self->audit_log({bug_list => [$removed_str, $added_str]});
+ }
+
+ $self->set_updated(_localtimestamp());
+
+ $dbh->bz_commit_transaction;
+
+ if (defined(Bugzilla->request_cache->{bug_list}->{$self->id})) {
+ delete Bugzilla->request_cache->{bug_list}->{$self->id};
+ }
+ delete $self->{bug_id_list};
+ delete $self->{_old_bug_id_list};
+
+ return {removed => $removed, added => $added};
+}
+
+sub _update_groups {
+ my ($self, $type, $is_view_group) = @_;
+
+ my $old_key = "_old_${type}_groups";
+ my $new_key = "${type}_groups";
+
+ return unless defined $self->{$old_key};
+
+ my $delete_sql
+ = 'DELETE FROM lob_group_map WHERE lob_id = ? AND is_view_group = ?';
+ my $insert_sql
+ = 'INSERT INTO lob_group_map (lob_id, group_id, is_view_group) VALUES (?,?,?)';
+
+ my $groups = $self->$new_key;
+ my $old_groups = $self->{$old_key};
+
+ my @removed_ids = map { $_->id } @$old_groups;
+ my @added_ids = map { $_->id } @$groups;
+ my ($removed, $added) = diff_arrays(\@removed_ids, \@added_ids);
+
+ if (scalar(@$removed) == 0 && scalar(@$added) == 0) {
+ return;
+ }
+
+ my $dbh = Bugzilla->dbh;
+
+ $dbh->bz_start_transaction;
+ $dbh->do($delete_sql, undef, $self->id, $is_view_group);
+ my $stmt = $dbh->prepare($insert_sql);
+
+ foreach my $group (@$groups) {
+ $stmt->execute($self->id, $group->id, $is_view_group);
+ }
+
+ if ($self->AUDIT_UPDATES) {
+ my $removed_str = join(',', @$removed);
+ my $added_str = join(',', @$added);
+ $self->audit_log({"${type}_group" => [$removed_str, $added_str]});
+ }
+
+ $dbh->bz_commit_transaction;
+
+ delete $self->{$old_key};
+ delete $self->{$new_key};
+
+ my $changes = {};
+ $changes->{removed} = $removed if scalar(@$removed);
+ $changes->{added} = $added if scalar(@$added);
+
+ return $changes;
+}
+
+sub _remove_groups {
+ my ($self) = @_;
+
+ my $delete_sql = 'DELETE FROM lob_group_map WHERE lob_id = ?';
+
+ Bugzilla->dbh->do($delete_sql, undef, $self->id);
+
+ return;
+}
+
+sub remove_from_db {
+ my ($self) = @_;
+
+ my $dbh = Bugzilla->dbh;
+ $dbh->bz_start_transaction;
+ $self->set_bug_ids([]);
+ $self->_update_bug_ids;
+ $self->_remove_groups;
+ $self->SUPER::remove_from_db;
+ $dbh->bz_commit_transaction;
+
+ return;
+}
+
+sub update {
+ my $self = shift;
+
+ Bugzilla->dbh->bz_start_transaction;
+
+ my $updates = {};
+
+ if (defined $self->{_old_bug_id_list}) {
+ my $ch = $self->_update_bug_ids;
+ $updates->{bug_ids} = $ch if defined $ch;
+ }
+ if (defined $self->{_old_edit_groups}) {
+ my $ch = $self->_update_groups('edit', 0);
+ $updates->{edit_groups} = $ch if defined $ch;
+ }
+ if (defined $self->{_old_view_groups}) {
+ my $ch = $self->_update_groups('view', 1);
+ $updates->{view_groups} = $ch if defined $ch;
+ }
+
+ my ($changes, $old_self) = $self->SUPER::update(@_);
+
+ $changes = {(%$changes, %$updates)};
+
+ Bugzilla->dbh->bz_commit_transaction;
+
+ return ($changes, $old_self);
+}
+
+
+sub _validate_group {
+ my ($self, $group) = @_;
+
+ unless ($group->is_bug_group) {
+ ThrowUserError('buglist_must_be_bug_group', {group => $group});
+ }
+
+ return;
+}
+
+sub can_edit {
+ my ($self) = @_;
+
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
+
+ return 1 if $user->in_group('admin');
+
+ return 1 if ($self->owner eq $user->login_name);
+
+ return any { $user->in_group($_->name) } @{$self->edit_groups};
+}
+
+sub can_view {
+ my ($self) = @_;
+
+ return 1 if (scalar(@{$self->view_groups}) == 0);
+
+ my $user = Bugzilla->login(LOGIN_REQUIRED);
+
+ return 1 if ($user->in_group('admin'));
+
+ return 1 if ($self->owner eq $user->login);
+
+ return any { $user->in_group($_->name) } @{$self->view_groups};
+}
+
+1;