diff options
Diffstat (limited to 'extensions/ListOfBugs/lib/BugList.pm')
-rw-r--r-- | extensions/ListOfBugs/lib/BugList.pm | 404 |
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; |