Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 6fd89c557d
Fetching contributors…

Cannot retrieve contributors at this time

413 lines (332 sloc) 10.183 kb
#!/usr/bin/perl -w
#
# This script outputs all reminders that are due within the next e.g. two
# days and mails the result to the corresponding owners.
#
package RT::Importer;
#use lib ("/etc/request-tracker3.6", "/usr/lib/rt/",
# "/usr/local/share/request-tracker3.6/lib");
use lib (
"/etc/request-tracker3.6",
"/usr/share/request-tracker3.6/lib",
"/usr/local/share/request-tracker3.6/lib"
);
use RT::Interface::CLI qw(CleanEnv GetCurrentUser);
use RT::Attachment;
use RT::Ticket;
use RT::Transaction;
use RT::User;
use Getopt::Std;
use MIME::Base64;
use XML::Simple;
use strict;
use warnings;
my $cf;
my $rtname;
my $directory;
my %user_types = map { $_ => 1 } qw(
Owner
Creator
LastUpdatedBy
Requestor
Cc
AdminCc
AddWatcher
DelWatcher
Take
);
my %link_types = map { $_ => 1 } qw(
DependsOn
DependedOnBy
RefersTo
ReferredToBy
MemberOf
MergedInto
HasMember
);
# clean out all the nasties from the environment..
CleanEnv();
# load the config file..
RT::LoadConfig();
# connect to the database and get RT::SystemUser and RT::Nobody loaded..
RT::Init();
# reset the RT die signal handler, we don't need the extra info..
$SIG{__DIE__} = "";
$SIG{__WARN__} = "";
# drop setgid permissions, which is version 3.0 specific
eval { RT::DropSetGIDPermissions() };
# Keep track of what has been converted.
my %E;
$E{Users} = {
1 => $RT::SystemUser->Id,
6 => $RT::Nobody->Id,
};
main() unless caller;
sub ConvertUser {
my ($user) = @_;
return $RT::Nobody->Id unless $user;
return $E{Users}{$user} if $E{Users}{$user};
my $userObj = new RT::User($RT::SystemUser);
$userObj->LoadOrCreateByEmail($user);
return $E{Users}{$user} = $userObj->Id || $RT::Nobody->Id;
}
sub ConvertQueue {
my ($queue) = @_;
return $E{Queues}{$queue} if $E{Queues}{$queue};
my $queueObj = new RT::Queue($RT::SystemUser);
$queueObj->Load($queue);
return $E{Queues}{$queue} = $queueObj || ConvertQueue('General');
}
sub _ConvertItem {
my $type = shift;
my $item = shift;
my %T = (
Tickets => {
import => \&import_ticket,
children => 'Transactions',
},
Transactions => {
import => \&import_transaction,
children => 'Attachments',
parent_id => 'ObjectId',
},
Attachments => {
import => \&import_attachment,
parent_id => 'TransactionId',
},
Links => { import => \&import_link, }
);
die "Unknown type [$type]!" unless $T{$type};
my $old_id = $item->{id};
warn "Converting $type #$old_id\n";
my ($new_id, $obj) = $E{$type}{$old_id} || $T{$type}{import}( $item, @_ );
if ($new_id) {
$E{$type}{$old_id} = $new_id;
print " Created\n";
}
else {
# Get rid of the old id to try to create with a new id
delete $item->{id};
($new_id, $obj) = $T{$type}{import}( $item, @_ );
if ($new_id) {
$E{$type}{$old_id} = $new_id;
print " Created as #$new_id\n";
}
}
unless ( $E{$type}{$old_id} ) {
print STDERR "Failed to create $type $old_id!!!\n";
return;
}
my $child_type = $T{$type}{children};
if ( $child_type and $item->{$child_type} ) {
my $parent_id = $T{$child_type}{parent_id};
foreach my $child_id (
sort { $a <=> $b }
keys %{ $item->{$child_type} }
)
{
my $child = $item->{$child_type}->{$child_id};
$child->{$parent_id} = $new_id if $parent_id;
_ConvertItem( $child_type, $child, $new_id );
}
}
return $new_id unless $obj;
foreach my $key (qw( LastUpdatedBy LastUpdated )) {
my $value = $item->{$key} or next;
$value = ConvertUser($value) if $key eq 'LastUpdatedBy';
# Annoying to dig into the guts this far!
$obj->__Set( Field => $key, Value => $value );
}
return $new_id;
}
sub ConvertTicket { _ConvertItem( 'Tickets', @_ ) }
sub ConvertTransaction { _ConvertItem( 'Transactions', @_ ) }
sub ConvertAttachment { _ConvertItem( 'Attachments', @_ ) }
sub ConvertLink { _ConvertItem( 'Links', @_ ) }
sub _pick_apart {
my ($item) = @_;
my %i;
foreach my $key ( keys %{$item} ) {
my $value = $item->{$key};
next unless $value;
$key = 'Requestor' if $key eq 'Requestors';
if ( $link_types{$key} ) {
# have to process these after all the tickets are created
queue_links($value);
next;
}
elsif ( ref $value ) {
next;
}
elsif ( $key eq 'Queue' ) {
$value = ConvertQueue($value);
}
elsif ( $user_types{$key} ) {
$value = [ grep {$_} map { ConvertUser($_) } split /\s*,\s*/,
$value ];
next unless @{$value};
if ( $key eq 'Owner'
or $key eq 'Creator'
or $key eq 'LastUpdatedBy'
or $key eq 'Take' )
{
$value = $value->[0];
}
}
$i{$key} = $value;
}
return %i;
}
sub import_ticket {
my ($ticket) = @_;
my %t = _pick_apart($ticket);
my $eid = $t{EffectiveId};
$t{EffectiveId} = 0;
my $ticketObj = new RT::Ticket($RT::SystemUser);
my ( $newid, $msg ) = $ticketObj->Import(%t) or return;
print $msg and return unless $newid;
# My exporter didnt export merged tickets so we dont need to do this
# But it may be required and I just dont know about it.
#$ticketObj->SetEffectiveId(ConvertTicket($eid)) if ($eid != $ticket->{id});
$ticketObj->AddCustomFieldValue(
Field => $cf,
Value => "[$rtname #$t{id}]"
);
foreach my $custom_field ( @{ $ticket->{CustomFields} } ) {
$ticketObj->AddCustomFieldValue(
Field => $custom_field->{Name},
Value => $custom_field->{Value},
);
}
return $newid, $ticketObj;
}
sub import_transaction {
my ( $transaction, $ticket_id ) = @_;
my %t = _pick_apart( $transaction );
if ( $link_types{ $t{Type} } ) {
if ($ticket_id) { # If this is the first time through don't add
queue_link_txn($transaction);
return;
}
$t{OldValue} = $E{Tickets}{ $t{OldValue} };
$t{NewValue} = $E{Tickets}{ $t{NewValue} };
}
if ( $t{Type} eq 'Set' and $t{Field} eq 'Queue' ) {
$t{OldValue} = ConvertQueue( $t{OldValue} );
$t{NewValue} = ConvertQueue( $t{NewValue} );
}
if ( ( $t{Type} eq 'Set' and $user_types{ $t{Field} } )
or $user_types{ $t{Type} } )
{
$t{OldValue} = ConvertUser( $t{OldValue} );
$t{NewValue} = ConvertUser( $t{NewValue} );
}
if ( ( $t{Type} eq 'EmailRecord' ) ) {
$t{OldValue} = $E{Tickets}{ $t{OldValue} } if $t{OldValue};
$t{NewValue} = $E{Tickets}{ $t{NewValue} } if $t{NewValue};
}
$t{ActivateScrips} = 0;
my $transactionObj = new RT::Transaction($RT::SystemUser);
my ( $newid, $msg ) = $transactionObj->Create(%t);
unless ($newid) {
print $msg;
return;
}
foreach my $custom_field ( @{ $transaction->{CustomFields} } ) {
$transactionObj->AddCustomFieldValue(
Field => $custom_field->{Name},
Value => $custom_field->{Value},
);
}
return $newid, $transactionObj;
}
sub import_attachment {
my ($attachment) = @_;
my %a = _pick_apart( $attachment );
delete $a{Owner};
if ( $a{Parent} ) {
# I guess we just have to hope this exists
my $parent = $a{Parent};
$a{Parent} = $E{Attachments}{$parent};
}
if ( $a{Content} ) {
Encode::_utf8_off( $a{Content} );
$a{Content} = decode_base64( $a{Content} );
}
else { $a{Content} = '' }
my $attachObj = new RT::Attachment($RT::SystemUser);
my ( $newid, $msg ) = $attachObj->Import(%a);
print $msg and return unless $newid;
return $newid, $attachObj;
}
sub import_link {
my ($link) = @_;
my $base = $link->{Base};
$base =~ /([0-9]*)$/;
$base = $E{Tickets}{$1};
my $target = $link->{Target};
$target =~ /([0-9]*)$/;
$target = $E{Tickets}{$1};
return unless $base and $target;
my $linkObj = new RT::Link($RT::SystemUser);
my $newid = $linkObj->Create(
Base => $base,
Target => $target,
Type => $link->{Type}
);
return unless $newid;
return $newid, $linkObj;
}
{
my @link_transactions;
my @links;
sub queue_link_txn { push @link_transactions, @_ }
sub queue_links {
push @links, grep { ref $_ eq 'HASH' and $_->{id} } @_;
}
sub process_queued_links {
while ( my $txn = shift @link_transactions ) {
ConvertTransaction($txn);
}
while ( my $link = shift @links ) {
ConvertLink($link);
}
}
}
sub read_file {
my ($file) = @_;
return XMLin(
$file,
SuppressEmpty => 1,
GroupTags => {
Transactions => 'Transaction',
Attachments => 'Attachment',
CustomFields => 'CustomField',
},
ForceArray => [qw( Transaction Attachment CustomField )],
KeyAttr => { Transaction => '+id', Attachment => '+id' },
);
}
sub main {
my %opts;
getopts( 'c:r:d:h', \%opts );
$cf = $opts{c};
$rtname = $opts{r};
$directory = $opts{d};
unless ( !$opts{h} && $cf && $rtname && $directory ) {
print
"rt-ticket-importer -d <directory> -r <source RT name> -c <CustomfieldId>\n";
exit;
}
opendir my $dh, $directory or die $!;
my @files = map {"$directory/$_"}
sort grep { $_ =~ /Ticket_\d+\.xml$/i } readdir $dh;
closedir $dh;
foreach my $file (@files) {
warn "Converting $file\n";
my $ticket = read_file($file);
ConvertTicket($ticket);
}
process_queued_links();
}
1;
Jump to Line
Something went wrong with that request. Please try again.