[Rt-commit] rt branch, allow-loops, created. rt-3.8.5-295-g9e051fa
Alex M Vandiver
alexmv at bestpractical.com
Wed Oct 14 17:14:34 EDT 2009
The branch, allow-loops has been created
at 9e051fa517e566c3c7419a3e95192b0de0f42f99 (commit)
- Log -----------------------------------------------------------------
commit 9e051fa517e566c3c7419a3e95192b0de0f42f99
Author: Alex Vandiver <alexmv at bestpractical.com>
Date: Tue Sep 29 19:38:21 2009 -0400
Add LinkSelfLoops configuration, to allow internal linking of self loops
Incoming mail messages whose ticket and queue disagree are inspected
to determine if this is a message from ourself, and then to create or
associate the incoming mail with a ticket in the queue.
Add tests for LinkSelfLoops
diff --git a/lib/RT/Action/SendEmail.pm b/lib/RT/Action/SendEmail.pm
index a09bd3e..ac24340 100755
--- a/lib/RT/Action/SendEmail.pm
+++ b/lib/RT/Action/SendEmail.pm
@@ -574,6 +574,7 @@ sub SetRTSpecialHeaders {
if ( RT->Config->Get('EmailOutputEncoding') );
$self->SetReturnAddress();
$self->SetReferencesHeaders();
+ $self->SetHeader("X-RT-Transaction-Id" => $self->TransactionObj->Id );
unless ( $self->TemplateObj->MIMEObj->head->get('Message-ID') ) {
@@ -611,6 +612,7 @@ sub SetRTSpecialHeaders {
unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") );
$self->SetHeader( 'X-RT-Loop-Prevention', RT->Config->Get('rtname') );
+ $self->SetHeader( 'X-RT-Allow-Self-Loops', 1) if RT->Config->Get('LinkSelfLoops');
$self->SetHeader( 'RT-Ticket',
RT->Config->Get('rtname') . " #" . $self->TicketObj->id() );
$self->SetHeader( 'Managed-by',
diff --git a/lib/RT/EmailParser.pm b/lib/RT/EmailParser.pm
index 7890f49..1ab46ba 100755
--- a/lib/RT/EmailParser.pm
+++ b/lib/RT/EmailParser.pm
@@ -356,6 +356,7 @@ Returns the same array with any IsRTAddress()es weeded out.
sub CullRTAddresses {
my $self = shift;
my @addresses= (@_);
+ return @addresses if RT->Config->Get('LinkSelfLoops');
my @addrlist;
foreach my $addr( @addresses ) {
diff --git a/lib/RT/Interface/Email.pm b/lib/RT/Interface/Email.pm
index 1279816..6f757ee 100755
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
@@ -107,6 +107,10 @@ Takes a HEAD object of L<MIME::Head> class and returns true if the
message's been sent by this RT instance. Uses "X-RT-Loop-Prevention"
field of the head for test.
+If C<X-RT-Allow-Self-Loops> is set on the message, and it from our own
+instance, and the C<LinkSelfLoops> configuration option is set,
+returns -1.
+
=cut
sub CheckForLoops {
@@ -116,12 +120,16 @@ sub CheckForLoops {
my $RTLoop = $head->get("X-RT-Loop-Prevention") || "";
chomp ($RTLoop); # remove that newline
if ( $RTLoop eq RT->Config->Get('rtname') ) {
- return 1;
+ if ( $head->get('X-RT-Allow-Self-Loops') and RT->Config->Get('LinkSelfLoops') ) {
+ return -1;
+ } else {
+ return 1;
+ }
}
# TODO: We might not trap the case where RT instance A sends a mail
# to RT instance B which sends a mail to ...
- return undef;
+ return 0;
}
=head2 CheckForSuspiciousSender HEAD
@@ -1306,14 +1314,15 @@ sub Gateway {
my $MessageId = $head->get('Message-ID')
|| "<no-message-id-". time . rand(2000) .'@'. RT->Config->Get('Organization') .'>';
+ chomp $MessageId;
#Pull apart the subject line
my $Subject = $head->get('Subject') || '';
chomp $Subject;
# {{{ Lets check for mail loops of various sorts.
- my ($should_store_machine_generated_message, $IsALoop, $result);
- ( $should_store_machine_generated_message, $ErrorsTo, $result, $IsALoop ) =
+ my ($IsALoop, $result);
+ ( undef, $ErrorsTo, $result, $IsALoop ) =
_HandleMachineGeneratedMail(
Message => $Message,
ErrorsTo => $ErrorsTo,
@@ -1323,9 +1332,10 @@ sub Gateway {
# Do not pass loop messages to MailPlugins, to make sure the loop
# is broken, unless $RT::StoreLoops is set.
- if ($IsALoop && !$should_store_machine_generated_message) {
+ if ($IsALoop > 0) {
return ( 0, $result, undef );
}
+
# }}}
$args{'ticket'} ||= ParseTicketId( $Subject );
@@ -1390,11 +1400,6 @@ sub Gateway {
);
}
-
- unless ($should_store_machine_generated_message) {
- return ( 0, $result, undef );
- }
-
# if plugin's updated SystemTicket then update arguments
$args{'ticket'} = $SystemTicket->Id if $SystemTicket && $SystemTicket->Id;
@@ -1402,39 +1407,25 @@ sub Gateway {
if ( !$args{'ticket'} && grep /^(comment|correspond)$/, @actions )
{
+ # This might be a creation we already saw; check if we've seen
+ # the message-id in this queue recently.
- my @Cc;
- my @Requestors = ( $CurrentUser->id );
-
- if (RT->Config->Get('ParseNewMessageForTicketCcs')) {
- @Cc = ParseCcAddressesFromHead(
- Head => $head,
- CurrentUser => $CurrentUser,
- QueueObj => $SystemQueueObj
- );
+ if (my $other = RecentMessage( $MessageId, queue => $SystemQueueObj->Id )) {
+ warn "Found dup, ticket is @{[$other->Id]}";
+ return ( 1, "Duplicate self-loop delivery (#@{[$other->Id]}))", $other );
}
- my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
- Queue => $SystemQueueObj->Id,
- Subject => $Subject,
- Requestor => \@Requestors,
- Cc => \@Cc,
- MIMEObj => $Message
+ my @ret = CreateTicket(
+ CurrentUser => $CurrentUser,
+ Message => $Message,
+ QueueObj => $SystemQueueObj,
+ ErrorsTo => $ErrorsTo,
);
- if ( $id == 0 ) {
- MailError(
- To => $ErrorsTo,
- Subject => "Ticket creation failed: $Subject",
- Explanation => $ErrStr,
- MIMEObj => $Message
- );
- return ( 0, "Ticket creation failed: $ErrStr", $Ticket );
- }
-
+ return @ret unless $ret[0];
# strip comments&corresponds from the actions we don't need
# to record them if we've created the ticket just now
@actions = grep !/^(comment|correspond)$/, @actions;
- $args{'ticket'} = $id;
+ ($args{'ticket'}, undef, $Ticket) = @ret;
} elsif ( $args{'ticket'} ) {
@@ -1458,10 +1449,36 @@ sub Gateway {
# }}}
my $unsafe_actions = RT->Config->Get('UnsafeEmailCommands');
+ my $return = $Ticket->Id;
foreach my $action (@actions) {
# If the action is comment, add a comment.
if ( $action =~ /^(?:comment|correspond)$/i ) {
+
+ # Check if this is an internal self-loop
+ if ( $Ticket->QueueObj->Id != $SystemQueueObj->Id
+ and $IsALoop < 0 )
+ {
+ my @ret = LinkSelfLoops(
+ Ticket => $Ticket,
+ QueueObj => $SystemQueueObj,
+ Message => $Message,
+ ErrorsTo => $ErrorsTo,
+ CurrentUser => $CurrentUser,
+ );
+ if (not $ret[0]) {
+ # If it failed, return the error
+ return @ret;
+ } elsif (ref $ret[0]) {
+ # Returns the object to comment on
+ $Ticket = $ret[0];
+ } else {
+ # Or a simple true value to drop on the floor
+ $return = $ret[0];
+ next;
+ }
+ }
+
my $method = ucfirst lc $action;
my ( $status, $msg ) = $Ticket->$method( MIMEObj => $Message );
unless ($status) {
@@ -1486,9 +1503,174 @@ sub Gateway {
return ($status, $msg, $Ticket) unless $status == 1;
}
}
+ $Ticket->Load($return);
return ( 1, "Success", $Ticket );
}
+sub RecentMessage {
+ my ($messageid, $type, $id) = @_;
+ my $messages = RT::Attachments->new($RT::SystemUser);
+ $messages->Limit( FIELD => 'messageid', VALUE => $messageid );
+ my $txns = $messages->Join(
+ ALIAS1 => 'main',
+ FIELD1 => 'transactionid',
+ TABLE2 => 'transactions',
+ FIELD2 => 'id',
+ );
+ $messages->Limit(
+ ALIAS => $txns,
+ FIELD => 'objecttype',
+ VALUE => 'RT::Ticket',
+ );
+ if ( $type eq "queue" ) {
+ my $tickets = $messages->Join(
+ ALIAS1 => $txns,
+ FIELD1 => 'objectid',
+ TABLE2 => 'tickets',
+ FIELD2 => 'id',
+ );
+ $messages->Limit(
+ ALIAS => $tickets,
+ FIELD => 'queue',
+ VALUE => $id,
+ );
+ } else {
+ $messages->Limit(
+ ALIAS => $txns,
+ FIELD => 'objectid',
+ VALUE => $id,
+ );
+ }
+
+ my $first = $messages->First;
+ return $first ? $first->TransactionObj->Object : undef
+}
+
+
+=head2 LinkSelfLoops
+
+=cut
+
+sub LinkSelfLoops {
+ my %args = (
+ Ticket => undef,
+ QueueObj => undef,
+ Message => undef,
+ ErrorsTo => undef,
+ CurrentUser => undef,
+ @_
+ );
+
+ # Determine original message-id by looking at our headers, looking
+ # up that txn, and chasing the txn's attachment's headers, etc..
+ my $txn = RT::Transaction->new( $RT::SystemUser );
+ $txn->Load( $args{Message}->head->get('X-RT-Transaction-Id') );
+ my $origid;
+ while ($txn->Id) {
+ last unless my $attach = $txn->Attachments->First;
+ $origid = $attach->MessageId;
+ last unless my $txnid = $attach->GetHeader("X-RT-Transaction-Id");
+ $txn = RT::Transaction->new( $RT::SystemUser );
+ $txn->Load($txnid);
+ }
+
+ die "No original message-id" unless $origid;
+ chomp $origid;
+
+ my $orig = $txn->Attachments->First->ContentAsMIME;
+ $args{Message}->head->set($_, $orig->head->get($_))
+ for qr/Subject Content-Type Content-Transfer-Encoding Content-Length MIME-Version/;
+ $args{Message}->bodyhandle( $orig->bodyhandle );
+ $args{Message}->parts( [$orig->parts] );
+
+ # Look for linked tickets in the given queue
+ my @links = map {$_->Content}
+ $args{Ticket}->Attributes->Named('InternalLinks-'.$args{QueueObj}->Id);
+
+ if (not @links) {
+ # No existing link between ticket and that queue. Look for
+ # the message-id in the queue
+ my $other = RecentMessage($origid, queue => $args{QueueObj}->Id);
+ unless ($other) {
+ # If we didn't find it, create it
+ my @ret = CreateTicket(
+ CurrentUser => $args{CurrentUser},
+ Message => $args{Message},
+ QueueObj => $args{QueueObj},
+ ErrorsTo => $args{ErrorsTo},
+ );
+ return @ret unless $ret[0];
+ (undef, undef, $other) = @ret;
+ }
+ # Regardless, link them now.
+ $args{Ticket}->AddAttribute(
+ Name => "InternalLinks-" . $other->Queue,
+ Content => $other->Id,
+ );
+ $other->AddAttribute(
+ Name => "InternalLinks-" . $args{Ticket}->Queue,
+ Content => $args{Ticket}->Id,
+ );
+ # ..and drop the message on the floor.
+ return $other->Id;
+ }
+
+ if (@links > 1) {
+ die "More than one link to queue @{[$args{QueueObj}->Name]}: @links";
+ }
+
+ # We found a specific linked ticket in the given queue. See if it
+ # has seen the original message-id yet -- if so, drop on the floor.
+ my $other = RT::Ticket->new( $args{CurrentUser} );
+ $other->Load(@links);
+ return $args{Ticket}->Id if RecentMessage($origid, ticket => $other->id);
+
+ # Otherwise, the comment/correspond goes on the linked ticket
+ return $other;
+}
+
+sub CreateTicket {
+ my %args = (
+ CurrentUser => undef,
+ Message => undef,
+ QueueObj => undef,
+ ErrorsTo => undef,
+ @_,
+ );
+ my @Cc;
+ my @Requestors = ( $args{CurrentUser}->id );
+
+ if (RT->Config->Get('ParseNewMessageForTicketCcs')) {
+ @Cc = ParseCcAddressesFromHead(
+ Head => $args{Message}->head,
+ CurrentUser => $args{CurrentUser},
+ QueueObj => $args{QueueObj},
+ );
+ }
+
+ my $Subject = $args{Message}->head->get('Subject') || '';
+ chomp $Subject;
+
+ my $Ticket = RT::Ticket->new($args{CurrentUser});
+ my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
+ Queue => $args{QueueObj}->Id,
+ Subject => $Subject,
+ Requestor => \@Requestors,
+ Cc => \@Cc,
+ MIMEObj => $args{Message},
+ );
+ if ( $id == 0 ) {
+ MailError(
+ To => $args{ErrorsTo},
+ Subject => "Ticket creation failed: $Subject",
+ Explanation => $ErrStr,
+ MIMEObj => $args{Message}
+ );
+ return ( 0, "Ticket creation failed: $ErrStr", $Ticket );
+ }
+ return ($id, "Ticket created", $Ticket);
+}
+
=head2 GetAuthenticationLevel
# Authentication Level
@@ -1681,13 +1863,13 @@ sub _HandleMachineGeneratedMail {
#If the message is autogenerated, we need to know, so we can not
# send mail to the sender
- if ( $IsBounce || $IsSuspiciousSender || $IsAutoGenerated || $IsALoop ) {
+ if ( $IsBounce || $IsSuspiciousSender || $IsAutoGenerated || ($IsALoop > 0) ) {
$SquelchReplies = 1;
$ErrorsTo = $owner_mail;
}
# Warn someone if it's a loop, before we drop it on the ground
- if ($IsALoop) {
+ if ($IsALoop > 0) {
$RT::Logger->crit("RT Received mail (".$args{MessageId}.") from itself.");
#Should we mail it to RTOwner?
@@ -1715,7 +1897,7 @@ sub _HandleMachineGeneratedMail {
$head->delete('RT-Squelch-Replies-To');
}
- if ($SquelchReplies) {
+ if ($SquelchReplies and $IsALoop >= 0) {
# Squelch replies to the sender, and also leave a clue to
# allow us to squelch ALL outbound messages. This way we
diff --git a/t/mail/linkselfloops.t b/t/mail/linkselfloops.t
new file mode 100644
index 0000000..0aa13a8
--- /dev/null
+++ b/t/mail/linkselfloops.t
@@ -0,0 +1,749 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use RT::Test config => 'Set( $LinkSelfLoops, 1 );', 'no_plan' => 1;
+
+RT::Test->set_mail_catcher;
+my ($baseurl, $m) = RT::Test->started_ok;
+
+# Set up queues
+my $systems = RT::Test->load_or_create_queue(
+ Name => 'Systems',
+ CorrespondAddress => 'systems at example.com',
+ CommentAddress => 'systems-comment at example.com',
+);
+ok $systems && $systems->id, 'loaded or created systems queue';
+
+my $helpdesk = RT::Test->load_or_create_queue(
+ Name => 'Helpdesk',
+ CorrespondAddress => 'helpdesk at example.com',
+ CommentAddress => 'helpdesk-comment at example.com',
+);
+ok $helpdesk && $helpdesk->id, 'loaded or created helpdesk queue';
+
+# ...and rights
+RT::Test->set_rights(
+ { Principal => 'Everyone',
+ Right => [
+ 'CreateTicket',
+ 'ShowTicket',
+ 'SeeQueue',
+ 'ReplyToTicket',
+ 'CommentOnTicket',
+ 'ModifyTicket'
+ ],
+ },
+ { Principal => 'Privileged',
+ Right => ['TakeTicket', 'OwnTicket', 'ShowTicketComments'],
+ }
+);
+
+# ...and users
+my $bjoern = RT::Test->load_or_create_user(
+ EmailAddress => 'bjoern at example.com',
+);
+
+my $sven = RT::Test->load_or_create_user(
+ EmailAddress => 'sven at example.com',
+);
+my ($ok, $msg);
+($ok, $msg) = $helpdesk->AddWatcher( Type => 'AdminCc', Email => 'bjoern at example.com' );
+ok($ok, "Added bjoern as admincc on helpdesk - $msg");
+($ok, $msg) = $systems->AddWatcher( Type => 'AdminCc', Email => 'sven at example.com' );
+ok($ok, "Added sven as admincc on systems - $msg");
+
+sub parse_mail {
+ my $mail = shift;
+ require RT::EmailParser;
+ my $parser = RT::EmailParser->new;
+ $parser->ParseMIMEEntityFromScalar( $mail );
+ return $parser->Entity;
+}
+
+sub reinsert {
+ my $text = shift;
+ my $mime = parse_mail($text);
+ return (0, 0) unless ($mime->head->get("To")||"") =~ /(helpdesk|systems)(?:-(comment))?\@example\.com/
+ or ($mime->head->get("Cc")||"") =~ /(helpdesk|systems)(?:-(comment))?\@example\.com/
+ or ($mime->head->get("Bcc")||"") =~ /(helpdesk|systems)(?:-(comment))?\@example\.com/;
+
+ my ($queue, $action) = (ucfirst($1), $2 || "correspond");
+ return RT::Test->send_via_mailgate( $text, queue => $queue, action => $action );
+}
+
+sub got_mail_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my @messages = @_;
+ my @mails = RT::Test->fetch_caught_mails;
+ is( scalar(@mails), scalar(@messages) );
+ for my $msg (@messages) {
+ my $text = shift @mails;
+ my $mail = parse_mail($text);
+ my $fail;
+ for (grep {$_ ne "id"} keys %{$msg}) {
+ like($mail->head->get($_), $msg->{$_}, "$_ contains @{[$msg->{$_}]}") or $fail++;
+ }
+ warn $text if $fail;
+ my ($status, $id) = reinsert($text);
+ if ($msg->{id}) {
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ is ($id, $msg->{id}, "Created ticket");
+ }
+ }
+ warn $_ for @mails;
+}
+
+sub record_ok {
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+ my %args = (
+ mode => 'comment',
+ on => undef,
+ as => undef,
+ cc => undef,
+ @_,
+ );
+
+ $args{as} ||= $args{on}->CurrentUser;
+
+ my $ticket = RT::Ticket->new( $args{as} );
+ $ticket->Load( ref $args{on} ? $args{on}->Id : $args{on} );
+ my $method = ucfirst lc $args{mode};
+
+ my $caller = join(":", caller);
+ my $mime = MIME::Entity->build(
+ Data => $caller,
+ "Message-Id" => "$caller\@example.com",
+ Subject => $caller,
+ );
+ my ($id, $status) = $ticket->$method(
+ MIMEObj => $mime,
+ CcMessageTo => $args{cc},
+ );
+ ok($id, "Added $method on @{[$ticket->Id]} as @{[$args{as}->EmailAddress]})");
+}
+
+# =====> SITUATION 1: Helpdesk queue adds systems@ as a one-time cc on a
+# comment (helpdesk gets all correspondence from systems, as a comment;
+# systems only gets mail explicitly one-time-CC'd to them)
+
+{
+ # Joe sends mail to helpdesk@
+ my $text = <<EOF;
+From: joe\@example.com
+To: helpdesk\@example.com
+Subject: This is a test of new ticket creation
+Message-Id: first\@example.com
+
+A helpdesk ticket
+EOF
+
+ my ($status, $id) = RT::Test->send_via_mailgate($text, queue => 'Helpdesk');
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "Created ticket");
+ my ($helpticket, $systicket) = ($id, $id + 1);
+
+ # Sends mail back to Joe, and to Bjoern
+ got_mail_ok( { to => qr/joe\@/ }, { bcc => qr/bjoern\@/} );
+
+ # Ticket #101 is created in the helpdesk queue with joe as the requestor
+ my $ticket = RT::Test->last_ticket( $bjoern );
+ isa_ok ($ticket, 'RT::Ticket');
+ is ($ticket->Id, $id, "correct ticket id");
+ is ($ticket->Subject , 'This is a test of new ticket creation', "Created the ticket");
+
+ # Bjoern adds a comment with systems@ as a one-time CC.
+ record_ok( mode => 'comment', on => $ticket, as => $bjoern, cc => 'systems at example.com');
+
+ # RT sends mail to systems@
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ cc => qr/systems\@/,
+ id => $systicket,
+ },
+ );
+
+ # Ticket #102 is created in the system queue with helpdesk-comment@ as the requestor
+ $ticket = RT::Test->last_ticket( $sven );
+ is($ticket->RequestorAddresses, 'helpdesk-comment at example.com');
+
+ # Auto-reply goes back to #101, and to sven
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Auto-reply gets dropped
+ got_mail_ok();
+ is(RT::Test->last_ticket->id, $ticket->id);
+
+ # Ticket #102 is now linked to ticket #101
+
+ # Sven adds a comment on #102
+ record_ok( mode => 'comment', on => $systicket, as => $sven );
+
+ # No mail is sent out (Sven would get it, but NotifyActor is not set)
+ got_mail_ok();
+
+ # Sven adds a correspondence on #102
+ record_ok( mode => 'correspond', on => $systicket, as => $sven );
+
+ # helpdesk-comment is notified
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ );
+
+ # Which notifies Bjoern
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ bcc => qr/bjoern\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #101
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern );
+
+ # AdminCCs on #101 are notified
+ got_mail_ok();
+
+ # Bjoern adds a correspondence on #101
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern );
+
+ # Joe and AdminCCs on #101 are notified
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #101, choosing to one-time-CC systems@
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern, cc => 'systems at example.com' );
+
+ # AdminCCs on #101 are notified, as is systems@,
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ cc => qr/systems\@/,
+ id => $helpticket,
+ },
+ );
+
+ # which notifies Sven and AdminCCs on #102
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Bjoern adds a correspondence on #101, choosing to one-time-CC systems@
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern, cc => 'systems at example.com' );
+
+ # Joe and AdminCCs on #101 are notified, as is systems@,
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ cc => qr/systems\@/,
+ id => $helpticket,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # which notifies Sven and AdminCCs on #102
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ );
+
+ # Mail to helpdesk-comment gets droppped
+ got_mail_ok();
+}
+
+# ======> SITUATION 2: Helpdesk queue adds systems@ as a one-time cc on
+# a correspondence
+# (The result is identical to the above, with the exception of the
+# original email)
+{
+ # Joe sends mail to helpdesk@
+ my $text = <<EOF;
+From: joe\@example.com
+To: helpdesk\@example.com
+Subject: This is a test of new ticket creation
+Message-Id: second\@example.com
+
+A helpdesk ticket
+EOF
+
+ my ($status, $id) = RT::Test->send_via_mailgate($text, queue => 'Helpdesk');
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "Created ticket");
+ my ($helpticket, $systicket) = ($id, $id + 1);
+
+ # Sends mail back to Joe, and to Bjoern
+ got_mail_ok( { to => qr/joe\@/ }, { bcc => qr/bjoern\@/} );
+
+ # Ticket #201 is created in the helpdesk queue with joe as the requestor
+ my $ticket = RT::Test->last_ticket( $bjoern );
+ isa_ok ($ticket, 'RT::Ticket');
+ is ($ticket->Id, $id, "correct ticket id");
+ is ($ticket->Subject , 'This is a test of new ticket creation', "Created the ticket");
+
+ # Bjoern adds a correspondence with systems@ as a one-time CC.
+ record_ok( mode => 'correspond', on => $ticket, as => $bjoern, cc => 'systems at example.com');
+
+ # RT sends mail to joe and systems@
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ cc => qr/systems\@/,
+ id => $systicket,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # Ticket #202 is created in the system queue with helpdesk@ as the requestor
+ $ticket = RT::Test->last_ticket( $sven );
+ is($ticket->RequestorAddresses, 'helpdesk at example.com');
+
+ # Auto-reply goes back to #201, and to sven
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk\@/,
+ id => $systicket,
+ },
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Auto-reply gets dropped
+ got_mail_ok();
+ is(RT::Test->last_ticket->id, $ticket->id);
+
+ # Ticket #202 is linked to ticket #201
+
+ # Sven adds a comment on #202
+ record_ok( mode => 'comment', on => $systicket, as => $sven );
+
+ # No mail is sent out (Sven would get it, but NotifyActor is not set)
+ got_mail_ok();
+
+ # Sven adds a correspondence on #202
+ record_ok( mode => 'correspond', on => $systicket, as => $sven );
+
+ # AdminCCs on #202 are notified, as is helpdesk@,
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk\@/,
+ id => $systicket,
+ },
+ );
+
+ # Which notifies Joe, Bjoern, and AdminCCs on #201
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ bcc => qr/bjoern\@/,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #201
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern );
+
+ # AdminCCs on #201 are notified
+ got_mail_ok();
+
+ # Bjoern adds a correspondence on #201
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern );
+
+ # Joe and AdminCCs on #201 are notified
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #201, choosing to one-time-CC systems@
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern, cc => 'systems at example.com' );
+
+ # AdminCCs on #201 are notified, as is systems@,
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ cc => qr/systems\@/,
+ id => $helpticket,
+ },
+ );
+ # which notifies Sven and AdminCCs on #202 (and the "requestor"
+ # helpdesk@, since it came from helpdesk-comment@, not helpdesk@,
+ # so NotifyActor isn't relevant!)
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ { from => qr/systems\@/,
+ to => qr/helpdesk\@/,
+ id => $systicket,
+ },
+ );
+
+ # Mail to helpdesk gets droppped
+ got_mail_ok();
+
+ # Bjoern adds a correspondence on #201, choosing to one-time-CC systems@
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern, cc => 'systems at example.com' );
+ # Joe and AdminCCs on #201 are notified, as is systems@,
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ cc => qr/systems\@/,
+ id => $helpticket,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+ # which notifies Sven and AdminCCs on #202
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+}
+
+# ======> SITUATION 3: Helpdesk queue adds systems@ as permanent cc
+# (linked system ticket gets all helpdesk correspondence, but not
+# comments; helpdesk gets correspondence from systems)
+
+{
+ # Joe sends mail to helpdesk@
+ my $text = <<EOF;
+From: joe\@example.com
+To: helpdesk\@example.com
+Subject: This is a test of new ticket creation
+Message-Id: third\@example.com
+
+A helpdesk ticket
+EOF
+
+ my ($status, $id) = RT::Test->send_via_mailgate($text, queue => 'Helpdesk');
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "Created ticket");
+ my ($helpticket, $systicket) = ($id, $id + 1);
+
+ # Sends mail back to Joe, and to Bjoern
+ got_mail_ok( { to => qr/joe\@/ }, { bcc => qr/bjoern\@/} );
+
+ # Ticket #301 is created in the helpdesk queue with joe as the requestor
+ my $ticket = RT::Test->last_ticket( $bjoern );
+ isa_ok ($ticket, 'RT::Ticket');
+ is ($ticket->Id, $id, "correct ticket id");
+ is ($ticket->Subject , 'This is a test of new ticket creation', "Created the ticket");
+
+ # Bjoern adds systems@ as a cc on the ticket
+ ok($ticket->AddWatcher( Type => 'Cc', Email => 'systems at example.com' ), "Added systems@ as a watcher");
+
+ # Bjoern adds a comment
+ record_ok( mode => 'comment', on => $ticket, as => $bjoern );
+
+ # No mail is sent out (Bjoern would get it, but NotifyActor is not set)
+ got_mail_ok();
+
+ # Bjoern adds a correspondence
+ record_ok( mode => 'correspond', on => $ticket, as => $bjoern );
+
+ # Joe and AdminCCs on #301 are notified, as is systems@
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ cc => qr/systems\@/,
+ id => $systicket,
+ },
+ );
+
+ # Ticket #302 is created in the system queue with helpdesk@ as the requestor
+ $ticket = RT::Test->last_ticket( $sven );
+ is($ticket->RequestorAddresses, 'helpdesk at example.com');
+
+ # Auto-reply goes back to #301, and to sven
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk\@/,
+ id => $systicket,
+ },
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Auto-reply gets dropped
+ got_mail_ok();
+ is(RT::Test->last_ticket->id, $ticket->id);
+
+ # Ticket #302 is linked to ticket #301
+
+ # Sven adds a comment on #302
+ record_ok( mode => 'comment', on => $systicket, as => $sven );
+
+ # AdminCCs on #302 are notified
+ got_mail_ok();
+
+ # Sven adds a correspondence on #302
+ record_ok( mode => 'correspond', on => $systicket, as => $sven );
+
+ # AdminCCs on #302 are notified, as is helpdesk@,
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk\@/,
+ id => $systicket,
+ },
+ );
+
+ # which notifies Bjoern and Joe on #301
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ bcc => qr/bjoern\@/,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #301
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern );
+
+ # AdminCCs on #301 are notified
+ got_mail_ok();
+
+ # Bjoern adds a correspondence on #301
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern );
+
+ # Joe and AdminCCs on #301 are notified, as is systems@
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ cc => qr/systems\@/,
+ id => $helpticket,
+ },
+ );
+
+ # which notifies Sven and AdminCCs on #302
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+}
+
+# ======> SITUATION 4: Helpdesk queue adds systems@ as permanent AdminCC
+# (linked system ticket gets all correspondence and comments; helpdesk
+# gets correspondence from systems)
+
+{
+ # Joe sends mail to helpdesk@
+ my $text = <<EOF;
+From: joe\@example.com
+To: helpdesk\@example.com
+Subject: This is a test of new ticket creation
+Message-Id: fourth\@example.com
+
+A helpdesk ticket
+EOF
+
+ my ($status, $id) = RT::Test->send_via_mailgate($text, queue => 'Helpdesk');
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "Created ticket");
+ my ($helpticket, $systicket) = ($id, $id + 1);
+
+ # Sends mail back to Joe, and to Bjoern
+ got_mail_ok( { to => qr/joe\@/ }, { bcc => qr/bjoern\@/} );
+
+ # Ticket #401 is created in the helpdesk queue with joe as the requestor
+ my $ticket = RT::Test->last_ticket( $bjoern );
+ isa_ok ($ticket, 'RT::Ticket');
+ is ($ticket->Id, $id, "correct ticket id");
+ is ($ticket->Subject , 'This is a test of new ticket creation', "Created the ticket");
+
+ # Bjoern adds systems@ as an AdminCC on the ticket
+ ok($ticket->AddWatcher( Type => 'AdminCc', Email => 'systems at example.com' ), "Added systems@ as a watcher");
+
+ # Bjoern adds a comment
+ record_ok( mode => 'comment', on => $ticket, as => $bjoern );
+
+ # AdminCCs on #401 are notified, as is systems@
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ bcc => qr/systems\@/,
+ id => $systicket,
+ },
+ );
+
+ # Ticket #402 is created in the system queue with helpdesk-comment@ as the requestor
+ $ticket = RT::Test->last_ticket( $sven );
+ is($ticket->RequestorAddresses, 'helpdesk-comment at example.com');
+
+ # Auto-reply goes back to #401, and to sven
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Auto-reply gets dropped
+ got_mail_ok();
+ is(RT::Test->last_ticket->id, $ticket->id);
+
+ # Ticket #402 is linked to ticket #401
+
+ # Sven adds a comment on #402
+ record_ok( mode => 'comment', on => $systicket, as => $sven );
+
+ # AdminCCs on #402 are notified
+ got_mail_ok();
+
+ # Sven adds a correspondence on #402
+ record_ok( mode => 'correspond', on => $systicket, as => $sven );
+
+ # AdminCCs on #402 are notified, as is helpdesk-comment@,
+ got_mail_ok(
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ );
+ # which notifies Bjoern and AdminCCs on #401
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ bcc => qr/bjoern\@/,
+ },
+ );
+
+ # Bjoern adds a comment on #401
+ record_ok( mode => 'comment', on => $helpticket, as => $bjoern );
+ # AdminCCs on #401 are notified, as is systems@
+ got_mail_ok(
+ { from => qr/helpdesk-comment\@/,
+ bcc => qr/systems\@/,
+ id => $helpticket,
+ },
+ );
+ # which notifies Sven and AdminCCs on #402
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ );
+
+ # Bjoern adds a correspondence on #401
+ record_ok( mode => 'correspond', on => $helpticket, as => $bjoern );
+ # Joe and AdminCCs on #401 are notified, as is systems@
+ got_mail_ok(
+ { from => qr/helpdesk\@/,
+ bcc => qr/systems\@/,
+ id => $helpticket,
+ },
+ { from => qr/helpdesk\@/,
+ to => qr/joe\@/,
+ },
+ );
+
+ # which notifies Sven and AdminCCs on #402 (and requestor, which is helpdesk-comment)
+ got_mail_ok(
+ { from => qr/systems\@/,
+ bcc => qr/sven\@/,
+ },
+ { from => qr/systems\@/,
+ to => qr/helpdesk-comment\@/,
+ id => $systicket,
+ },
+ );
+
+ # helpdesk-comment@ mail gets dropped
+ got_mail_ok();
+}
+
+
+# ======> SITUATION 5: Helpdesk queue adds systems@ as permanent
+# AdminCC, systems adds helpdesk@ as permanent AdminCC (All
+# correspondence and comment from helpdesk added as comment on system;
+# all correspondence and comment from system added as comment on helpdesk)
+
+{
+ # Joe sends mail to helpdesk@
+ my $text = <<EOF;
+From: joe\@example.com
+To: helpdesk\@example.com
+Subject: This is a test of new ticket creation
+Message-Id: fifth\@example.com
+
+A helpdesk ticket
+EOF
+
+ my ($status, $id) = RT::Test->send_via_mailgate($text, queue => 'Helpdesk');
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "Created ticket");
+ my ($helpticket, $systicket) = ($id, $id + 1);
+
+ # Sends mail back to Joe, and to Bjoern
+ got_mail_ok( { to => qr/joe\@/ }, { bcc => qr/bjoern\@/} );
+
+ # Ticket #501 is created in the helpdesk queue with joe as the requestor
+ my $ticket = RT::Test->last_ticket( $bjoern );
+ isa_ok ($ticket, 'RT::Ticket');
+ is ($ticket->Id, $id, "correct ticket id");
+ is ($ticket->Subject , 'This is a test of new ticket creation', "Created the ticket");
+
+ # Bjoern adds systems@ as an AdminCC ticket #501
+ # Bjoern adds a comment
+ # AdminCCs on #501 are notified, as is systems@
+
+ # Ticket #502 is created in the system queue with helpdesk-comment@ as
+ # the requestor
+ # Ticket #502 is linked to ticket #501
+ # Sven takes ticket #502
+ # Sven adds helpdesk@ as an AdminCC on ticket #502
+
+ # Sven adds a comment on #502
+ # AdminCCs on #502 are notified, as is helpdesk-comment@,
+ # which adds a comment on #501,
+ # which notifies Bjoern and AdminCCs on #501
+ # (Note that RT will correctly detect that #502 has seen this comment
+ # already, and _not_loop it back!)
+
+ # Sven adds a correspondence on #502
+ # AdminCCs on #502 are notified, as is helpdesk-comment@,
+ # which adds a comment on #501,
+ # which notifies Bjoern and AdminCCs on #501
+ # (See above note about looping)
+
+ # Bjoern adds a comment on #501
+ # AdminCCs on #501 are notified, as is systems@
+ # which adds a comment on #502,
+ # which notifies Sven and AdminCCs on #502
+ # (See above note about looping)
+
+ # Bjoern adds a correspondence on #501
+ # Joe and AdminCCs on #501 are notified, as is systems@
+ # which adds a comment on #502,
+ # which notifies Sven and AdminCCs on #502
+ # (see above note about looping)
+}
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list