[rt-devel] How to add custom field

Matthew D. Stock stock at cse.Buffalo.EDU
Tue Mar 30 08:38:23 EST 2004


Kuldeep Singh Tomar writes:
 > How can we add the  value of custom field on submission of mail. I am 
 > using rt3. Basically we are using some interface where we submit the 
 > mail to rt-system and want to use the value of custom fields in our 
 > rtsystem through this interface.

Assuming you mean assign custom field values to tickets and not create new
custom field values...

Here's a patch for 3.0.9 that adds the ability to parse X- headers in
email.  It currently only uses MailFrom authentication.  It will process
several field types, most notably Select custom fields.  Read the patch for
details on use, but here are a couple of examples:

X-owner: stock
X-status: resolved
X-customfoobar: flammable

Jesse, are you interested in taking this as part of 3.0.x or as a contrib?
  -Matt

-- 
Matthew D. Stock <stock at cse.buffalo.edu>
Director of Information Technology
Computer Science and Engineering, University at Buffalo

-------------- next part --------------
diff -ur rt-3-0-9/lib/RT/Interface/Email/Auth/MailFrom.pm rt3/lib/RT/Interface/Email/Auth/MailFrom.pm
--- rt-3-0-9/lib/RT/Interface/Email/Auth/MailFrom.pm	Fri Feb 13 12:31:23 2004
+++ rt3/lib/RT/Interface/Email/Auth/MailFrom.pm	Thu Mar 11 15:45:25 2004
@@ -45,7 +45,17 @@
     }
 
     if ( $CurrentUser->Id ) {
+      my $Queue;
+
+      if (defined($Queue = $args{'Queue'}) &&
+	 $Queue->IsWatcher(Type => 'AdminCC',
+			   PrincipalId => $CurrentUser->PrincipalId)) {
+	$RT::Logger->debug( "Giving elevated privs" );
+	return ( $CurrentUser, 2);
+      } else {
+	$RT::Logger->debug( "Normal privs" );
         return ( $CurrentUser, 1 );
+      }
     }
     
 
diff -ur rt-3-0-9/lib/RT/Interface/Email.pm rt3/lib/RT/Interface/Email.pm
--- rt-3-0-9/lib/RT/Interface/Email.pm	Fri Feb 13 12:31:23 2004
+++ rt3/lib/RT/Interface/Email.pm	Fri Mar 12 14:45:51 2004
@@ -331,6 +331,56 @@
 }
 # }}}
 
+# {{{ ParseActionsFromHead
+
+=head2 ParseActionsFromHead RT::Queue MIME::Header
+
+Return an array of action value pairs.  These pairs should be vetted here,
+since they will be passed on to the Ticket methods.
+
+=cut
+
+sub ParseActionsFromHead {
+    my $QueueObj = shift;
+    my $head = shift;
+    my @actions = ();
+
+    # If we were asked about the status, check to see if it's valid for that
+    # queue.  If not, silently ignore the field.
+    if (my $headerobj = $head->get('X-Status')) {
+      chomp($headerobj);
+      if ($QueueObj->IsValidStatus($headerobj)) {
+	push @actions, 'Status', $headerobj;
+      }
+    }
+
+    # We'll let the ticket code check to make sure it's ok to set the owner.
+    if (my $headerobj = $head->get('X-Owner')) {
+      chomp($headerobj);
+      push @actions, 'Owner', $headerobj;
+    }
+
+    if (my $headerobj = $head->get('X-TimeTaken')) {
+      chomp($headerobj);
+      push @actions, 'TimeTaken', $headerobj;
+    }
+
+    # Sort out the custom field tags for this queue.  We don't have a ticket
+    # yet, so the tests on the values happens later.
+    my $CustomFields = $QueueObj->CustomFields();
+    while (my $CustomField = $CustomFields->Next()) {
+      my $i=0;
+      foreach my $headerobj ($head->get('X-'.$CustomField->Name)) {
+	chomp($headerobj);
+	$RT::Logger->debug("Found customfield $i " . $CustomField->Name);
+	push @actions, $CustomField->Name . "-$i", $headerobj;
+	$i++;
+      }
+    }
+    return @actions;
+}
+# }}}
+
 # {{{ ParseAddressFromHeader
 
 =head2 ParseAddressFromHeader ADDRESS
@@ -361,6 +411,70 @@
 # }}}
 
 
+sub ProcessActions {
+  my $CurrentUser = shift;
+  my $Ticket = shift;
+  my %actions = @_;
+  my %seen;
+  my $CustomFields = $Ticket->QueueObj->CustomFields();
+
+  foreach my $action (keys %actions) {
+    $RT::Logger->debug("Found an $action action");
+    if ($action eq 'Owner') {
+      chomp($actions{$action});
+      $RT::Logger->debug("Setting new owner to " . $actions{$action});
+      my ($success, $msg) = $Ticket->SetOwner($actions{$action}, "Force");
+      if (!$success) {
+	$RT::Logger->debug("SetOwner(): $msg");
+      }
+    }
+
+    if ($action eq 'Status' && $Ticket->Status != $actions{$action}) {
+      $Ticket->SetStatus($actions{$action});
+    }
+
+    my ($cfield, $index) = split('-',$action);
+    while (my $CustomField = $CustomFields->Next) {
+      my $name = $CustomField->Name;
+
+      next if ($cfield ne $name);
+      next if ($CustomField->Type !~ /^Select/);
+
+      # Now that we have a custom field match, we need to make sure the
+      # value is valid.  This is complicated because of the various kinds
+      # of fields.  For the moment, I'm only going to deal with Select
+      # fields, since that's all we use.
+      #
+      # We also assume that if ANY value of a multivalue custom field is
+      # offered, that the complete set will be provided.  In other words, we
+      # empty out the values for that field, and set only the ones that
+      # are in the headers.
+      chomp($actions{$action});
+      my $CustomFieldValues = $CustomField->Values();
+
+      # If we have index 0, nuke all of the existing values.
+      if ($CustomField->Type eq "SelectMultiple" &&
+	  !defined($seen{$CustomField->Name})) {
+	$seen{$CustomField->Name} = 1;
+	$RT::Logger->debug("Starting Delete loop");
+	while (my $value = $CustomFieldValues->Next) {
+          my ($status, $msg) =
+	    $Ticket->DeleteCustomFieldValue(Field => $CustomField->Id,
+					    Value => $value->Name);
+        }
+      }
+
+      while (my $value = $CustomFieldValues->Next) {
+	# Case insensitive match, to be friendly to the user.
+	next if (lc($value->Name) ne lc($actions{$action}));
+	my ($status, $msg) =
+	  $Ticket->AddCustomFieldValue(Field => $CustomField->Id,
+				       Value => $value->Name);
+	last;
+      }
+    }
+  }
+}
 
 =head2 Gateway ARGSREF
 
@@ -503,6 +617,7 @@
     for (@RT::MailPlugins) {
         my $Code;
         my $NewAuthStat;
+
         if ( ref($_) eq "CODE" ) {
             $Code = $_;
         }
@@ -607,6 +722,17 @@
     }
 
     # }}}
+
+    # {{{ If the user has enough privs, process action headers.
+
+    my @actions = ();
+    if ( $AuthStat == 2 ) {
+      $RT::Logger->debug("We have the privs to look for actions!");
+      @actions = ParseActionsFromHead($SystemQueueObj, $head);
+    }
+
+    # }}}
+
     # {{{ Warn someone  if it's a loop
 
     # Warn someone if it's a loop, before we drop it on the ground
@@ -663,7 +789,7 @@
             @Cc = ParseCcAddressesFromHead(
                 Head        => $head,
                 CurrentUser => $CurrentUser,
-                QueueObj    => $SystemQueueObj
+		QueueObj    => $SystemQueueObj
             );
         }
 
@@ -672,7 +798,8 @@
             Subject   => $Subject,
             Requestor => \@Requestors,
             Cc        => \@Cc,
-            MIMEObj   => $Message
+            MIMEObj   => $Message,
+	    @actions
         );
         if ( $id == 0 ) {
             MailError(
@@ -706,11 +833,14 @@
         }
 
         my ( $status, $msg );
+	ProcessActions($CurrentUser, $Ticket, @actions);
         if ( $args{'action'} =~ /^correspond$/ ) {
-            ( $status, $msg ) = $Ticket->Correspond( MIMEObj => $Message );
+            ( $status, $msg ) = $Ticket->Correspond( MIMEObj => $Message,
+						     @actions);
         }
         else {
-            ( $status, $msg ) = $Ticket->Comment( MIMEObj => $Message );
+            ( $status, $msg ) = $Ticket->Comment( MIMEObj => $Message,
+						  @actions);
         }
         unless ($status) {
 


More information about the Rt-devel mailing list