AddWatchersOnCorrespond

From Request Tracker Wiki
Revision as of 13:47, 7 December 2022 by Robl (talk | contribs) (link to AddWatchersOnCorrespondDomains)
Jump to navigation Jump to search

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. )


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 = $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: