summaryrefslogtreecommitdiffstats
path: root/importxml.pl
diff options
context:
space:
mode:
Diffstat (limited to 'importxml.pl')
-rwxr-xr-ximportxml.pl2028
1 files changed, 1032 insertions, 996 deletions
diff --git a/importxml.pl b/importxml.pl
index 23609f2b3..e815b638a 100755
--- a/importxml.pl
+++ b/importxml.pl
@@ -38,15 +38,19 @@ use warnings;
#####################################################################
use File::Basename qw(dirname);
+
# MTAs may call this script from any directory, but it should always
# run from this one so that it can find its modules.
BEGIN {
- require File::Basename;
- my $dir = $0; $dir =~ /(.*)/; $dir = $1; # trick taint
- chdir(File::Basename::dirname($dir));
+ require File::Basename;
+ my $dir = $0;
+ $dir =~ /(.*)/;
+ $dir = $1; # trick taint
+ chdir(File::Basename::dirname($dir));
}
use lib qw(. lib local/lib/perl5);
+
# Data dumber is used for debugging, I got tired of copying it back in
# and then removing it.
#use Data::Dumper;
@@ -75,19 +79,19 @@ use Getopt::Long;
use Pod::Usage;
use XML::Twig;
-my $debug = 0;
-my $mail = '';
+my $debug = 0;
+my $mail = '';
my $attach_path = '';
-my $help = 0;
+my $help = 0;
my ($default_product_name, $default_component_name);
my $result = GetOptions(
- "verbose|debug+" => \$debug,
- "mail|sendmail!" => \$mail,
- "attach_path=s" => \$attach_path,
- "help|?" => \$help,
- "product=s" => \$default_product_name,
- "component=s" => \$default_component_name,
+ "verbose|debug+" => \$debug,
+ "mail|sendmail!" => \$mail,
+ "attach_path=s" => \$attach_path,
+ "help|?" => \$help,
+ "product=s" => \$default_product_name,
+ "component=s" => \$default_component_name,
);
pod2usage(0) if $help;
@@ -100,11 +104,11 @@ our @logs;
our @attachments;
our $bugtotal;
my $xml;
-my $dbh = Bugzilla->dbh;
-my $params = Bugzilla->params;
+my $dbh = Bugzilla->dbh;
+my $params = Bugzilla->params;
my ($timestamp) = $dbh->selectrow_array("SELECT NOW()");
-$default_product_name = '' if !defined $default_product_name;
+$default_product_name = '' if !defined $default_product_name;
$default_component_name = '' if !defined $default_component_name;
###############################################################################
@@ -112,166 +116,168 @@ $default_component_name = '' if !defined $default_component_name;
###############################################################################
sub MailMessage {
- return unless ($mail);
- my $subject = shift;
- my $message = shift;
- my @recipients = @_;
- my $from = $params->{"mailfrom"};
- $from =~ s/@/\@/g;
-
- foreach my $to (@recipients){
- my $header = "To: $to\n";
- $header .= "From: Bugzilla <$from>\n";
- $header .= "Subject: $subject\n\n";
- my $sendmessage = $header . $message . "\n";
- MessageToMTA($sendmessage);
- }
+ return unless ($mail);
+ my $subject = shift;
+ my $message = shift;
+ my @recipients = @_;
+ my $from = $params->{"mailfrom"};
+ $from =~ s/@/\@/g;
+
+ foreach my $to (@recipients) {
+ my $header = "To: $to\n";
+ $header .= "From: Bugzilla <$from>\n";
+ $header .= "Subject: $subject\n\n";
+ my $sendmessage = $header . $message . "\n";
+ MessageToMTA($sendmessage);
+ }
}
sub Debug {
- return unless ($debug);
- my ( $message, $level ) = (@_);
- print STDERR "OK: $message \n" if ( $level == OK_LEVEL );
- print STDERR "ERR: $message \n" if ( $level == ERR_LEVEL );
- print STDERR "$message\n"
- if ( ( $debug == $level ) && ( $level == DEBUG_LEVEL ) );
+ return unless ($debug);
+ my ($message, $level) = (@_);
+ print STDERR "OK: $message \n" if ($level == OK_LEVEL);
+ print STDERR "ERR: $message \n" if ($level == ERR_LEVEL);
+ print STDERR "$message\n" if (($debug == $level) && ($level == DEBUG_LEVEL));
}
sub Error {
- my ( $reason, $errtype, $exporter ) = @_;
- my $subject = "Bug import error: $reason";
- my $message = "Cannot import these bugs because $reason ";
- $message .= "\n\nPlease re-open the original bug.\n" if ($errtype);
- $message .= "For more info, contact " . $params->{"maintainer"} . ".\n";
- my @to = ( $params->{"maintainer"}, $exporter);
- Debug( $message, ERR_LEVEL );
- MailMessage( $subject, $message, @to );
- exit;
+ my ($reason, $errtype, $exporter) = @_;
+ my $subject = "Bug import error: $reason";
+ my $message = "Cannot import these bugs because $reason ";
+ $message .= "\n\nPlease re-open the original bug.\n" if ($errtype);
+ $message .= "For more info, contact " . $params->{"maintainer"} . ".\n";
+ my @to = ($params->{"maintainer"}, $exporter);
+ Debug($message, ERR_LEVEL);
+ MailMessage($subject, $message, @to);
+ exit;
}
# This subroutine handles flags for process_bug. It is generic in that
# it can handle both attachment flags and bug flags.
sub flag_handler {
- my (
- $name, $status, $setter_login,
- $requestee_login, $exporterid, $bugid,
- $componentid, $productid, $attachid
- )
- = @_;
-
- my $type = ($attachid) ? "attachment" : "bug";
- my $err = '';
- my $setter = new Bugzilla::User({ name => $setter_login });
- my $requestee;
- my $requestee_id;
-
- unless ($setter) {
- $err = "Invalid setter $setter_login on $type flag $name\n";
- $err .= " Dropping flag $name\n";
- return $err;
+ my (
+ $name, $status, $setter_login,
+ $requestee_login, $exporterid, $bugid,
+ $componentid, $productid, $attachid
+ ) = @_;
+
+ my $type = ($attachid) ? "attachment" : "bug";
+ my $err = '';
+ my $setter = new Bugzilla::User({name => $setter_login});
+ my $requestee;
+ my $requestee_id;
+
+ unless ($setter) {
+ $err = "Invalid setter $setter_login on $type flag $name\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
+ }
+ if (!$setter->can_see_bug($bugid)) {
+ $err .= "Setter is not a member of bug group\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
+ }
+ my $setter_id = $setter->id;
+ if (defined($requestee_login)) {
+ $requestee = new Bugzilla::User({name => $requestee_login});
+ if ($requestee) {
+ if (!$requestee->can_see_bug($bugid)) {
+ $err .= "Requestee is not a member of bug group\n";
+ $err .= " Requesting from the wind\n";
+ }
+ else {
+ $requestee_id = $requestee->id;
+ }
}
- if ( !$setter->can_see_bug($bugid) ) {
- $err .= "Setter is not a member of bug group\n";
- $err .= " Dropping flag $name\n";
- return $err;
+ else {
+ $err = "Invalid requestee $requestee_login on $type flag $name\n";
+ $err .= " Requesting from the wind.\n";
}
- my $setter_id = $setter->id;
- if ( defined($requestee_login) ) {
- $requestee = new Bugzilla::User({ name => $requestee_login });
- if ( $requestee ) {
- if ( !$requestee->can_see_bug($bugid) ) {
- $err .= "Requestee is not a member of bug group\n";
- $err .= " Requesting from the wind\n";
- }
- else{
- $requestee_id = $requestee->id;
- }
- }
- else {
- $err = "Invalid requestee $requestee_login on $type flag $name\n";
- $err .= " Requesting from the wind.\n";
- }
+ }
+ my $flag_types;
+
+ # If this is an attachment flag we need to do some dirty work to look
+ # up the flagtype ID
+ if ($attachid) {
+ $flag_types = Bugzilla::FlagType::match({
+ 'target_type' => 'attachment',
+ 'product_id' => $productid,
+ 'component_id' => $componentid
+ });
+ }
+ else {
+ my $bug = new Bugzilla::Bug($bugid);
+ $flag_types = $bug->flag_types;
+ }
+ unless ($flag_types) {
+ $err = "No flag types defined for this bug\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
+ }
+
+ # We need to see if the imported flag is in the list of known flags
+ # It is possible for two flags on the same bug have the same name
+ # If this is the case, we will only match the first one.
+ my $ftype;
+ foreach my $f (@{$flag_types}) {
+ if ($f->name eq $name) {
+ $ftype = $f;
+ last;
}
- my $flag_types;
-
- # If this is an attachment flag we need to do some dirty work to look
- # up the flagtype ID
- if ($attachid) {
- $flag_types = Bugzilla::FlagType::match(
- {
- 'target_type' => 'attachment',
- 'product_id' => $productid,
- 'component_id' => $componentid
- } );
- }
- else {
- my $bug = new Bugzilla::Bug($bugid);
- $flag_types = $bug->flag_types;
+ }
+
+ if ($ftype) { # We found the flag in the list
+ my $grant_group = $ftype->grant_group;
+ if ( ($status eq '+' || $status eq '-')
+ && $grant_group
+ && !$setter->in_group_id($grant_group->id))
+ {
+ $err = "Setter $setter_login on $type flag $name ";
+ $err .= "is not in the Grant Group\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
}
- unless ($flag_types){
- $err = "No flag types defined for this bug\n";
- $err .= " Dropping flag $name\n";
- return $err;
+ my $request_group = $ftype->request_group;
+ if ( $request_group
+ && $status eq '?'
+ && !$setter->in_group_id($request_group->id))
+ {
+ $err = "Setter $setter_login on $type flag $name ";
+ $err .= "is not in the Request Group\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
}
- # We need to see if the imported flag is in the list of known flags
- # It is possible for two flags on the same bug have the same name
- # If this is the case, we will only match the first one.
- my $ftype;
- foreach my $f ( @{$flag_types} ) {
- if ( $f->name eq $name) {
- $ftype = $f;
- last;
- }
+ # Take the first flag_type that matches
+ unless ($ftype->is_active) {
+ $err = "Flag $name is not active in this database\n";
+ $err .= " Dropping flag $name\n";
+ return $err;
}
- if ($ftype) { # We found the flag in the list
- my $grant_group = $ftype->grant_group;
- if (( $status eq '+' || $status eq '-' )
- && $grant_group && !$setter->in_group_id($grant_group->id)) {
- $err = "Setter $setter_login on $type flag $name ";
- $err .= "is not in the Grant Group\n";
- $err .= " Dropping flag $name\n";
- return $err;
- }
- my $request_group = $ftype->request_group;
- if ($request_group
- && $status eq '?' && !$setter->in_group_id($request_group->id)) {
- $err = "Setter $setter_login on $type flag $name ";
- $err .= "is not in the Request Group\n";
- $err .= " Dropping flag $name\n";
- return $err;
- }
-
- # Take the first flag_type that matches
- unless ($ftype->is_active) {
- $err = "Flag $name is not active in this database\n";
- $err .= " Dropping flag $name\n";
- return $err;
- }
-
- $dbh->do("INSERT INTO flags
+ $dbh->do(
+ "INSERT INTO flags
(type_id, status, bug_id, attach_id, creation_date,
setter_id, requestee_id)
VALUES (?, ?, ?, ?, ?, ?, ?)", undef,
- ($ftype->id, $status, $bugid, $attachid, $timestamp,
- $setter_id, $requestee_id));
- }
- else {
- $err = "Dropping unknown $type flag: $name\n";
- return $err;
- }
+ ($ftype->id, $status, $bugid, $attachid, $timestamp, $setter_id, $requestee_id)
+ );
+ }
+ else {
+ $err = "Dropping unknown $type flag: $name\n";
return $err;
+ }
+ return $err;
}
# Converts and returns the input data as an array.
sub _to_array {
- my $value = shift;
+ my $value = shift;
- $value = [$value] if !ref($value);
- return @$value;
+ $value = [$value] if !ref($value);
+ return @$value;
}
###############################################################################
@@ -289,25 +295,26 @@ sub _to_array {
# bugs are being moved from
#
sub init() {
- my ( $twig, $bugzilla ) = @_;
- my $root = $twig->root;
- my $maintainer = $root->{'att'}->{'maintainer'};
- my $exporter = $root->{'att'}->{'exporter'};
- my $urlbase = $root->{'att'}->{'urlbase'};
- my $xmlversion = $root->{'att'}->{'version'};
-
- if ($xmlversion ne BUGZILLA_VERSION) {
- my $log = "Possible version conflict!\n";
- $log .= " XML was exported from Bugzilla version $xmlversion\n";
- $log .= " But this installation uses ";
- $log .= BUGZILLA_VERSION . "\n";
- Debug($log, OK_LEVEL);
- push(@logs, $log);
- }
- Error( "no maintainer", "REOPEN", $exporter ) unless ($maintainer);
- Error( "no exporter", "REOPEN", $exporter ) unless ($exporter);
- Error( "invalid exporter: $exporter", "REOPEN", $exporter ) if ( !login_to_id($exporter) );
- Error( "no urlbase set", "REOPEN", $exporter ) unless ($urlbase);
+ my ($twig, $bugzilla) = @_;
+ my $root = $twig->root;
+ my $maintainer = $root->{'att'}->{'maintainer'};
+ my $exporter = $root->{'att'}->{'exporter'};
+ my $urlbase = $root->{'att'}->{'urlbase'};
+ my $xmlversion = $root->{'att'}->{'version'};
+
+ if ($xmlversion ne BUGZILLA_VERSION) {
+ my $log = "Possible version conflict!\n";
+ $log .= " XML was exported from Bugzilla version $xmlversion\n";
+ $log .= " But this installation uses ";
+ $log .= BUGZILLA_VERSION . "\n";
+ Debug($log, OK_LEVEL);
+ push(@logs, $log);
+ }
+ Error("no maintainer", "REOPEN", $exporter) unless ($maintainer);
+ Error("no exporter", "REOPEN", $exporter) unless ($exporter);
+ Error("invalid exporter: $exporter", "REOPEN", $exporter)
+ if (!login_to_id($exporter));
+ Error("no urlbase set", "REOPEN", $exporter) unless ($urlbase);
}
@@ -326,69 +333,74 @@ sub init() {
# The submitter_id gets filled in with $exporterid.
sub process_attachment() {
- my ( $twig, $attach ) = @_;
- Debug( "Parsing attachments", DEBUG_LEVEL );
- my %attachment;
-
- $attachment{'date'} =
- format_time( $attach->field('date'), "%Y-%m-%d %R" ) || $timestamp;
- $attachment{'desc'} = $attach->field('desc');
- $attachment{'ctype'} = $attach->field('type') || "unknown/unknown";
- $attachment{'attachid'} = $attach->field('attachid');
- $attachment{'ispatch'} = $attach->{'att'}->{'ispatch'} || 0;
- $attachment{'isobsolete'} = $attach->{'att'}->{'isobsolete'} || 0;
- $attachment{'isprivate'} = $attach->{'att'}->{'isprivate'} || 0;
- $attachment{'filename'} = $attach->field('filename') || "file";
- $attachment{'attacher'} = $attach->field('attacher');
- # Attachment data is not exported in versions 2.20 and older.
- if (defined $attach->first_child('data') &&
- defined $attach->first_child('data')->{'att'}->{'encoding'}) {
- my $encoding = $attach->first_child('data')->{'att'}->{'encoding'};
- if ($encoding =~ /base64/) {
- # decode the base64
- my $data = $attach->field('data');
- my $output = decode_base64($data);
- $attachment{'data'} = $output;
- }
- elsif ($encoding =~ /filename/) {
- # read the attachment file
- Error("attach_path is required", undef) unless ($attach_path);
-
- my $filename = $attach->field('data');
- # Remove any leading path data from the filename
- $filename =~ s/(.*\/|.*\\)//gs;
-
- my $attach_filename = $attach_path . "/" . $filename;
- open(ATTACH_FH, "<", $attach_filename) or
- Error("cannot open $attach_filename", undef);
- $attachment{'data'} = do { local $/; <ATTACH_FH> };
- close ATTACH_FH;
- }
- }
- else {
- $attachment{'data'} = $attach->field('data');
+ my ($twig, $attach) = @_;
+ Debug("Parsing attachments", DEBUG_LEVEL);
+ my %attachment;
+
+ $attachment{'date'}
+ = format_time($attach->field('date'), "%Y-%m-%d %R") || $timestamp;
+ $attachment{'desc'} = $attach->field('desc');
+ $attachment{'ctype'} = $attach->field('type') || "unknown/unknown";
+ $attachment{'attachid'} = $attach->field('attachid');
+ $attachment{'ispatch'} = $attach->{'att'}->{'ispatch'} || 0;
+ $attachment{'isobsolete'} = $attach->{'att'}->{'isobsolete'} || 0;
+ $attachment{'isprivate'} = $attach->{'att'}->{'isprivate'} || 0;
+ $attachment{'filename'} = $attach->field('filename') || "file";
+ $attachment{'attacher'} = $attach->field('attacher');
+
+ # Attachment data is not exported in versions 2.20 and older.
+ if ( defined $attach->first_child('data')
+ && defined $attach->first_child('data')->{'att'}->{'encoding'})
+ {
+ my $encoding = $attach->first_child('data')->{'att'}->{'encoding'};
+ if ($encoding =~ /base64/) {
+
+ # decode the base64
+ my $data = $attach->field('data');
+ my $output = decode_base64($data);
+ $attachment{'data'} = $output;
}
+ elsif ($encoding =~ /filename/) {
- # attachment flags
- my @aflags;
- foreach my $aflag ( $attach->children('flag') ) {
- my %aflag;
- $aflag{'name'} = $aflag->{'att'}->{'name'};
- $aflag{'status'} = $aflag->{'att'}->{'status'};
- $aflag{'setter'} = $aflag->{'att'}->{'setter'};
- $aflag{'requestee'} = $aflag->{'att'}->{'requestee'};
- push @aflags, \%aflag;
- }
- $attachment{'flags'} = \@aflags if (@aflags);
+ # read the attachment file
+ Error("attach_path is required", undef) unless ($attach_path);
- # free up the memory for use by the rest of the script
- $attach->delete;
- if ($attachment{'attachid'}) {
- push @attachments, \%attachment;
- }
- else {
- push @attachments, "err";
+ my $filename = $attach->field('data');
+
+ # Remove any leading path data from the filename
+ $filename =~ s/(.*\/|.*\\)//gs;
+
+ my $attach_filename = $attach_path . "/" . $filename;
+ open(ATTACH_FH, "<", $attach_filename)
+ or Error("cannot open $attach_filename", undef);
+ $attachment{'data'} = do { local $/; <ATTACH_FH> };
+ close ATTACH_FH;
}
+ }
+ else {
+ $attachment{'data'} = $attach->field('data');
+ }
+
+ # attachment flags
+ my @aflags;
+ foreach my $aflag ($attach->children('flag')) {
+ my %aflag;
+ $aflag{'name'} = $aflag->{'att'}->{'name'};
+ $aflag{'status'} = $aflag->{'att'}->{'status'};
+ $aflag{'setter'} = $aflag->{'att'}->{'setter'};
+ $aflag{'requestee'} = $aflag->{'att'}->{'requestee'};
+ push @aflags, \%aflag;
+ }
+ $attachment{'flags'} = \@aflags if (@aflags);
+
+ # free up the memory for use by the rest of the script
+ $attach->delete;
+ if ($attachment{'attachid'}) {
+ push @attachments, \%attachment;
+ }
+ else {
+ push @attachments, "err";
+ }
}
# This subroutine will be called once for each <bug> in the xml file.
@@ -400,836 +412,862 @@ sub process_attachment() {
# purged from memory to free it up for later bugs.
sub process_bug {
- my ( $twig, $bug ) = @_;
- my $root = $twig->root;
- my $maintainer = $root->{'att'}->{'maintainer'};
- my $exporter_login = $root->{'att'}->{'exporter'};
- my $exporter = new Bugzilla::User({ name => $exporter_login });
- my $urlbase = $root->{'att'}->{'urlbase'};
-
- # We will store output information in this variable.
- my $log = "";
- if ( defined $bug->{'att'}->{'error'} ) {
- $log .= "\nError in bug " . $bug->field('bug_id') . "\@$urlbase: ";
- $log .= $bug->{'att'}->{'error'} . "\n";
- if ( $bug->{'att'}->{'error'} =~ /NotFound/ ) {
- $log .= "$exporter_login tried to move bug " . $bug->field('bug_id');
- $log .= " here, but $urlbase reports that this bug";
- $log .= " does not exist.\n";
- }
- elsif ( $bug->{'att'}->{'error'} =~ /NotPermitted/ ) {
- $log .= "$exporter_login tried to move bug " . $bug->field('bug_id');
- $log .= " here, but $urlbase reports that $exporter_login does ";
- $log .= " not have access to that bug.\n";
- }
- return;
+ my ($twig, $bug) = @_;
+ my $root = $twig->root;
+ my $maintainer = $root->{'att'}->{'maintainer'};
+ my $exporter_login = $root->{'att'}->{'exporter'};
+ my $exporter = new Bugzilla::User({name => $exporter_login});
+ my $urlbase = $root->{'att'}->{'urlbase'};
+
+ # We will store output information in this variable.
+ my $log = "";
+ if (defined $bug->{'att'}->{'error'}) {
+ $log .= "\nError in bug " . $bug->field('bug_id') . "\@$urlbase: ";
+ $log .= $bug->{'att'}->{'error'} . "\n";
+ if ($bug->{'att'}->{'error'} =~ /NotFound/) {
+ $log .= "$exporter_login tried to move bug " . $bug->field('bug_id');
+ $log .= " here, but $urlbase reports that this bug";
+ $log .= " does not exist.\n";
}
- $bugtotal++;
-
- # This list contains all other bug fields that we want to process.
- # If it is not in this list it will not be included.
- my %all_fields;
- foreach my $field (
- qw(long_desc attachment flag group), Bugzilla::Bug::fields() )
- {
- $all_fields{$field} = 1;
+ elsif ($bug->{'att'}->{'error'} =~ /NotPermitted/) {
+ $log .= "$exporter_login tried to move bug " . $bug->field('bug_id');
+ $log .= " here, but $urlbase reports that $exporter_login does ";
+ $log .= " not have access to that bug.\n";
}
-
- my %bug_fields;
- my $err = "";
-
- # Loop through all the xml tags inside a <bug> and compare them to the
- # lists of fields. If they match throw them into the hash. Otherwise
- # append it to the log, which will go into the comments when we are done.
- foreach my $bugchild ( $bug->children() ) {
- Debug( "Parsing field: " . $bugchild->name, DEBUG_LEVEL );
-
- # Skip the token if one is included. We don't want it included in
- # the comments, and it is not used by the importer.
- next if $bugchild->name eq 'token';
-
- if ( defined $all_fields{ $bugchild->name } ) {
- my @values = $bug->children_text($bugchild->name);
- if (scalar @values > 1) {
- $bug_fields{$bugchild->name} = \@values;
- }
- else {
- $bug_fields{$bugchild->name} = $values[0];
- }
- }
- else {
- $err .= "Unknown bug field \"" . $bugchild->name . "\"";
- $err .= " encountered while moving bug\n";
- $err .= " <" . $bugchild->name . ">";
- if ( $bugchild->children_count > 1 ) {
- $err .= "\n";
- foreach my $subchild ( $bugchild->children() ) {
- $err .= " <" . $subchild->name . ">";
- $err .= $subchild->field;
- $err .= "</" . $subchild->name . ">\n";
- }
- }
- else {
- $err .= $bugchild->field;
- }
- $err .= "</" . $bugchild->name . ">\n";
- }
+ return;
+ }
+ $bugtotal++;
+
+ # This list contains all other bug fields that we want to process.
+ # If it is not in this list it will not be included.
+ my %all_fields;
+ foreach my $field (qw(long_desc attachment flag group), Bugzilla::Bug::fields())
+ {
+ $all_fields{$field} = 1;
+ }
+
+ my %bug_fields;
+ my $err = "";
+
+ # Loop through all the xml tags inside a <bug> and compare them to the
+ # lists of fields. If they match throw them into the hash. Otherwise
+ # append it to the log, which will go into the comments when we are done.
+ foreach my $bugchild ($bug->children()) {
+ Debug("Parsing field: " . $bugchild->name, DEBUG_LEVEL);
+
+ # Skip the token if one is included. We don't want it included in
+ # the comments, and it is not used by the importer.
+ next if $bugchild->name eq 'token';
+
+ if (defined $all_fields{$bugchild->name}) {
+ my @values = $bug->children_text($bugchild->name);
+ if (scalar @values > 1) {
+ $bug_fields{$bugchild->name} = \@values;
+ }
+ else {
+ $bug_fields{$bugchild->name} = $values[0];
+ }
}
-
- # Parse long descriptions
- my @long_descs;
- foreach my $comment ( $bug->children('long_desc') ) {
- Debug( "Parsing Long Description", DEBUG_LEVEL );
- my %long_desc = ( who => $comment->field('who'),
- bug_when => format_time($comment->field('bug_when'), '%Y-%m-%d %T'),
- isprivate => $comment->{'att'}->{'isprivate'} || 0 );
-
- # If the exporter is not in the insidergroup, keep the comment public.
- $long_desc{isprivate} = 0 unless $exporter->is_insider;
-
- my $data = $comment->field('thetext');
- if ( defined $comment->first_child('thetext')->{'att'}->{'encoding'}
- && $comment->first_child('thetext')->{'att'}->{'encoding'} =~
- /base64/ )
- {
- $data = decode_base64($data);
- }
-
- # For backwards-compatibility with Bugzillas before 3.6:
- #
- # If we leave the attachment ID in the comment it will be made a link
- # to the wrong attachment. Since the new attachment ID is unknown yet
- # let's strip it out for now. We will make a comment with the right ID
- # later
- $data =~ s/Created an attachment \(id=\d+\)/Created an attachment/g;
-
- # Same goes for bug #'s Since we don't know if the referenced bug
- # is also being moved, lets make sure they know it means a different
- # bugzilla.
- my $url = $urlbase . "show_bug.cgi?id=";
- $data =~ s/([Bb]ugs?\s*\#?\s*(\d+))/$url$2/g;
-
- # Keep the original commenter if possible, else we will fall back
- # to the exporter account.
- $long_desc{whoid} = login_to_id($long_desc{who});
-
- if (!$long_desc{whoid}) {
- $data = "The original author of this comment is $long_desc{who}.\n\n" . $data;
+ else {
+ $err .= "Unknown bug field \"" . $bugchild->name . "\"";
+ $err .= " encountered while moving bug\n";
+ $err .= " <" . $bugchild->name . ">";
+ if ($bugchild->children_count > 1) {
+ $err .= "\n";
+ foreach my $subchild ($bugchild->children()) {
+ $err .= " <" . $subchild->name . ">";
+ $err .= $subchild->field;
+ $err .= "</" . $subchild->name . ">\n";
}
-
- $long_desc{'thetext'} = $data;
- push @long_descs, \%long_desc;
+ }
+ else {
+ $err .= $bugchild->field;
+ }
+ $err .= "</" . $bugchild->name . ">\n";
}
-
- my @sorted_descs = sort { $a->{'bug_when'} cmp $b->{'bug_when'} } @long_descs;
-
- my $comments = "\n\n--- Bug imported by $exporter_login ";
- $comments .= format_time(scalar localtime(time()), '%Y-%m-%d %R %Z') . " ";
- $comments .= " ---\n\n";
- $comments .= "This bug was previously known as _bug_ $bug_fields{'bug_id'} at ";
- $comments .= $urlbase . "show_bug.cgi?id=" . $bug_fields{'bug_id'} . "\n";
- if ( defined $bug_fields{'dependson'} ) {
- $comments .= "This bug depended on bug(s) " .
- join(' ', _to_array($bug_fields{'dependson'})) . ".\n";
+ }
+
+ # Parse long descriptions
+ my @long_descs;
+ foreach my $comment ($bug->children('long_desc')) {
+ Debug("Parsing Long Description", DEBUG_LEVEL);
+ my %long_desc = (
+ who => $comment->field('who'),
+ bug_when => format_time($comment->field('bug_when'), '%Y-%m-%d %T'),
+ isprivate => $comment->{'att'}->{'isprivate'} || 0
+ );
+
+ # If the exporter is not in the insidergroup, keep the comment public.
+ $long_desc{isprivate} = 0 unless $exporter->is_insider;
+
+ my $data = $comment->field('thetext');
+ if (defined $comment->first_child('thetext')->{'att'}->{'encoding'}
+ && $comment->first_child('thetext')->{'att'}->{'encoding'} =~ /base64/)
+ {
+ $data = decode_base64($data);
}
- if ( defined $bug_fields{'blocked'} ) {
- $comments .= "This bug blocked bug(s) " .
- join(' ', _to_array($bug_fields{'blocked'})) . ".\n";
+
+ # For backwards-compatibility with Bugzillas before 3.6:
+ #
+ # If we leave the attachment ID in the comment it will be made a link
+ # to the wrong attachment. Since the new attachment ID is unknown yet
+ # let's strip it out for now. We will make a comment with the right ID
+ # later
+ $data =~ s/Created an attachment \(id=\d+\)/Created an attachment/g;
+
+ # Same goes for bug #'s Since we don't know if the referenced bug
+ # is also being moved, lets make sure they know it means a different
+ # bugzilla.
+ my $url = $urlbase . "show_bug.cgi?id=";
+ $data =~ s/([Bb]ugs?\s*\#?\s*(\d+))/$url$2/g;
+
+ # Keep the original commenter if possible, else we will fall back
+ # to the exporter account.
+ $long_desc{whoid} = login_to_id($long_desc{who});
+
+ if (!$long_desc{whoid}) {
+ $data = "The original author of this comment is $long_desc{who}.\n\n" . $data;
}
- # Now we process each of the fields in turn and make sure they contain
- # valid data. We will create two parallel arrays, one for the query
- # and one for the values. For every field we need to push an entry onto
- # each array.
- my @query = ();
- my @values = ();
-
- # Each of these fields we will check for newlines and shove onto the array
- foreach my $field (qw(status_whiteboard bug_file_loc short_desc)) {
- if ($bug_fields{$field}) {
- $bug_fields{$field} = clean_text( $bug_fields{$field} );
- push( @query, $field );
- push( @values, $bug_fields{$field} );
- }
+ $long_desc{'thetext'} = $data;
+ push @long_descs, \%long_desc;
+ }
+
+ my @sorted_descs = sort { $a->{'bug_when'} cmp $b->{'bug_when'} } @long_descs;
+
+ my $comments = "\n\n--- Bug imported by $exporter_login ";
+ $comments .= format_time(scalar localtime(time()), '%Y-%m-%d %R %Z') . " ";
+ $comments .= " ---\n\n";
+ $comments .= "This bug was previously known as _bug_ $bug_fields{'bug_id'} at ";
+ $comments .= $urlbase . "show_bug.cgi?id=" . $bug_fields{'bug_id'} . "\n";
+ if (defined $bug_fields{'dependson'}) {
+ $comments .= "This bug depended on bug(s) "
+ . join(' ', _to_array($bug_fields{'dependson'})) . ".\n";
+ }
+ if (defined $bug_fields{'blocked'}) {
+ $comments .= "This bug blocked bug(s) "
+ . join(' ', _to_array($bug_fields{'blocked'})) . ".\n";
+ }
+
+ # Now we process each of the fields in turn and make sure they contain
+ # valid data. We will create two parallel arrays, one for the query
+ # and one for the values. For every field we need to push an entry onto
+ # each array.
+ my @query = ();
+ my @values = ();
+
+ # Each of these fields we will check for newlines and shove onto the array
+ foreach my $field (qw(status_whiteboard bug_file_loc short_desc)) {
+ if ($bug_fields{$field}) {
+ $bug_fields{$field} = clean_text($bug_fields{$field});
+ push(@query, $field);
+ push(@values, $bug_fields{$field});
}
+ }
- # Alias
- if ( $bug_fields{'alias'} ) {
- my ($alias) = $dbh->selectrow_array("SELECT COUNT(*) FROM bugs
+ # Alias
+ if ($bug_fields{'alias'}) {
+ my ($alias) = $dbh->selectrow_array(
+ "SELECT COUNT(*) FROM bugs
WHERE alias = ?", undef,
- $bug_fields{'alias'} );
- if ($alias) {
- $err .= "Dropping conflicting bug alias ";
- $err .= $bug_fields{'alias'} . "\n";
- }
- else {
- $alias = $bug_fields{'alias'};
- push @query, 'alias';
- push @values, $alias;
- }
+ $bug_fields{'alias'}
+ );
+ if ($alias) {
+ $err .= "Dropping conflicting bug alias ";
+ $err .= $bug_fields{'alias'} . "\n";
}
-
- # Timestamps
- push( @query, "creation_ts" );
- push( @values,
- format_time( $bug_fields{'creation_ts'}, "%Y-%m-%d %T" )
- || $timestamp );
-
- push( @query, "delta_ts" );
- push( @values,
- format_time( $bug_fields{'delta_ts'}, "%Y-%m-%d %T" )
- || $timestamp );
-
- # Bug Access
- push( @query, "cclist_accessible" );
- push( @values, $bug_fields{'cclist_accessible'} ? 1 : 0 );
-
- push( @query, "reporter_accessible" );
- push( @values, $bug_fields{'reporter_accessible'} ? 1 : 0 );
-
- my $product = new Bugzilla::Product(
- { name => $bug_fields{'product'} || '' });
- if (!$product) {
- $err .= "Unknown Product " . $bug_fields{'product'} . "\n";
- $err .= " Using default product set at the command line.\n";
- $product = new Bugzilla::Product({ name => $default_product_name })
- or Error("an invalid default product was defined for the target"
- . " DB. " . $params->{"maintainer"} . " needs to specify "
- . "--product when calling importxml.pl", "REOPEN",
- $exporter);
+ else {
+ $alias = $bug_fields{'alias'};
+ push @query, 'alias';
+ push @values, $alias;
}
- my $component = new Bugzilla::Component({
- product => $product, name => $bug_fields{'component'} || '' });
+ }
+
+ # Timestamps
+ push(@query, "creation_ts");
+ push(@values,
+ format_time($bug_fields{'creation_ts'}, "%Y-%m-%d %T") || $timestamp);
+
+ push(@query, "delta_ts");
+ push(@values,
+ format_time($bug_fields{'delta_ts'}, "%Y-%m-%d %T") || $timestamp);
+
+ # Bug Access
+ push(@query, "cclist_accessible");
+ push(@values, $bug_fields{'cclist_accessible'} ? 1 : 0);
+
+ push(@query, "reporter_accessible");
+ push(@values, $bug_fields{'reporter_accessible'} ? 1 : 0);
+
+ my $product = new Bugzilla::Product({name => $bug_fields{'product'} || ''});
+ if (!$product) {
+ $err .= "Unknown Product " . $bug_fields{'product'} . "\n";
+ $err .= " Using default product set at the command line.\n";
+ $product = new Bugzilla::Product({name => $default_product_name})
+ or Error(
+ "an invalid default product was defined for the target" . " DB. "
+ . $params->{"maintainer"}
+ . " needs to specify "
+ . "--product when calling importxml.pl",
+ "REOPEN", $exporter
+ );
+ }
+ my $component
+ = new Bugzilla::Component({
+ product => $product, name => $bug_fields{'component'} || ''
+ });
+ if (!$component) {
+ $err .= "Unknown Component " . $bug_fields{'component'} . "\n";
+ $err .= " Using default product and component set ";
+ $err .= "at the command line.\n";
+
+ $product = new Bugzilla::Product({name => $default_product_name});
+ $component = new Bugzilla::Component(
+ {name => $default_component_name, product => $product});
if (!$component) {
- $err .= "Unknown Component " . $bug_fields{'component'} . "\n";
- $err .= " Using default product and component set ";
- $err .= "at the command line.\n";
-
- $product = new Bugzilla::Product({ name => $default_product_name });
- $component = new Bugzilla::Component({
- name => $default_component_name, product => $product });
- if (!$component) {
- Error("an invalid default component was defined for the target"
- . " DB. ". $params->{"maintainer"} . " needs to specify "
- . "--component when calling importxml.pl", "REOPEN",
- $exporter);
- }
+ Error(
+ "an invalid default component was defined for the target" . " DB. "
+ . $params->{"maintainer"}
+ . " needs to specify "
+ . "--component when calling importxml.pl",
+ "REOPEN", $exporter
+ );
}
+ }
+
+ my $prod_id = $product->id;
+ my $comp_id = $component->id;
+
+ push(@query, "product_id");
+ push(@values, $prod_id);
+ push(@query, "component_id");
+ push(@values, $comp_id);
+
+ # Since there is no default version for a product, we check that the one
+ # coming over is valid. If not we will use the first one in @versions
+ # and warn them.
+ my $version = new Bugzilla::Version(
+ {product => $product, name => $bug_fields{'version'}});
+
+ push(@query, "version");
+ if ($version) {
+ push(@values, $version->name);
+ }
+ else {
+ my @versions = @{$product->versions};
+ my $v = $versions[0];
+ push(@values, $v->name);
+ $err .= "Unknown version \"";
+ $err .= (defined $bug_fields{'version'}) ? $bug_fields{'version'} : "unknown";
+ $err .= " in product " . $product->name . ". \n";
+ $err .= " Setting version to \"" . $v->name . "\".\n";
+ }
+
+ # Milestone
+ if ($params->{"usetargetmilestone"}) {
+ my $milestone;
+ if (defined $bug_fields{'target_milestone'}
+ && $bug_fields{'target_milestone'} ne "")
+ {
- my $prod_id = $product->id;
- my $comp_id = $component->id;
-
- push( @query, "product_id" );
- push( @values, $prod_id );
- push( @query, "component_id" );
- push( @values, $comp_id );
-
- # Since there is no default version for a product, we check that the one
- # coming over is valid. If not we will use the first one in @versions
- # and warn them.
- my $version = new Bugzilla::Version(
- { product => $product, name => $bug_fields{'version'} });
-
- push( @query, "version" );
- if ($version) {
- push( @values, $version->name );
+ $milestone = new Bugzilla::Milestone(
+ {product => $product, name => $bug_fields{'target_milestone'}});
+ }
+ if ($milestone) {
+ push(@values, $milestone->name);
}
else {
- my @versions = @{ $product->versions };
- my $v = $versions[0];
- push( @values, $v->name );
- $err .= "Unknown version \"";
- $err .= ( defined $bug_fields{'version'} )
- ? $bug_fields{'version'}
- : "unknown";
- $err .= " in product " . $product->name . ". \n";
- $err .= " Setting version to \"" . $v->name . "\".\n";
+ push(@values, $product->default_milestone);
+ $err .= "Unknown milestone \"";
+ $err
+ .= (defined $bug_fields{'target_milestone'})
+ ? $bug_fields{'target_milestone'}
+ : "unknown";
+ $err .= " in product " . $product->name . ". \n";
+ $err .= " Setting to default milestone for this product, ";
+ $err .= "\"" . $product->default_milestone . "\".\n";
}
-
- # Milestone
- if ( $params->{"usetargetmilestone"} ) {
- my $milestone;
- if (defined $bug_fields{'target_milestone'}
- && $bug_fields{'target_milestone'} ne "") {
-
- $milestone = new Bugzilla::Milestone(
- { product => $product, name => $bug_fields{'target_milestone'} });
- }
- if ($milestone) {
- push( @values, $milestone->name );
- }
- else {
- push( @values, $product->default_milestone );
- $err .= "Unknown milestone \"";
- $err .= ( defined $bug_fields{'target_milestone'} )
- ? $bug_fields{'target_milestone'}
- : "unknown";
- $err .= " in product " . $product->name . ". \n";
- $err .= " Setting to default milestone for this product, ";
- $err .= "\"" . $product->default_milestone . "\".\n";
- }
- push( @query, "target_milestone" );
+ push(@query, "target_milestone");
+ }
+
+ # For priority, severity, opsys and platform we check that the one being
+ # imported is valid. If it is not we use the defaults set in the parameters.
+ if (
+ defined($bug_fields{'bug_severity'})
+ && check_field(
+ 'bug_severity', scalar $bug_fields{'bug_severity'},
+ undef, ERR_LEVEL
+ )
+ )
+ {
+ push(@values, $bug_fields{'bug_severity'});
+ }
+ else {
+ push(@values, $params->{'defaultseverity'});
+ $err .= "Unknown severity ";
+ $err
+ .= (defined $bug_fields{'bug_severity'})
+ ? $bug_fields{'bug_severity'}
+ : "unknown";
+ $err .= ". Setting to default severity \"";
+ $err .= $params->{'defaultseverity'} . "\".\n";
+ }
+ push(@query, "bug_severity");
+
+ if (defined($bug_fields{'priority'})
+ && check_field('priority', scalar $bug_fields{'priority'}, undef, ERR_LEVEL))
+ {
+ push(@values, $bug_fields{'priority'});
+ }
+ else {
+ push(@values, $params->{'defaultpriority'});
+ $err .= "Unknown priority ";
+ $err .= (defined $bug_fields{'priority'}) ? $bug_fields{'priority'} : "unknown";
+ $err .= ". Setting to default priority \"";
+ $err .= $params->{'defaultpriority'} . "\".\n";
+ }
+ push(@query, "priority");
+
+ if (
+ defined($bug_fields{'rep_platform'})
+ && check_field(
+ 'rep_platform', scalar $bug_fields{'rep_platform'},
+ undef, ERR_LEVEL
+ )
+ )
+ {
+ push(@values, $bug_fields{'rep_platform'});
+ }
+ else {
+ push(@values, $params->{'defaultplatform'});
+ $err .= "Unknown platform ";
+ $err
+ .= (defined $bug_fields{'rep_platform'})
+ ? $bug_fields{'rep_platform'}
+ : "unknown";
+ $err .= ". Setting to default platform \"";
+ $err .= $params->{'defaultplatform'} . "\".\n";
+ }
+ push(@query, "rep_platform");
+
+ if (defined($bug_fields{'op_sys'})
+ && check_field('op_sys', scalar $bug_fields{'op_sys'}, undef, ERR_LEVEL))
+ {
+ push(@values, $bug_fields{'op_sys'});
+ }
+ else {
+ push(@values, $params->{'defaultopsys'});
+ $err .= "Unknown operating system ";
+ $err .= (defined $bug_fields{'op_sys'}) ? $bug_fields{'op_sys'} : "unknown";
+ $err .= ". Setting to default OS \"" . $params->{'defaultopsys'} . "\".\n";
+ }
+ push(@query, "op_sys");
+
+ # Process time fields
+ if ($params->{"timetrackinggroup"}) {
+ my $date
+ = validate_date($bug_fields{'deadline'}) ? $bug_fields{'deadline'} : undef;
+ push(@values, $date);
+ push(@query, "deadline");
+ if (defined $bug_fields{'estimated_time'}) {
+ eval { Bugzilla::Object::_validate_time($bug_fields{'estimated_time'}, "e"); };
+ if (!$@) {
+ push(@values, $bug_fields{'estimated_time'});
+ push(@query, "estimated_time");
+ }
}
-
- # For priority, severity, opsys and platform we check that the one being
- # imported is valid. If it is not we use the defaults set in the parameters.
- if (defined( $bug_fields{'bug_severity'} )
- && check_field('bug_severity', scalar $bug_fields{'bug_severity'},
- undef, ERR_LEVEL) )
- {
- push( @values, $bug_fields{'bug_severity'} );
+ if (defined $bug_fields{'remaining_time'}) {
+ eval { Bugzilla::Object::_validate_time($bug_fields{'remaining_time'}, "r"); };
+ if (!$@) {
+ push(@values, $bug_fields{'remaining_time'});
+ push(@query, "remaining_time");
+ }
+ }
+ if (defined $bug_fields{'actual_time'}) {
+ eval { Bugzilla::Object::_validate_time($bug_fields{'actual_time'}, "a"); };
+ if ($@) {
+ $bug_fields{'actual_time'} = 0.0;
+ $err .= "Invalid Actual Time. Setting to 0.0\n";
+ }
}
else {
- push( @values, $params->{'defaultseverity'} );
- $err .= "Unknown severity ";
- $err .= ( defined $bug_fields{'bug_severity'} )
- ? $bug_fields{'bug_severity'}
- : "unknown";
- $err .= ". Setting to default severity \"";
- $err .= $params->{'defaultseverity'} . "\".\n";
+ $bug_fields{'actual_time'} = 0.0;
+ $err .= "Actual time not defined. Setting to 0.0\n";
}
- push( @query, "bug_severity" );
-
- if (defined( $bug_fields{'priority'} )
- && check_field('priority', scalar $bug_fields{'priority'},
- undef, ERR_LEVEL ) )
- {
- push( @values, $bug_fields{'priority'} );
+ }
+
+ # Reporter Assignee QA Contact
+ my $exporterid = $exporter->id;
+ my $reporterid = login_to_id($bug_fields{'reporter'})
+ if $bug_fields{'reporter'};
+ push(@query, "reporter");
+ if (($bug_fields{'reporter'}) && ($reporterid)) {
+ push(@values, $reporterid);
+ }
+ else {
+ push(@values, $exporterid);
+ $err .= "The original reporter of this bug does not have\n";
+ $err .= " an account here. Reassigning to the person who moved\n";
+ $err .= " it here: $exporter_login.\n";
+ if ($bug_fields{'reporter'}) {
+ $err .= " Previous reporter was $bug_fields{'reporter'}.\n";
}
else {
- push( @values, $params->{'defaultpriority'} );
- $err .= "Unknown priority ";
- $err .= ( defined $bug_fields{'priority'} )
- ? $bug_fields{'priority'}
- : "unknown";
- $err .= ". Setting to default priority \"";
- $err .= $params->{'defaultpriority'} . "\".\n";
+ $err .= " Previous reporter is unknown.\n";
}
- push( @query, "priority" );
-
- if (defined( $bug_fields{'rep_platform'} )
- && check_field('rep_platform', scalar $bug_fields{'rep_platform'},
- undef, ERR_LEVEL ) )
- {
- push( @values, $bug_fields{'rep_platform'} );
+ }
+
+ my $changed_owner = 0;
+ my $owner;
+ push(@query, "assigned_to");
+ if ( ($bug_fields{'assigned_to'})
+ && ($owner = login_to_id($bug_fields{'assigned_to'})))
+ {
+ push(@values, $owner);
+ }
+ else {
+ push(@values, $component->default_assignee->id);
+ $changed_owner = 1;
+ $err .= "The original assignee of this bug does not have\n";
+ $err .= " an account here. Reassigning to the default assignee\n";
+ $err .= " for the component, " . $component->default_assignee->login . ".\n";
+ if ($bug_fields{'assigned_to'}) {
+ $err .= " Previous assignee was $bug_fields{'assigned_to'}.\n";
}
else {
- push( @values, $params->{'defaultplatform'} );
- $err .= "Unknown platform ";
- $err .= ( defined $bug_fields{'rep_platform'} )
- ? $bug_fields{'rep_platform'}
- : "unknown";
- $err .=". Setting to default platform \"";
- $err .= $params->{'defaultplatform'} . "\".\n";
+ $err .= " Previous assignee is unknown.\n";
}
- push( @query, "rep_platform" );
+ }
- if (defined( $bug_fields{'op_sys'} )
- && check_field('op_sys', scalar $bug_fields{'op_sys'},
- undef, ERR_LEVEL ) )
+ if ($params->{"useqacontact"}) {
+ my $qa_contact;
+ push(@query, "qa_contact");
+ if ( (defined $bug_fields{'qa_contact'})
+ && ($qa_contact = login_to_id($bug_fields{'qa_contact'})))
{
- push( @values, $bug_fields{'op_sys'} );
+ push(@values, $qa_contact);
}
else {
- push( @values, $params->{'defaultopsys'} );
- $err .= "Unknown operating system ";
- $err .= ( defined $bug_fields{'op_sys'} )
- ? $bug_fields{'op_sys'}
- : "unknown";
- $err .= ". Setting to default OS \"" . $params->{'defaultopsys'} . "\".\n";
- }
- push( @query, "op_sys" );
-
- # Process time fields
- if ( $params->{"timetrackinggroup"} ) {
- my $date = validate_date( $bug_fields{'deadline'} ) ? $bug_fields{'deadline'} : undef;
- push( @values, $date );
- push( @query, "deadline" );
- if ( defined $bug_fields{'estimated_time'} ) {
- eval {
- Bugzilla::Object::_validate_time($bug_fields{'estimated_time'}, "e");
- };
- if (!$@){
- push( @values, $bug_fields{'estimated_time'} );
- push( @query, "estimated_time" );
- }
- }
- if ( defined $bug_fields{'remaining_time'} ) {
- eval {
- Bugzilla::Object::_validate_time($bug_fields{'remaining_time'}, "r");
- };
- if (!$@){
- push( @values, $bug_fields{'remaining_time'} );
- push( @query, "remaining_time" );
- }
- }
- if ( defined $bug_fields{'actual_time'} ) {
- eval {
- Bugzilla::Object::_validate_time($bug_fields{'actual_time'}, "a");
- };
- if ($@){
- $bug_fields{'actual_time'} = 0.0;
- $err .= "Invalid Actual Time. Setting to 0.0\n";
- }
- }
- else {
- $bug_fields{'actual_time'} = 0.0;
- $err .= "Actual time not defined. Setting to 0.0\n";
- }
+ push(@values, $component->default_qa_contact->id || undef);
+ if ($component->default_qa_contact->id) {
+ $err .= "Setting qa contact to the default for this product.\n";
+ $err .= " This bug either had no qa contact or an invalid one.\n";
+ }
}
-
- # Reporter Assignee QA Contact
- my $exporterid = $exporter->id;
- my $reporterid = login_to_id( $bug_fields{'reporter'} )
- if $bug_fields{'reporter'};
- push( @query, "reporter" );
- if ( ( $bug_fields{'reporter'} ) && ($reporterid) ) {
- push( @values, $reporterid );
+ }
+
+ # Status & Resolution
+ my $valid_res
+ = check_field('resolution', scalar $bug_fields{'resolution'}, undef,
+ ERR_LEVEL);
+ my $valid_status
+ = check_field('bug_status', scalar $bug_fields{'bug_status'}, undef,
+ ERR_LEVEL);
+ my $is_open = is_open_state($bug_fields{'bug_status'});
+ my $status = $bug_fields{'bug_status'} || undef;
+ my $resolution = $bug_fields{'resolution'} || undef;
+
+ # Check everconfirmed
+ my $everconfirmed;
+ if ($product->allows_unconfirmed) {
+ $everconfirmed = $bug_fields{'everconfirmed'} || 0;
+ }
+ else {
+ $everconfirmed = 1;
+ }
+ push(@query, "everconfirmed");
+ push(@values, $everconfirmed);
+
+ # Sanity check will complain about having bugs marked duplicate but no
+ # entry in the dup table. Since we can't tell the bug ID of bugs
+ # that might not yet be in the database we have no way of populating
+ # this table. Change the resolution instead.
+ if ($valid_res && ($bug_fields{'resolution'} eq "DUPLICATE")) {
+ $resolution = "INVALID";
+ $err .= "This bug was marked DUPLICATE in the database ";
+ $err .= "it was moved from.\n Changing resolution to \"INVALID\"\n";
+ }
+
+ # If there is at least 1 initial bug status different from UNCO, use it,
+ # else use the open bug status with the lowest sortkey (different from UNCO).
+ my @bug_statuses = @{Bugzilla::Status->can_change_to()};
+ @bug_statuses = grep { $_->name ne 'UNCONFIRMED' } @bug_statuses;
+
+ my $initial_status;
+ if (scalar(@bug_statuses)) {
+ $initial_status = $bug_statuses[0]->name;
+ }
+ else {
+ @bug_statuses = Bugzilla::Status->get_all();
+
+ # Exclude UNCO and inactive bug statuses.
+ @bug_statuses
+ = grep { $_->is_active && $_->name ne 'UNCONFIRMED' } @bug_statuses;
+ my @open_statuses = grep { $_->is_open } @bug_statuses;
+ if (scalar(@open_statuses)) {
+ $initial_status = $open_statuses[0]->name;
}
else {
- push( @values, $exporterid );
- $err .= "The original reporter of this bug does not have\n";
- $err .= " an account here. Reassigning to the person who moved\n";
- $err .= " it here: $exporter_login.\n";
- if ( $bug_fields{'reporter'} ) {
- $err .= " Previous reporter was $bug_fields{'reporter'}.\n";
+ # There is NO other open bug statuses outside UNCO???
+ Error("no open bug statuses available.");
+ }
+ }
+
+ if ($status) {
+ if ($valid_status) {
+ if ($is_open) {
+ if ($resolution) {
+ $err .= "Resolution set on an open status.\n";
+ $err .= " Dropping resolution $resolution\n";
+ $resolution = undef;
}
- else {
- $err .= " Previous reporter is unknown.\n";
+ if ($changed_owner) {
+ if ($everconfirmed) {
+ $status = $initial_status;
+ }
+ else {
+ $status = "UNCONFIRMED";
+ }
+ if ($status ne $bug_fields{'bug_status'}) {
+ $err .= "Bug reassigned, setting status to \"$status\".\n";
+ $err .= " Previous status was \"";
+ $err .= $bug_fields{'bug_status'} . "\".\n";
+ }
}
- }
-
- my $changed_owner = 0;
- my $owner;
- push( @query, "assigned_to" );
- if ( ( $bug_fields{'assigned_to'} )
- && ( $owner = login_to_id( $bug_fields{'assigned_to'} )) ) {
- push( @values, $owner );
- }
- else {
- push( @values, $component->default_assignee->id );
- $changed_owner = 1;
- $err .= "The original assignee of this bug does not have\n";
- $err .= " an account here. Reassigning to the default assignee\n";
- $err .= " for the component, ". $component->default_assignee->login .".\n";
- if ( $bug_fields{'assigned_to'} ) {
- $err .= " Previous assignee was $bug_fields{'assigned_to'}.\n";
+ if ($everconfirmed) {
+ if ($status eq "UNCONFIRMED") {
+ $err .= "Bug Status was UNCONFIRMED but everconfirmed was true\n";
+ $err .= " Setting status to $initial_status\n";
+ $status = $initial_status;
+ }
}
- else {
- $err .= " Previous assignee is unknown.\n";
+ else { # $everconfirmed is false
+ if ($status ne "UNCONFIRMED") {
+ $err .= "Bug Status was $status but everconfirmed was false\n";
+ $err .= " Setting status to UNCONFIRMED\n";
+ $status = "UNCONFIRMED";
+ }
}
- }
-
- if ( $params->{"useqacontact"} ) {
- my $qa_contact;
- push( @query, "qa_contact" );
- if ( ( defined $bug_fields{'qa_contact'})
- && ( $qa_contact = login_to_id( $bug_fields{'qa_contact'} ) ) ) {
- push( @values, $qa_contact );
+ }
+ else { # $is_open is false
+ if (!$resolution) {
+ $err .= "Missing Resolution. Setting status to ";
+ if ($everconfirmed) {
+ $status = $initial_status;
+ $err .= "$initial_status\n";
+ }
+ else {
+ $status = "UNCONFIRMED";
+ $err .= "UNCONFIRMED\n";
+ }
}
- else {
- push( @values, $component->default_qa_contact->id || undef );
- if ($component->default_qa_contact->id){
- $err .= "Setting qa contact to the default for this product.\n";
- $err .= " This bug either had no qa contact or an invalid one.\n";
- }
+ elsif (!$valid_res) {
+ $err .= "Unknown resolution \"$resolution\".\n";
+ $err .= " Setting resolution to INVALID\n";
+ $resolution = "INVALID";
}
+ }
}
-
- # Status & Resolution
- my $valid_res = check_field('resolution',
- scalar $bug_fields{'resolution'},
- undef, ERR_LEVEL );
- my $valid_status = check_field('bug_status',
- scalar $bug_fields{'bug_status'},
- undef, ERR_LEVEL );
- my $is_open = is_open_state($bug_fields{'bug_status'});
- my $status = $bug_fields{'bug_status'} || undef;
- my $resolution = $bug_fields{'resolution'} || undef;
-
- # Check everconfirmed
- my $everconfirmed;
- if ($product->allows_unconfirmed) {
- $everconfirmed = $bug_fields{'everconfirmed'} || 0;
+ else { # $valid_status is false
+ if ($everconfirmed) {
+ $status = $initial_status;
+ }
+ else {
+ $status = "UNCONFIRMED";
+ }
+ $err .= "Bug has invalid status, setting status to \"$status\".\n";
+ $err .= " Previous status was \"";
+ $err .= $bug_fields{'bug_status'} . "\".\n";
+ $resolution = undef;
+ }
+ }
+ else {
+ if ($everconfirmed) {
+ $status = $initial_status;
}
else {
- $everconfirmed = 1;
+ $status = "UNCONFIRMED";
}
- push (@query, "everconfirmed");
- push (@values, $everconfirmed);
-
- # Sanity check will complain about having bugs marked duplicate but no
- # entry in the dup table. Since we can't tell the bug ID of bugs
- # that might not yet be in the database we have no way of populating
- # this table. Change the resolution instead.
- if ( $valid_res && ( $bug_fields{'resolution'} eq "DUPLICATE" ) ) {
- $resolution = "INVALID";
- $err .= "This bug was marked DUPLICATE in the database ";
- $err .= "it was moved from.\n Changing resolution to \"INVALID\"\n";
+ $err .= "Bug has no status, setting status to \"$status\".\n";
+ $err .= " Previous status was unknown\n";
+ $resolution = undef;
+ }
+
+ if ($resolution) {
+ push(@query, "resolution");
+ push(@values, $resolution);
+ }
+
+ # Bug status
+ push(@query, "bug_status");
+ push(@values, $status);
+
+ # Custom fields - Multi-select fields have their own table.
+ my %multi_select_fields;
+ foreach my $field (Bugzilla->active_custom_fields) {
+ my $custom_field = $field->name;
+ my $value = $bug_fields{$custom_field};
+ next unless defined $value;
+ if ($field->type == FIELD_TYPE_FREETEXT) {
+ push(@query, $custom_field);
+ push(@values, clean_text($value));
}
-
- # If there is at least 1 initial bug status different from UNCO, use it,
- # else use the open bug status with the lowest sortkey (different from UNCO).
- my @bug_statuses = @{Bugzilla::Status->can_change_to()};
- @bug_statuses = grep { $_->name ne 'UNCONFIRMED' } @bug_statuses;
-
- my $initial_status;
- if (scalar(@bug_statuses)) {
- $initial_status = $bug_statuses[0]->name;
- }
- else {
- @bug_statuses = Bugzilla::Status->get_all();
- # Exclude UNCO and inactive bug statuses.
- @bug_statuses = grep { $_->is_active && $_->name ne 'UNCONFIRMED'} @bug_statuses;
- my @open_statuses = grep { $_->is_open } @bug_statuses;
- if (scalar(@open_statuses)) {
- $initial_status = $open_statuses[0]->name;
- }
- else {
- # There is NO other open bug statuses outside UNCO???
- Error("no open bug statuses available.");
- }
+ elsif ($field->type == FIELD_TYPE_TEXTAREA) {
+ push(@query, $custom_field);
+ push(@values, $value);
}
-
- if ($status) {
- if($valid_status){
- if($is_open){
- if ($resolution) {
- $err .= "Resolution set on an open status.\n";
- $err .= " Dropping resolution $resolution\n";
- $resolution = undef;
- }
- if($changed_owner){
- if($everconfirmed){
- $status = $initial_status;
- }
- else{
- $status = "UNCONFIRMED";
- }
- if ($status ne $bug_fields{'bug_status'}){
- $err .= "Bug reassigned, setting status to \"$status\".\n";
- $err .= " Previous status was \"";
- $err .= $bug_fields{'bug_status'} . "\".\n";
- }
- }
- if($everconfirmed){
- if($status eq "UNCONFIRMED"){
- $err .= "Bug Status was UNCONFIRMED but everconfirmed was true\n";
- $err .= " Setting status to $initial_status\n";
- $status = $initial_status;
- }
- }
- else{ # $everconfirmed is false
- if($status ne "UNCONFIRMED"){
- $err .= "Bug Status was $status but everconfirmed was false\n";
- $err .= " Setting status to UNCONFIRMED\n";
- $status = "UNCONFIRMED";
- }
- }
- }
- else{ # $is_open is false
- if (!$resolution) {
- $err .= "Missing Resolution. Setting status to ";
- if($everconfirmed){
- $status = $initial_status;
- $err .= "$initial_status\n";
- }
- else{
- $status = "UNCONFIRMED";
- $err .= "UNCONFIRMED\n";
- }
- }
- elsif (!$valid_res) {
- $err .= "Unknown resolution \"$resolution\".\n";
- $err .= " Setting resolution to INVALID\n";
- $resolution = "INVALID";
- }
- }
- }
- else{ # $valid_status is false
- if($everconfirmed){
- $status = $initial_status;
- }
- else{
- $status = "UNCONFIRMED";
- }
- $err .= "Bug has invalid status, setting status to \"$status\".\n";
- $err .= " Previous status was \"";
- $err .= $bug_fields{'bug_status'} . "\".\n";
- $resolution = undef;
- }
+ elsif ($field->type == FIELD_TYPE_SINGLE_SELECT) {
+ my $is_well_formed = check_field($custom_field, $value, undef, ERR_LEVEL);
+ if ($is_well_formed) {
+ push(@query, $custom_field);
+ push(@values, $value);
+ }
+ else {
+ $err .= "Skipping illegal value \"$value\" in $custom_field.\n";
+ }
}
- else {
- if($everconfirmed){
- $status = $initial_status;
+ elsif ($field->type == FIELD_TYPE_MULTI_SELECT) {
+ my @legal_values;
+ foreach my $item (_to_array($value)) {
+ my $is_well_formed = check_field($custom_field, $item, undef, ERR_LEVEL);
+ if ($is_well_formed) {
+ push(@legal_values, $item);
}
- else{
- $status = "UNCONFIRMED";
+ else {
+ $err .= "Skipping illegal value \"$item\" in $custom_field.\n";
}
- $err .= "Bug has no status, setting status to \"$status\".\n";
- $err .= " Previous status was unknown\n";
- $resolution = undef;
+ }
+ if (scalar @legal_values) {
+ $multi_select_fields{$custom_field} = \@legal_values;
+ }
}
-
- if ($resolution) {
- push( @query, "resolution" );
- push( @values, $resolution );
+ elsif ($field->type == FIELD_TYPE_DATETIME) {
+ eval { $value = Bugzilla::Bug->_check_datetime_field($value); };
+ if ($@) {
+ $err .= "Skipping illegal value \"$value\" in $custom_field.\n";
+ }
+ else {
+ push(@query, $custom_field);
+ push(@values, $value);
+ }
}
-
- # Bug status
- push( @query, "bug_status" );
- push( @values, $status );
-
- # Custom fields - Multi-select fields have their own table.
- my %multi_select_fields;
- foreach my $field (Bugzilla->active_custom_fields) {
- my $custom_field = $field->name;
- my $value = $bug_fields{$custom_field};
- next unless defined $value;
- if ($field->type == FIELD_TYPE_FREETEXT) {
- push(@query, $custom_field);
- push(@values, clean_text($value));
- } elsif ($field->type == FIELD_TYPE_TEXTAREA) {
- push(@query, $custom_field);
- push(@values, $value);
- } elsif ($field->type == FIELD_TYPE_SINGLE_SELECT) {
- my $is_well_formed = check_field($custom_field, $value, undef, ERR_LEVEL);
- if ($is_well_formed) {
- push(@query, $custom_field);
- push(@values, $value);
- } else {
- $err .= "Skipping illegal value \"$value\" in $custom_field.\n" ;
- }
- } elsif ($field->type == FIELD_TYPE_MULTI_SELECT) {
- my @legal_values;
- foreach my $item (_to_array($value)) {
- my $is_well_formed = check_field($custom_field, $item, undef, ERR_LEVEL);
- if ($is_well_formed) {
- push(@legal_values, $item);
- } else {
- $err .= "Skipping illegal value \"$item\" in $custom_field.\n" ;
- }
- }
- if (scalar @legal_values) {
- $multi_select_fields{$custom_field} = \@legal_values;
- }
- } elsif ($field->type == FIELD_TYPE_DATETIME) {
- eval { $value = Bugzilla::Bug->_check_datetime_field($value); };
- if ($@) {
- $err .= "Skipping illegal value \"$value\" in $custom_field.\n" ;
- }
- else {
- push(@query, $custom_field);
- push(@values, $value);
- }
- } elsif ($field->type == FIELD_TYPE_DATE) {
- eval { $value = Bugzilla::Bug->_check_date_field($value); };
- if ($@) {
- $err .= "Skipping illegal value \"$value\" in $custom_field.\n" ;
- }
- else {
- push(@query, $custom_field);
- push(@values, $value);
- }
- } else {
- $err .= "Type of custom field $custom_field is an unhandled FIELD_TYPE: " .
- $field->type . "\n";
- }
+ elsif ($field->type == FIELD_TYPE_DATE) {
+ eval { $value = Bugzilla::Bug->_check_date_field($value); };
+ if ($@) {
+ $err .= "Skipping illegal value \"$value\" in $custom_field.\n";
+ }
+ else {
+ push(@query, $custom_field);
+ push(@values, $value);
+ }
}
-
- # For the sake of sanitycheck.cgi we do this.
- # Update lastdiffed if you do not want to have mail sent
- unless ($mail) {
- push @query, "lastdiffed";
- push @values, $timestamp;
+ else {
+ $err .= "Type of custom field $custom_field is an unhandled FIELD_TYPE: "
+ . $field->type . "\n";
}
-
- # INSERT the bug
- my $query = "INSERT INTO bugs (" . join( ", ", @query ) . ") VALUES (";
- $query .= '?,' foreach (@values);
- chop($query); # Remove the last comma.
- $query .= ")";
-
- $dbh->do( $query, undef, @values );
- my $id = $dbh->bz_last_key( 'bugs', 'bug_id' );
-
- # We are almost certain to get some uninitialized warnings
- # Since this is just for debugging the query, let's shut them up
- eval {
- no warnings 'uninitialized';
- Debug(
- "Bug Query: INSERT INTO bugs (\n"
- . join( ",\n", @query )
- . "\n) VALUES (\n"
- . join( ",\n", @values ),
- DEBUG_LEVEL
- );
- };
-
- # Handle CC's
- if ( defined $bug_fields{'cc'} ) {
- my %ccseen;
- my $sth_cc = $dbh->prepare("INSERT INTO cc (bug_id, who) VALUES (?,?)");
- foreach my $person (_to_array($bug_fields{'cc'})) {
- next unless $person;
- my $uid;
- if ($uid = login_to_id($person)) {
- if ( !$ccseen{$uid} ) {
- $sth_cc->execute( $id, $uid );
- $ccseen{$uid} = 1;
- }
- }
- else {
- $err .= "CC member $person does not have an account here\n";
- }
+ }
+
+ # For the sake of sanitycheck.cgi we do this.
+ # Update lastdiffed if you do not want to have mail sent
+ unless ($mail) {
+ push @query, "lastdiffed";
+ push @values, $timestamp;
+ }
+
+ # INSERT the bug
+ my $query = "INSERT INTO bugs (" . join(", ", @query) . ") VALUES (";
+ $query .= '?,' foreach (@values);
+ chop($query); # Remove the last comma.
+ $query .= ")";
+
+ $dbh->do($query, undef, @values);
+ my $id = $dbh->bz_last_key('bugs', 'bug_id');
+
+ # We are almost certain to get some uninitialized warnings
+ # Since this is just for debugging the query, let's shut them up
+ eval {
+ no warnings 'uninitialized';
+ Debug(
+ "Bug Query: INSERT INTO bugs (\n"
+ . join(",\n", @query)
+ . "\n) VALUES (\n"
+ . join(",\n", @values),
+ DEBUG_LEVEL
+ );
+ };
+
+ # Handle CC's
+ if (defined $bug_fields{'cc'}) {
+ my %ccseen;
+ my $sth_cc = $dbh->prepare("INSERT INTO cc (bug_id, who) VALUES (?,?)");
+ foreach my $person (_to_array($bug_fields{'cc'})) {
+ next unless $person;
+ my $uid;
+ if ($uid = login_to_id($person)) {
+ if (!$ccseen{$uid}) {
+ $sth_cc->execute($id, $uid);
+ $ccseen{$uid} = 1;
}
+ }
+ else {
+ $err .= "CC member $person does not have an account here\n";
+ }
}
+ }
- # Handle keywords
- if ( defined( $bug_fields{'keywords'} ) ) {
- my %keywordseen;
- my $key_sth = $dbh->prepare(
- "INSERT INTO keywords
+ # Handle keywords
+ if (defined($bug_fields{'keywords'})) {
+ my %keywordseen;
+ my $key_sth = $dbh->prepare(
+ "INSERT INTO keywords
(bug_id, keywordid) VALUES (?,?)"
- );
- foreach my $keyword ( split( /[\s,]+/, $bug_fields{'keywords'} )) {
- next unless $keyword;
- my $keyword_obj = new Bugzilla::Keyword({name => $keyword});
- if (!$keyword_obj) {
- $err .= "Skipping unknown keyword: $keyword.\n";
- next;
- }
- if (!$keywordseen{$keyword_obj->id}) {
- $key_sth->execute($id, $keyword_obj->id);
- $keywordseen{$keyword_obj->id} = 1;
- }
- }
+ );
+ foreach my $keyword (split(/[\s,]+/, $bug_fields{'keywords'})) {
+ next unless $keyword;
+ my $keyword_obj = new Bugzilla::Keyword({name => $keyword});
+ if (!$keyword_obj) {
+ $err .= "Skipping unknown keyword: $keyword.\n";
+ next;
+ }
+ if (!$keywordseen{$keyword_obj->id}) {
+ $key_sth->execute($id, $keyword_obj->id);
+ $keywordseen{$keyword_obj->id} = 1;
+ }
}
-
- # Insert values of custom multi-select fields. They have already
- # been validated.
- foreach my $custom_field (keys %multi_select_fields) {
- my $sth = $dbh->prepare("INSERT INTO bug_$custom_field
- (bug_id, value) VALUES (?, ?)");
- foreach my $value (@{$multi_select_fields{$custom_field}}) {
- $sth->execute($id, $value);
- }
+ }
+
+ # Insert values of custom multi-select fields. They have already
+ # been validated.
+ foreach my $custom_field (keys %multi_select_fields) {
+ my $sth = $dbh->prepare(
+ "INSERT INTO bug_$custom_field
+ (bug_id, value) VALUES (?, ?)"
+ );
+ foreach my $value (@{$multi_select_fields{$custom_field}}) {
+ $sth->execute($id, $value);
}
-
- # Parse bug flags
- foreach my $bflag ( $bug->children('flag')) {
- next unless ( defined($bflag) );
- $err .= flag_handler(
- $bflag->{'att'}->{'name'}, $bflag->{'att'}->{'status'},
- $bflag->{'att'}->{'setter'}, $bflag->{'att'}->{'requestee'},
- $exporterid, $id,
- $comp_id, $prod_id,
- undef
- );
+ }
+
+ # Parse bug flags
+ foreach my $bflag ($bug->children('flag')) {
+ next unless (defined($bflag));
+ $err .= flag_handler(
+ $bflag->{'att'}->{'name'}, $bflag->{'att'}->{'status'},
+ $bflag->{'att'}->{'setter'}, $bflag->{'att'}->{'requestee'},
+ $exporterid, $id,
+ $comp_id, $prod_id,
+ undef
+ );
+ }
+
+ # Insert Attachments for the bug
+ foreach my $att (@attachments) {
+ if ($att eq "err") {
+ $err .= "No attachment ID specified, dropping attachment\n";
+ next;
+ }
+ if (!$exporter->is_insider && $att->{'isprivate'}) {
+ $err .= "Exporter not in insidergroup and attachment marked private.\n";
+ $err .= " Marking attachment public\n";
+ $att->{'isprivate'} = 0;
}
- # Insert Attachments for the bug
- foreach my $att (@attachments) {
- if ($att eq "err"){
- $err .= "No attachment ID specified, dropping attachment\n";
- next;
- }
- if (!$exporter->is_insider && $att->{'isprivate'}) {
- $err .= "Exporter not in insidergroup and attachment marked private.\n";
- $err .= " Marking attachment public\n";
- $att->{'isprivate'} = 0;
- }
-
- my $attacher_id = $att->{'attacher'} ? login_to_id($att->{'attacher'}) : undef;
+ my $attacher_id = $att->{'attacher'} ? login_to_id($att->{'attacher'}) : undef;
- $dbh->do("INSERT INTO attachments
+ $dbh->do(
+ "INSERT INTO attachments
(bug_id, creation_ts, modification_time, filename, description,
mimetype, ispatch, isprivate, isobsolete, submitter_id)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
- undef, $id, $att->{'date'}, $att->{'date'}, $att->{'filename'},
- $att->{'desc'}, $att->{'ctype'}, $att->{'ispatch'},
- $att->{'isprivate'}, $att->{'isobsolete'}, $attacher_id || $exporterid);
- my $att_id = $dbh->bz_last_key( 'attachments', 'attach_id' );
- my $att_data = $att->{'data'};
- my $sth = $dbh->prepare("INSERT INTO attach_data (id, thedata)
- VALUES ($att_id, ?)" );
- trick_taint($att_data);
- $sth->bind_param( 1, $att_data, $dbh->BLOB_TYPE );
- $sth->execute();
-
- $comments .= "Imported an attachment (id=$att_id)\n";
- if (!$attacher_id) {
- if ($att->{'attacher'}) {
- $err .= "The original submitter of attachment $att_id was\n ";
- $err .= $att->{'attacher'} . ", but he doesn't have an account here.\n";
- }
- else {
- $err .= "The original submitter of attachment $att_id is unknown.\n";
- }
- $err .= " Reassigning to the person who moved it here: $exporter_login.\n";
- }
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", undef, $id, $att->{'date'},
+ $att->{'date'}, $att->{'filename'}, $att->{'desc'}, $att->{'ctype'},
+ $att->{'ispatch'}, $att->{'isprivate'}, $att->{'isobsolete'},
+ $attacher_id || $exporterid
+ );
+ my $att_id = $dbh->bz_last_key('attachments', 'attach_id');
+ my $att_data = $att->{'data'};
+ my $sth = $dbh->prepare(
+ "INSERT INTO attach_data (id, thedata)
+ VALUES ($att_id, ?)"
+ );
+ trick_taint($att_data);
+ $sth->bind_param(1, $att_data, $dbh->BLOB_TYPE);
+ $sth->execute();
+
+ $comments .= "Imported an attachment (id=$att_id)\n";
+ if (!$attacher_id) {
+ if ($att->{'attacher'}) {
+ $err .= "The original submitter of attachment $att_id was\n ";
+ $err .= $att->{'attacher'} . ", but he doesn't have an account here.\n";
+ }
+ else {
+ $err .= "The original submitter of attachment $att_id is unknown.\n";
+ }
+ $err .= " Reassigning to the person who moved it here: $exporter_login.\n";
+ }
- # Process attachment flags
- foreach my $aflag (@{ $att->{'flags'} }) {
- next unless defined($aflag) ;
- $err .= flag_handler(
- $aflag->{'name'}, $aflag->{'status'},
- $aflag->{'setter'}, $aflag->{'requestee'},
- $exporterid, $id,
- $comp_id, $prod_id,
- $att_id
- );
- }
+ # Process attachment flags
+ foreach my $aflag (@{$att->{'flags'}}) {
+ next unless defined($aflag);
+ $err .= flag_handler(
+ $aflag->{'name'}, $aflag->{'status'}, $aflag->{'setter'},
+ $aflag->{'requestee'}, $exporterid, $id,
+ $comp_id, $prod_id, $att_id
+ );
}
+ }
- # Clear the attachments array for the next bug
- @attachments = ();
+ # Clear the attachments array for the next bug
+ @attachments = ();
- # Insert comments and append any errors
- my $worktime = $bug_fields{'actual_time'} || 0.0;
- $worktime = 0.0 if (!$exporter->is_timetracker);
- $comments .= "\n$err\n" if $err;
+ # Insert comments and append any errors
+ my $worktime = $bug_fields{'actual_time'} || 0.0;
+ $worktime = 0.0 if (!$exporter->is_timetracker);
+ $comments .= "\n$err\n" if $err;
- my $sth_comment =
- $dbh->prepare('INSERT INTO longdescs (bug_id, who, bug_when, isprivate,
+ my $sth_comment = $dbh->prepare(
+ 'INSERT INTO longdescs (bug_id, who, bug_when, isprivate,
thetext, work_time)
- VALUES (?, ?, ?, ?, ?, ?)');
-
- foreach my $c (@sorted_descs) {
- $sth_comment->execute($id, $c->{whoid} || $exporterid, $c->{bug_when},
- $c->{isprivate}, $c->{thetext}, 0);
- }
- $sth_comment->execute($id, $exporterid, $timestamp, 0, $comments, $worktime);
- Bugzilla::Bug->new($id)->_sync_fulltext( new_bug => 1);
-
- # Add this bug to each group of which its product is a member.
- my $sth_group = $dbh->prepare("INSERT INTO bug_group_map (bug_id, group_id)
- VALUES (?, ?)");
- foreach my $group_id ( keys %{ $product->group_controls } ) {
- if ($product->group_controls->{$group_id}->{'membercontrol'} != CONTROLMAPNA
- && $product->group_controls->{$group_id}->{'othercontrol'} != CONTROLMAPNA){
- $sth_group->execute( $id, $group_id );
- }
- }
-
- $log .= "Bug ${urlbase}show_bug.cgi?id=$bug_fields{'bug_id'} ";
- $log .= "imported as bug $id.\n";
- $log .= Bugziilla->localconfig->{"urlbase"} . "show_bug.cgi?id=$id\n\n";
- if ($err) {
- $log .= "The following problems were encountered while creating bug $id.\n";
- $log .= $err;
- $log .= "You may have to set certain fields in the new bug by hand.\n\n";
+ VALUES (?, ?, ?, ?, ?, ?)'
+ );
+
+ foreach my $c (@sorted_descs) {
+ $sth_comment->execute($id, $c->{whoid} || $exporterid,
+ $c->{bug_when}, $c->{isprivate}, $c->{thetext}, 0);
+ }
+ $sth_comment->execute($id, $exporterid, $timestamp, 0, $comments, $worktime);
+ Bugzilla::Bug->new($id)->_sync_fulltext(new_bug => 1);
+
+ # Add this bug to each group of which its product is a member.
+ my $sth_group = $dbh->prepare(
+ "INSERT INTO bug_group_map (bug_id, group_id)
+ VALUES (?, ?)"
+ );
+ foreach my $group_id (keys %{$product->group_controls}) {
+ if ( $product->group_controls->{$group_id}->{'membercontrol'} != CONTROLMAPNA
+ && $product->group_controls->{$group_id}->{'othercontrol'} != CONTROLMAPNA)
+ {
+ $sth_group->execute($id, $group_id);
}
- Debug( $log, OK_LEVEL );
- push(@logs, $log);
- Bugzilla::BugMail::Send( $id, { 'changer' => $exporter } ) if ($mail);
-
- # done with the xml data. Lets clear it from memory
- $twig->purge;
+ }
+
+ $log .= "Bug ${urlbase}show_bug.cgi?id=$bug_fields{'bug_id'} ";
+ $log .= "imported as bug $id.\n";
+ $log .= Bugziilla->localconfig->{"urlbase"} . "show_bug.cgi?id=$id\n\n";
+ if ($err) {
+ $log .= "The following problems were encountered while creating bug $id.\n";
+ $log .= $err;
+ $log .= "You may have to set certain fields in the new bug by hand.\n\n";
+ }
+ Debug($log, OK_LEVEL);
+ push(@logs, $log);
+ Bugzilla::BugMail::Send($id, {'changer' => $exporter}) if ($mail);
+
+ # done with the xml data. Lets clear it from memory
+ $twig->purge;
}
-Debug( "Reading xml", DEBUG_LEVEL );
+Debug("Reading xml", DEBUG_LEVEL);
# Read STDIN in slurp mode. VERY dangerous, but we live on the wild side ;-)
local ($/);
@@ -1237,30 +1275,28 @@ $xml = <>;
# If there's anything except whitespace before <?xml then we guess it's a mail
# and MIME::Parser should parse it. Else don't.
-if ($xml =~ m/\S.*<\?xml/s ) {
+if ($xml =~ m/\S.*<\?xml/s) {
- # If the email was encoded (Mailer::MessageToMTA() does it when using UTF-8),
- # we have to decode it first, else the XML parsing will fail.
- my $parser = MIME::Parser->new;
- $parser->output_to_core(1);
- $parser->tmp_to_core(1);
- my $entity = $parser->parse_data($xml);
- my $bodyhandle = $entity->bodyhandle;
- $xml = $bodyhandle->as_string;
+ # If the email was encoded (Mailer::MessageToMTA() does it when using UTF-8),
+ # we have to decode it first, else the XML parsing will fail.
+ my $parser = MIME::Parser->new;
+ $parser->output_to_core(1);
+ $parser->tmp_to_core(1);
+ my $entity = $parser->parse_data($xml);
+ my $bodyhandle = $entity->bodyhandle;
+ $xml = $bodyhandle->as_string;
}
# remove everything in file before xml header
$xml =~ s/^.+(<\?xml version.+)$/$1/s;
-Debug( "Parsing tree", DEBUG_LEVEL );
+Debug("Parsing tree", DEBUG_LEVEL);
my $twig = XML::Twig->new(
- twig_handlers => {
- bug => \&process_bug,
- attachment => \&process_attachment
- },
- start_tag_handlers => { bugzilla => \&init }
+ twig_handlers => {bug => \&process_bug, attachment => \&process_attachment},
+ start_tag_handlers => {bugzilla => \&init}
);
+
# Prevent DoS using the billion laughs attack.
$twig->{NoExpand} = 1;
@@ -1272,11 +1308,11 @@ my $urlbase = $root->{'att'}->{'urlbase'};
# It is time to email the result of the import.
my $log = join("\n\n", @logs);
-$log .= "\n\nImported $bugtotal bug(s) from $urlbase,\n sent by $exporter.\n";
-my $subject = "$bugtotal Bug(s) successfully moved from $urlbase to "
- . Bugzilla->localconfig->{"urlbase"};
+$log .= "\n\nImported $bugtotal bug(s) from $urlbase,\n sent by $exporter.\n";
+my $subject = "$bugtotal Bug(s) successfully moved from $urlbase to "
+ . Bugzilla->localconfig->{"urlbase"};
my @to = ($exporter, $maintainer);
-MailMessage( $subject, $log, @to );
+MailMessage($subject, $log, @to);
__END__