Difference between revisions of "AddWatchersOnCorrespond"

From Request Tracker Wiki
Jump to navigation Jump to search
m
(BUGFIX: add CreatorEmailAddr as lower case. Check for bounce addresses lower case.)
 
(7 intermediate revisions by 2 users not shown)
Line 5: Line 5:
In our RT setup, we have a group named '''general''' which contains all admins for our site. If the user this [[Scrip]] is going to add as a [[Watcher]] to the ticket is also a member of the '''general''' group, then the Scrip will add them as an [[AdminCC]] [[Watcher]] instead of a [[CC]] [[Watcher]]. It should be fairly easy for others who do not need this feature to remove or modify this [[Scrip]] accordingly.
In our RT setup, we have a group named '''general''' which contains all admins for our site. If the user this [[Scrip]] is going to add as a [[Watcher]] to the ticket is also a member of the '''general''' group, then the Scrip will add them as an [[AdminCC]] [[Watcher]] instead of a [[CC]] [[Watcher]]. It should be fairly easy for others who do not need this feature to remove or modify this [[Scrip]] accordingly.


I wrote this [[Scrip]] to replace the patch we used to make to the RT Email Interface code, called [[ParseFollowupMessageForTicketCcs]]. Accordingly, it carries the same security warning about allowing basically '''anyone''' to add themselves to '''any''' ticket, simply by sending an appropriately formatted email. Some RT sites might not want this behavior, but it is necessary for us.
I wrote this [[Scrip]] to replace the patch we used to make to the RT Email Interface code, called [[ParseFollowupMessageForTicketCcs]]. Accordingly, it carries the same security warning about allowing basically '''anyone''' to add themselves to '''any''' ticket, simply by sending an appropriately formatted email. Some RT sites might not want this behaviour, but it is necessary for us.
 
* [[AddWatchersOnCorrespondDomains]] is a modified version of this Scrip which is more restrictive by domain.


Changelog
Changelog


2012-01-01: Fixed a bug in which the owner of the ticket would have been added as a Cc: for every reply he made. (HaimDimer)
2012-01-01: Fixed a bug in which the owner of the ticket would have been added as a Cc: for every reply he made. (HaimDimer)
2022-12-06: Populate RealName from email header when creating new user. (RT inserts the user's email address in the "phrase" part of the From: header if RealName is empty. This fix prevents emails bouncing because a mail provider's anti-spoofing policy rejects mail with an email address in the "phrase" section of From:/Cc: headers. )
2023-05-03: (RobL) BUGFIX: add CreatorEmailAddr as lower case. Check for bounce addresses lower case.


----
----
Line 41: Line 47:
# Extract a list of people associated with this transaction:
# Extract a list of people associated with this transaction:
#  - including the transaction creator, and if it is an email, the sender and recipients of that email
#  - including the transaction creator, and if it is an email, the sender and recipients of that email
my @People = ($EmailAddr);
my %People;
my $CreatorEmailAddr = lc $self->TransactionObj->CreatorObj->EmailAddress;
my $CreatorRealName  = $self->TransactionObj->CreatorObj->RealName;
$People{$CreatorEmailAddr}{RealName} = GetFullName($CreatorEmailAddr,$CreatorRealName);
 
foreach my $h (qw(From To Cc)) {
foreach my $h (qw(From To Cc)) {
     my $header = $Transaction->Attachments->First->GetHeader($h);
     my $header = $Transaction->Attachments->First->GetHeader($h);
Line 52: Line 62:
         # Ignore any email address that looks like one for ANY of our queues:
         # Ignore any email address that looks like one for ANY of our queues:
         next if RT::EmailParser->IsRTAddress($addr);
         next if RT::EmailParser->IsRTAddress($addr);
         $RT::Logger->debug("$scrip: Ticket #$Id correspondence contains header - $h: $addr");
        push @People, $addr;
        # Get phrase from address header for full name: "Fred Bloggs" <fred@example.com>
        # (Extract Fred Bloggs to fullname.) Clean up. If nothing suitable then make something from email.
        my $fullname = GetFullName($addr,$addrobj->phrase);
        $People{$addr}{RealName} = $fullname;
         $RT::Logger->debug("$scrip: Ticket #$Id correspondence contains header - $h: $addr $fullname");
     }
     }
}
}
Line 62: Line 76:


# Now check if each user is already watching the ticket or queue:
# Now check if each user is already watching the ticket or queue:
foreach my $addr (@People) {
foreach my $addr (sort keys %People) {
     my $User = RT::User->new($RT::SystemUser);
 
     $User->LoadOrCreateByEmail($addr);
    next if ($addr =~ /^(postmaster|root|mailer-daemon)\@/);
 
     my $User = RT::User->new( $RT::SystemUser );
     $User->LoadOrCreateByEmail(
        RealName    => $People{$addr}{RealName},
        EmailAddress => $addr,
        Comments    => "Autocreated by $scrip",
    );
 
     my $Name = $User->Name;
     my $Name = $User->Name;
     my $Principal = $User->PrincipalId;
     my $Principal = $User->PrincipalId;
Line 73: Line 95:
             $Ticket->IsWatcher(Type => 'Requestor', PrincipalId => $Principal) or
             $Ticket->IsWatcher(Type => 'Requestor', PrincipalId => $Principal) or
             $Ticket->IsOwner($User) )) {
             $Ticket->IsOwner($User) )) {
         # If the user is a member of the experts group, then add them as an AdminCc, otherwise as a nor
         # If the user is a member of the experts group, then add them as an AdminCc, otherwise as a Cc:
         my $type = 'Cc';
         my $type = 'Cc';
         $type = 'AdminCc' if $Experts->HasMember($User->PrincipalObj);
         $type = 'AdminCc' if $Experts->HasMember($User->PrincipalObj);
Line 79: Line 101:
         my ($ret, $msg) = $Ticket->AddWatcher(Type  => $type, PrincipalId => $Principal);
         my ($ret, $msg) = $Ticket->AddWatcher(Type  => $type, PrincipalId => $Principal);
         if ($ret) {
         if ($ret) {
             $RT::Logger->info("$scrip: New $type watcher added to ticket #$Id: $addr (#$Principal)");
             $RT::Logger->info("$scrip: New $type watcher added to ticket #$Id: $addr $fullname (#$Principal)");
         } else {
         } else {
             $RT::Logger->error("$scrip: Failed to add new $type watcher to ticket #$Id: $addr (#$Princi
             $RT::Logger->error("$scrip: Failed to add new $type watcher to ticket #$Id: $addr (#$Principal) - $msg");
         }
         }
     }
     }
}
sub GetFullName {
    # Get a nicely formatted name for RT RealName Field:
    # If fullname is blank, make something up from the
    # local_part of the email address: "fred.bloggs@..." -> "Fred Bloggs".
    # Do not allow fullname to contain "@".
    my ($addr,$fullname) = @_;
    my ($local_part,$domain) = split('@', $addr);
    if (($fullname eq '') || ($fullname =~ /\@/)) {
      $fullname = $local_part;
      $fullname =~ s/[\._-]/ /g;
      $fullname =~ s/(\w+)/\u$1/g;
    }
    $fullname =~ s/^[\"\']|[\"\']$//g; # strip leading/trailing " or '
    $fullname =~ s/^\s+|\s+$//g; # strip leading/trailing spaces
    return $fullname;
}
}


Line 92: Line 137:


----
----
[[Category:RT Action]]

Latest revision as of 07:47, 3 May 2023

AddWatchersOnCorrespond

This RT Scrip will add the person making the correspondence as a Watcher to the ticket if they are not already a Watcher, also, if the transaction originated from an email message, the script will scan the email headers and add all other recipients to the ticket as Watchers (if they are not yet Watchers). This can be used to complement the ParseNewMessageForTicketCcs SiteConfig option, which is part of the EmailInterface and does the same thing when tickets are created.

In our RT setup, we have a group named general which contains all admins for our site. If the user this Scrip is going to add as a Watcher to the ticket is also a member of the general group, then the Scrip will add them as an AdminCC Watcher instead of a CC Watcher. It should be fairly easy for others who do not need this feature to remove or modify this Scrip accordingly.

I wrote this Scrip to replace the patch we used to make to the RT Email Interface code, called ParseFollowupMessageForTicketCcs. Accordingly, it carries the same security warning about allowing basically anyone to add themselves to any ticket, simply by sending an appropriately formatted email. Some RT sites might not want this behaviour, but it is necessary for us.

Changelog

2012-01-01: Fixed a bug in which the owner of the ticket would have been added as a Cc: for every reply he made. (HaimDimer)

2022-12-06: Populate RealName from email header when creating new user. (RT inserts the user's email address in the "phrase" part of the From: header if RealName is empty. This fix prevents emails bouncing because a mail provider's anti-spoofing policy rejects mail with an email address in the "phrase" section of From:/Cc: headers. )

2023-05-03: (RobL) BUGFIX: add CreatorEmailAddr as lower case. Check for bounce addresses lower case.


Description: AddWatchersOnCorrespond

Condition: On Correspond

Action: User Defined

Template: Global template: Blank

Stage: TransactionBatch

Custom condition:

Custom action preparation code: return 1;

Custom action cleanup code:


# Get some info:
my $scrip = 'Scrip:AddWatchersOnCorrespond';
my $Transaction = $self->TransactionObj;
my $EmailAddr = $self->TransactionObj->CreatorObj->EmailAddress;
my $Queue = $self->TicketObj->QueueObj;
my $Ticket = $self->TicketObj;
my $Id = $self->TicketObj->id;

# Extract a list of people associated with this transaction:
#  - including the transaction creator, and if it is an email, the sender and recipients of that email
my %People;
my $CreatorEmailAddr = lc $self->TransactionObj->CreatorObj->EmailAddress;
my $CreatorRealName  = $self->TransactionObj->CreatorObj->RealName;
$People{$CreatorEmailAddr}{RealName} = GetFullName($CreatorEmailAddr,$CreatorRealName);

foreach my $h (qw(From To Cc)) {
    my $header = $Transaction->Attachments->First->GetHeader($h);
    my @addr = Mail::Address->parse($header);
    foreach my $addrobj (@addr) {
        my $addr = lc $RT::Nobody->UserObj->CanonicalizeEmailAddress($addrobj->address);
        # Ignore the specific addresses for this queue:
        next if lc $Queue->CorrespondAddress eq $addr;
        next if lc $Queue->CommentAddress eq $addr;
        # Ignore any email address that looks like one for ANY of our queues:
        next if RT::EmailParser->IsRTAddress($addr);
 
        # Get phrase from address header for full name: "Fred Bloggs" <fred@example.com> 
        # (Extract Fred Bloggs to fullname.) Clean up. If nothing suitable then make something from email.
        my $fullname = GetFullName($addr,$addrobj->phrase);
        $People{$addr}{RealName} = $fullname;
        $RT::Logger->debug("$scrip: Ticket #$Id correspondence contains header - $h: $addr $fullname");
    }
}

# Lookup the 'experts' (general) group to use below:
my $Experts = RT::Group->new($self->CurrentUser);
$Experts->LoadUserDefinedGroup('general');

# Now check if each user is already watching the ticket or queue:
foreach my $addr (sort keys %People) {

    next if ($addr =~ /^(postmaster|root|mailer-daemon)\@/);

    my $User = RT::User->new( $RT::SystemUser );
    $User->LoadOrCreateByEmail(
        RealName     => $People{$addr}{RealName},
        EmailAddress => $addr,
        Comments     => "Autocreated by $scrip",
    );

    my $Name = $User->Name;
    my $Principal = $User->PrincipalId;
    if ( not ($Queue->IsWatcher(Type => 'Cc', PrincipalId => $Principal) or
            $Queue->IsWatcher(Type => 'AdminCc', PrincipalId => $Principal) or
            $Ticket->IsWatcher(Type => 'Cc', PrincipalId => $Principal) or
            $Ticket->IsWatcher(Type => 'AdminCc', PrincipalId => $Principal) or
            $Ticket->IsWatcher(Type => 'Requestor', PrincipalId => $Principal) or
            $Ticket->IsOwner($User) )) {
        # If the user is a member of the experts group, then add them as an AdminCc, otherwise as a Cc:
        my $type = 'Cc';
        $type = 'AdminCc' if $Experts->HasMember($User->PrincipalObj);
        # Add the new watcher now and check for errors:
        my ($ret, $msg) = $Ticket->AddWatcher(Type  => $type, PrincipalId => $Principal);
        if ($ret) {
            $RT::Logger->info("$scrip: New $type watcher added to ticket #$Id: $addr $fullname (#$Principal)");
        } else {
            $RT::Logger->error("$scrip: Failed to add new $type watcher to ticket #$Id: $addr (#$Principal) - $msg");
        }
    }
}

sub GetFullName {

    # Get a nicely formatted name for RT RealName Field:

    # If fullname is blank, make something up from the
    # local_part of the email address: "fred.bloggs@..." -> "Fred Bloggs".
    # Do not allow fullname to contain "@".

    my ($addr,$fullname) = @_;
    my ($local_part,$domain) = split('@', $addr);

     if (($fullname eq '') || ($fullname =~ /\@/)) {
      $fullname = $local_part;
      $fullname =~ s/[\._-]/ /g;
      $fullname =~ s/(\w+)/\u$1/g;
     }

     $fullname =~ s/^[\"\']|[\"\']$//g; # strip leading/trailing " or '
     $fullname =~ s/^\s+|\s+$//g; # strip leading/trailing spaces

    return $fullname;
}

return 1;
# vim:ft=perl: