blob: 375707fd22939007c8548ce1e29eb68c0b38cbb4 [file] [log] [blame]
# 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/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
package Bugzilla::Extension::OldBugMove;
use 5.10.1;
use strict;
use warnings;
use parent qw(Bugzilla::Extension);
use Bugzilla::Constants;
use Bugzilla::Error;
use Bugzilla::Field::Choice;
use Bugzilla::Mailer;
use Bugzilla::User;
use Bugzilla::Util qw(trim);
use Scalar::Util qw(blessed);
use Storable qw(dclone);
use constant VERSION => BUGZILLA_VERSION;
# This is 4 because that's what it originally was when this code was
# a part of Bugzilla.
use constant CMT_MOVED_TO => 4;
sub install_update_db {
my $reso_type = Bugzilla::Field::Choice->type('resolution');
my $moved_reso = $reso_type->new({ name => 'MOVED' });
# We make the MOVED resolution inactive, so that it doesn't show up
# as a valid drop-down option.
if ($moved_reso) {
$moved_reso->set_is_active(0);
$moved_reso->update();
}
else {
print "Creating the MOVED resolution...\n";
$reso_type->create(
{ value => 'MOVED', sortkey => '30000', isactive => 0 });
}
}
sub config_add_panels {
my ($self, $args) = @_;
my $modules = $args->{'panel_modules'};
$modules->{'OldBugMove'} = 'Bugzilla::Extension::OldBugMove::Params';
}
sub template_before_create {
my ($self, $args) = @_;
my $config = $args->{config};
my $constants = $config->{CONSTANTS};
$constants->{CMT_MOVED_TO} = CMT_MOVED_TO;
my $vars = $config->{VARIABLES};
$vars->{oldbugmove_user_is_mover} = \&_user_is_mover;
}
sub object_before_delete {
my ($self, $args) = @_;
my $object = $args->{'object'};
if ($object->isa('Bugzilla::Field::Choice::resolution')) {
if ($object->name eq 'MOVED') {
ThrowUserError('oldbugmove_no_delete_moved');
}
}
}
sub object_before_set {
my ($self, $args) = @_;
my ($object, $field) = @$args{qw(object field)};
if ($field eq 'resolution' and $object->isa('Bugzilla::Bug')) {
# Store the old value so that end_of_set can check it.
$object->{'_oldbugmove_old_resolution'} = $object->resolution;
}
}
sub object_end_of_set {
my ($self, $args) = @_;
my ($object, $field) = @$args{qw(object field)};
if ($field eq 'resolution' and $object->isa('Bugzilla::Bug')) {
my $old_value = delete $object->{'_oldbugmove_old_resolution'};
return if $old_value eq $object->resolution;
if ($object->resolution eq 'MOVED') {
$object->add_comment('', { type => CMT_MOVED_TO,
extra_data => Bugzilla->user->login });
}
}
}
sub object_end_of_set_all {
my ($self, $args) = @_;
my $object = $args->{'object'};
if ($object->isa('Bugzilla::Bug') and Bugzilla->input_params->{'oldbugmove'}) {
my $new_status = Bugzilla->params->{'duplicate_or_move_bug_status'};
$object->set_bug_status($new_status, { resolution => 'MOVED' });
}
}
sub object_validators {
my ($self, $args) = @_;
my ($class, $validators) = @$args{qw(class validators)};
if ($class->isa('Bugzilla::Comment')) {
my $extra_data_validator = $validators->{extra_data};
$validators->{extra_data} =
sub { _check_comment_extra_data($extra_data_validator, @_) };
}
elsif ($class->isa('Bugzilla::Bug')) {
my $reso_validator = $validators->{resolution};
$validators->{resolution} =
sub { _check_bug_resolution($reso_validator, @_) };
}
}
sub _check_bug_resolution {
my $original_validator = shift;
my ($invocant, $resolution) = @_;
if ($resolution eq 'MOVED' && $invocant->resolution ne 'MOVED'
&& !Bugzilla->input_params->{'oldbugmove'})
{
# MOVED has a special meaning and can only be used when
# really moving bugs to another installation.
ThrowUserError('oldbugmove_no_manual_move');
}
return $original_validator->(@_);
}
sub _check_comment_extra_data {
my $original_validator = shift;
my ($invocant, $extra_data, undef, $params) = @_;
my $type = blessed($invocant) ? $invocant->type : $params->{type};
if ($type == CMT_MOVED_TO) {
return Bugzilla::User->check($extra_data)->login;
}
return $original_validator->(@_);
}
sub bug_end_of_update {
my ($self, $args) = @_;
my ($bug, $old_bug, $changes) = @$args{qw(bug old_bug changes)};
if (defined $changes->{'resolution'}
and $changes->{'resolution'}->[1] eq 'MOVED')
{
$self->_move_bug($bug, $old_bug);
}
}
sub _move_bug {
my ($self, $bug, $old_bug) = @_;
my $dbh = Bugzilla->dbh;
my $template = Bugzilla->template;
_user_is_mover(Bugzilla->user)
or ThrowUserError("auth_failure", { action => 'move',
object => 'bugs' });
# Don't export the new status and resolution. We want the current
# ones.
local $Storable::forgive_me = 1;
my $export_me = dclone($bug);
$export_me->{bug_status} = $old_bug->bug_status;
delete $export_me->{status};
$export_me->{resolution} = $old_bug->resolution;
# Prepare and send all data about these bugs to the new database
my $to = Bugzilla->params->{'move-to-address'};
$to =~ s/@/\@/;
my $from = Bugzilla->params->{'mailfrom'};
$from =~ s/@/\@/;
my $msg = "To: $to\n";
$msg .= "From: Bugzilla <" . $from . ">\n";
$msg .= "Subject: Moving bug " . $bug->id . "\n\n";
my @fieldlist = (Bugzilla::Bug->fields, 'group', 'long_desc',
'attachment', 'attachmentdata');
my %displayfields = map { $_ => 1 } @fieldlist;
my $vars = { bugs => [$export_me], displayfields => \%displayfields };
$template->process("bug/show.xml.tmpl", $vars, \$msg)
|| ThrowTemplateError($template->error());
$msg .= "\n";
MessageToMTA($msg);
}
sub _user_is_mover {
my $user = shift;
my @movers = map { trim($_) } split(',', Bugzilla->params->{'movers'});
return ($user->id and grep($_ eq $user->login, @movers)) ? 1 : 0;
}
__PACKAGE__->NAME;