ParseFollowupMessageForTicketCcs

From Request Tracker Wiki
Jump to navigation Jump to search

ParseFollowupMessageForTicketCcs

After becoming more proficient in writing RT scrips, I decided to convert the patch below into a scrip so we wouldn't have to worry about patching after upgrading. It also works with correspondences made via the web instead of only via email like the patch below. See AddWatchersOnCorrespond for more information on the scrip version.

Automatically add ticket [CC]s from followup emails

The ParseNewMessageForTicketCcs option in SiteConfig will automatically add CC Watchers to a ticket during new ticket creation. We wanted the same behavior for email followups to existing tickets, so I patched the RT/Interface/Email.pm module to do this if the ParseFollowupMessageForTicketCcs option is also set in your SiteConfig.

Note: Both options use the RTAddressRegexp variable to avoid problems.

Patch written for and tested with RT version 3.4.5.


RT/Interface/Email.pm

diff -urN /usr/lib/rt/RT/Interface/Email.pm-dist /usr/lib/rt/RT/Interface/Email.pm
 --- /usr/lib/rt/RT/Interface/Email.pm-dist      2005-11-14 17:35:40.000000000 -0500
 +++ /usr/lib/rt/RT/Interface/Email.pm   2006-07-21 13:30:02.000000000 -0400
 @@ -746,6 +746,7 @@
      my $Ticket = RT::Ticket->new($CurrentUser);
 
      # {{{ If we don't have a ticket Id, we're creating a new ticket
 +    my $new_ticket = 1;
      if ( (!$SystemTicket || !$SystemTicket->Id) &&
             grep /^(comment|correspond)$/, @actions ) {
 
 @@ -784,6 +785,8 @@
         $args{'ticket'} = $id;
 
          # }}}
 +    } else {
 +      $new_ticket = 0;
      }
 
      $Ticket->Load( $args{'ticket'} );
 @@ -799,6 +802,21 @@
          return ( 0, $message );
      }
 
 +    # JAS - Add Ticket CCs for followups to current tickets also:
 +    if (not $new_ticket and $RT::ParseFollowupMessageForTicketCcs) {
 +      my @Cc = ParseCcAddressesFromHead(
 +                                       Head        => $head,
 +                                       CurrentUser => $CurrentUser,
 +                                       QueueObj    => $SystemQueueObj
 +                                      );
 +      foreach (@Cc) {
 +       $Ticket->AddWatcher(
 +                           Type => 'Cc',
 +                           Email => $_,
 +                          );
 +      }
 +    }
 +
      # }}}
      foreach my $action( @actions ) {
          #   If the action is comment, add a comment.
 
 

Later we decided to make RT also add senders as Cc watchers, so I created a new version of the patch. This version also verifies that the email address is not already a watcher of the ticket or queue before it is added.

Note: The person being added needs to have permission to see the ticket, which means you will probably have to grant the System group Everyone, Watch rights (globally or for the necessary Queues) for this to work.

Warning: "It's worth noting that this patch opens up a potentially dangerous hole. A malicious user could easily make themselves CC of ...all your tickets. In some organizations, this may not matter. But it's a showstopper here." --JV (from rt-users mailing list). Therefore, be aware and take appropriate precautions if you use this.


diff -urN /usr/lib/rt/RT/Interface/Email.pm-dist /usr/lib/rt/RT/Interface/Email.pm
 --- /usr/lib/rt/RT/Interface/Email.pm-dist      2005-11-14 17:35:40.000000000 -0500
 +++ /usr/lib/rt/RT/Interface/Email.pm   2007-02-07 14:52:44.000000000 -0500
 @@ -346,13 +346,17 @@
 
      my (@Addresses);
 
 +    # JAS - Add new From addresses in case the ticket was privately forwarded
 +    # to a new interested third party who then replies to the ticket.
 +    my $From = $args{'Head'}->get('Reply-To') || $args{'Head'}->get('From') || $args{'Head'}->get('Sender');
 +    my @FromObjs = Mail::Address->parse($From);
      my @ToObjs = Mail::Address->parse($args{'Head'}->get('To'));
      my @CcObjs = Mail::Address->parse($args{'Head'}->get('Cc'));
 
 -    foreach my $AddrObj (@ToObjs, @CcObjs) {
 +    foreach my $AddrObj (@FromObjs, @ToObjs, @CcObjs) {
         my $Address = $AddrObj->address;
         $Address = $args{'CurrentUser'}->UserObj->CanonicalizeEmailAddress($Address);
 -       next if ($args{'CurrentUser'}->EmailAddress =~ /^\Q$Address\E$/i);
 +       next if ($args{'CurrentUser'}->EmailAddress and $args{'CurrentUser'}->EmailAddress =~ /^\Q$Address\E$/i);
         next if ($args{'QueueObj'}->CorrespondAddress =~ /^\Q$Address\E$/i);
         next if ($args{'QueueObj'}->CommentAddress =~ /^\Q$Address\E$/i);
         next if (RT::EmailParser->IsRTAddress($Address));
 @@ -746,6 +750,7 @@
      my $Ticket = RT::Ticket->new($CurrentUser);
 
      # {{{ If we don't have a ticket Id, we're creating a new ticket
 +    my $new_ticket = 1;
      if ( (!$SystemTicket || !$SystemTicket->Id) &&
             grep /^(comment|correspond)$/, @actions ) {
 
 @@ -784,6 +789,8 @@
         $args{'ticket'} = $id;
 
          # }}}
 +    } else {
 +      $new_ticket = 0;
      }
 
      $Ticket->Load( $args{'ticket'} );
 @@ -799,6 +806,41 @@
          return ( 0, $message );
      }
 
 +    # JAS - Add Ticket CCs for followups to current tickets also:
 +    #     - Allow the CurrentUser to be added if they are not already on this ticket list.
 +    if (not $new_ticket and $RT::ParseFollowupMessageForTicketCcs) {
 +      my @Cc = ParseCcAddressesFromHead(Head        => $head,
 +                                       CurrentUser => $RT::SystemUser,  # Don't ignore the CurrentUser.
 +                                       QueueObj    => $SystemQueueObj,
 +                                      );
 +      foreach (@Cc) {
 +       my $user = RT::User->new($RT::SystemUser);
 +       $user->LoadByEmail($_);
 +       my $principal;
 +       $principal = $user->PrincipalId if $user->Id;
 +       # Only add people to this ticket if they are not already a watcher of the ticket or queue:
 +       if (not ($Ticket->IsWatcher(Type => 'Requestor', Email => $_)
 +                or $Ticket->IsWatcher(Type => 'Cc', Email => $_)
 +                or $Ticket->IsWatcher(Type => 'AdminCc', Email => $_)
 +                or $Ticket->QueueObj->IsWatcher(Type => 'Cc', PrincipalId => $principal)
 +                or $Ticket->QueueObj->IsWatcher(Type => 'AdminCc', PrincipalId => $principal))) {
 +         # NOTE: Passing both the Email address & PrincipalId for that address to the RT::Ticket:AddWatcher
 +         #       function will allow it to pass the ACL checks with only Watch rights, otherwise ModifyTicket
 +         #       rights will be needed since it assumes that someone is trying to add another person.
 +         #       See: RT/Ticket_Overlay.pm:AddWatcher for more info.
 +         my ($ret, $msg) = $Ticket->AddWatcher(Type  => 'Cc',
 +                                               Email => $_,
 +                                               PrincipalId => $principal,
 +                                              );
 +         if ($ret) {
 +           $RT::Logger->info("New Cc watcher added to ticket #". $Ticket->Id .": ". $_);
 +         } else {
 +           $RT::Logger->error("Failed to add new Cc watcher to ticket #". $Ticket->Id .": ". $_ ." - ". $msg);
 +         }
 +       }
 +      }
 +    }
 +
      # }}}
      foreach my $action( @actions ) {
          #   If the action is comment, add a comment.