Extension.pm 5.8 KB
Newer Older
1 2 3
# 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/.
4
#
5 6
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
7 8

package Bugzilla::Extension::OldBugMove;
9 10

use 5.10.1;
11
use strict;
12 13
use warnings;

14
use parent qw(Bugzilla::Extension);
15 16 17 18 19 20 21 22 23 24
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);

25 26
use constant VERSION => BUGZILLA_VERSION;

27 28 29 30 31
# 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 {
32 33 34 35 36 37 38 39 40 41 42 43 44
  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});
  }
45 46 47
}

sub config_add_panels {
48 49 50
  my ($self, $args) = @_;
  my $modules = $args->{'panel_modules'};
  $modules->{'OldBugMove'} = 'Bugzilla::Extension::OldBugMove::Params';
51 52 53
}

sub template_before_create {
54 55
  my ($self, $args) = @_;
  my $config = $args->{config};
56

57 58
  my $constants = $config->{CONSTANTS};
  $constants->{CMT_MOVED_TO} = CMT_MOVED_TO;
59

60 61
  my $vars = $config->{VARIABLES};
  $vars->{oldbugmove_user_is_mover} = \&_user_is_mover;
62 63 64
}

sub object_before_delete {
65 66 67 68 69
  my ($self, $args) = @_;
  my $object = $args->{'object'};
  if ($object->isa('Bugzilla::Field::Choice::resolution')) {
    if ($object->name eq 'MOVED') {
      ThrowUserError('oldbugmove_no_delete_moved');
70
    }
71
  }
72 73 74
}

sub object_before_set {
75 76 77 78 79 80 81
  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;
  }
82 83 84
}

sub object_end_of_set {
85 86 87 88 89 90 91 92
  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});
93
    }
94
  }
95 96 97
}

sub object_end_of_set_all {
98 99
  my ($self, $args) = @_;
  my $object = $args->{'object'};
100

101 102 103 104
  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'});
  }
105 106 107
}

sub object_validators {
108 109 110 111 112 113 114 115 116 117 118
  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, @_) };
  }
119 120 121
}

sub _check_bug_resolution {
122 123 124 125 126 127 128 129 130 131 132 133 134
  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->(@_);
135 136 137
}

sub _check_comment_extra_data {
138 139 140 141 142 143 144 145
  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->(@_);
146 147 148
}

sub bug_end_of_update {
149 150 151 152 153 154 155
  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);
  }
156 157 158
}

sub _move_bug {
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
  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);
191 192 193
}

sub _user_is_mover {
194
  my $user = shift;
195

196 197
  my @movers = map { trim($_) } split(',', Bugzilla->params->{'movers'});
  return ($user->id and grep($_ eq $user->login, @movers)) ? 1 : 0;
198 199 200
}

__PACKAGE__->NAME;