[Rt-devel] Re: [rt-users] sending ticket attachments via soap

Roy El-Hames rfh at pipex.net
Fri Sep 29 07:48:35 EDT 2006


Yeah sure attached .. Its basic and far from perfect, it was my first 
attempt writing soap service and just to serve my immediate needs, I 
Just hope somebody can use it as a base and develop a full service that 
can be used by .net and jave clients, The REST interface is very good, 
but all the rage (what managers like) is SOAP and web services etc  ..
Please bare in mind it includes some of our custom status'es , which you 
may have to remove ..
Regards;
Roy


Torsten Brumm wrote:
> Hi Roy,
>
> can you also share this soap services, the "old" one from BPS seams to be
> outdated or only for rt2x i think.
>
> Torsten
>
> 2006/9/8, Roy El-Hames <rfh at pipex.net>:
>>
>> rt-3.6.1/Apache2
>> I've written a simple soap service  for rt that can communicate with
>> windows .net client via a wsdl file, however I can't find the best way
>> to send attachments, as rt will expect a mime object that combine the
>> update/create text with the attachment, I'll need to create this object
>> on the server (rt side), can anyone suggest the best way to do this, the
>> .net developers would prefer to send attachments separate as a DIME
>> Referenced binary.
>> Thanks;
>> Roy
>> _______________________________________________
>> http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-users
>>
>> Community help: http://wiki.bestpractical.com
>> Commercial support: sales at bestpractical.com
>>
>>
>> Discover RT's hidden secrets with RT Essentials from O'Reilly Media.
>> Buy a copy at http://rtbook.bestpractical.com
>>
>
>
>

-------------- next part --------------
#!/usr/bin/perl

use lib ("/opt/rt3/local/html/SOAP");
use RTSoap;
use SOAP::Transport::HTTP;

SOAP::Transport::HTTP::CGI
  -> dispatch_to('/opt/rt3/local/html/SOAP','RTSoap')
  -> handle;
-------------- next part --------------
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="RTSoap" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="urn:RTSoap"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsd-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
 xmlns:http="http://schemas.xmlsoap.org/wsdl/" targetNamespace="urn:RTSoap"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <xsd:schema elementFormDefault="qualified" targetNamespace="urn:RTSoap">
      <xsd:element name="GetTicket">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element minOccurs="0" maxOccurs="1" name="Requester" type="xsd:string" />
            <xsd:element minOccurs="1" maxOccurs="1" name="TicketId" type="xsd:int" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

      <xsd:element name="GetTicketsByRequestor">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element minOccurs="1" maxOccurs="1" name="Requester" type="xsd:string" />
            <xsd:element minOccurs="1" maxOccurs="1" name="Status" type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

     <xsd:element name="CreateTicket">
      <xsd:complexType>
                <xsd:sequence>
                        <xsd:element name="Requester" type="xsd:string" />
                        <xsd:element name="Cc" type="xsd:string" />
                        <xsd:element name="Subject" type="xsd:string" />
                        <xsd:element name="Queue" type="xsd:string" />
                        <xsd:element name="Attachment" type="xsd:string" />
                        <xsd:element name="Text" type="xsd:string" />
                </xsd:sequence>
       </xsd:complexType>
    </xsd:element>

     <xsd:element name="UpdateTicket">
      <xsd:complexType>
                <xsd:sequence>
                        <xsd:element name="Requester" type="xsd:string" />
                        <xsd:element name="Cc" type="xsd:string" />
                        <xsd:element name="TicketId" type="xsd:int" />
                        <xsd:element name="Subject" type="xsd:string" />
                        <xsd:element name="Attachment" type="xsd:string" />
                        <xsd:element name="Text" type="xsd:string" />
                        <xsd:element name="Status" type="xsd:string"/>
                </xsd:sequence>
      </xsd:complexType>
    </xsd:element>

      <xsd:element name="GetTicketResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element minOccurs="0" maxOccurs="1" name="Basics" type="tns:Basics" />
            <xsd:element minOccurs="0" maxOccurs="1" name="Updates" type="tns:Updates" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

      <xsd:element name="GetTicketsByRequestorResponse">
        <xsd:complexType>
          <xsd:sequence>
                <xsd:element minOccurs="0" maxOccurs="1" name="TicketsList" type="tns:TicketsList" />
          </xsd:sequence>
       </xsd:complexType>
      </xsd:element>

      <xsd:element name="CreateTicketResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element minOccurs="0" maxOccurs="1" name="TicketId" type="tns:TicketId" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

      <xsd:element name="UpdateTicketResponse">
        <xsd:complexType>
          <xsd:sequence>
                <xsd:element minOccurs="0" maxOccurs="1" name="UpdateStatus" type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

     <xsd:complexType name="TicketId">
        <xsd:sequence>
         <xsd:element minOccurs="1" maxOccurs="1" name="TicketId" type="xsd:string" />
        </xsd:sequence>
     </xsd:complexType>

      <xsd:complexType name="Basics">
        <xsd:sequence>
          <xsd:element minOccurs="1" maxOccurs="1" name="TicketId" type="xsd:string" />
          <xsd:element minOccurs="0" maxOccurs="1" name="Subject" type="xsd:string" />
          <xsd:element minOccurs="0" maxOccurs="1" name="Status" type="xsd:string" />
          <xsd:element minOccurs="0" maxOccurs="1" name="LastUpdateTime" type="xsd:string" />
          <xsd:element minOccurs="0" maxOccurs="1" name="ResolvedTime" type="xsd:string" />
          <xsd:element minOccurs="0" maxOccurs="1" name="Requesters" type="xsd:string" />
        </xsd:sequence>
      </xsd:complexType>

      <xsd:complexType name="Update">
        <xsd:sequence>
                <xsd:element minOccurs="0" name="TransactionCreator" type="xsd:string" />
                <xsd:element minOccurs="0" name="TransactionCreated" type="xsd:string" />
                <xsd:element minOccurs="0" name="Correspondence" type="xsd:string" />
        </xsd:sequence>
      </xsd:complexType>

      <xsd:complexType name="Updates">
        <xsd:sequence>
               <xsd:element minOccurs="0" maxOccurs="unbounded" name="Update" type="tns:Update" />
        </xsd:sequence>
      </xsd:complexType>

      <xsd:complexType name="TicketParams">
        <xsd:sequence>
                <xsd:element minOccurs="0" name="TicketId" type="xsd:string" />
                <xsd:element minOccurs="0" name="Subject" type="xsd:string" />
                <xsd:element minOccurs="0" name="Status" type="xsd:string" />
        </xsd:sequence>
      </xsd:complexType>

      <xsd:complexType name="TicketsList">
        <xsd:sequence>
                <xsd:element minOccurs="0" maxOccurs="unbounded" name="TicketParams" type="tns:TicketParams" />
        </xsd:sequence>
      </xsd:complexType>

    </xsd:schema>
  </wsdl:types>
 <wsdl:message name="GetTicketSoapIn">
    <wsdl:part name="parameters" element="tns:GetTicket" />
  </wsdl:message>
  <wsdl:message name="GetTicketSoapOut">
    <wsdl:part name="parameters" element="tns:GetTicketResponse" />
  </wsdl:message>

  <wsdl:message name="GetTicketsByRequestorSoapIn">
    <wsdl:part name="parameters" element="tns:GetTicketsByRequestor" />
  </wsdl:message>
  <wsdl:message name="GetTicketsByRequestorSoapOut">
    <wsdl:part name="parameters" element="tns:GetTicketsByRequestorResponse" />
  </wsdl:message>

  <wsdl:message name="CreateTicketSoapIn">
    <wsdl:part name="parameters" element="tns:CreateTicket" />
  </wsdl:message>
  <wsdl:message name="CreateTicketSoapOut">
    <wsdl:part name="parameters" element="tns:CreateTicketResponse" />
  </wsdl:message>

  <wsdl:message name="UpdateTicketSoapIn">
    <wsdl:part name="parameters" element="tns:UpdateTicket" />
  </wsdl:message>
  <wsdl:message name="UpdateTicketSoapOut">
    <wsdl:part name="parameters" element="tns:UpdateTicketResponse" />
  </wsdl:message>

  <wsdl:portType name="ServiceSoap">

    <wsdl:operation name="GetTicket">
      <wsdl:input message="tns:GetTicketSoapIn" />
      <wsdl:output message="tns:GetTicketSoapOut" />
    </wsdl:operation>

    <wsdl:operation name="GetTicketsByRequestor">
      <wsdl:input message="tns:GetTicketsByRequestorSoapIn" />
      <wsdl:output message="tns:GetTicketsByRequestorSoapOut" />
    </wsdl:operation>

   <wsdl:operation name="CreateTicket">
      <wsdl:input message="tns:CreateTicketSoapIn" />
      <wsdl:output message="tns:CreateTicketSoapOut" />
    </wsdl:operation>

   <wsdl:operation name="UpdateTicket">
      <wsdl:input message="tns:UpdateTicketSoapIn" />
      <wsdl:output message="tns:UpdateTicketSoapOut" />
    </wsdl:operation>

  </wsdl:portType>

  <wsdl:binding name="ServiceSoap" type="tns:ServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />

    <wsdl:operation name="GetTicket">
      <soap:operation soapAction="urn:RTSoap/GetTicket" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="GetTicketsByRequestor">
      <soap:operation soapAction="urn:RTSoap/GetTicketsByRequestor" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="CreateTicket">
      <soap:operation soapAction="urn:RTSoap/CreateTicket" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

   <wsdl:operation name="UpdateTicket">
      <soap:operation soapAction="urn:RTSoap/UpdateTicket" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

  </wsdl:binding>
  <wsdl:binding name="ServiceSoap12" type="tns:ServiceSoap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />

    <wsdl:operation name="GetTicket">
      <soap12:operation soapAction="urn:RTSoap/GetTicket" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="GetTicketsByRequestor">
      <soap12:operation soapAction="urn:RTSoap/GetTicketsByRequestor" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="CreateTicket">
      <soap12:operation soapAction="urn:RTSoap/Create" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  <wsdl:operation name="UpdateTicket">
      <soap12:operation soapAction="urn:RTSoap/UpdateTicket" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>

 </wsdl:binding>
  <wsdl:service name="Service">
    <wsdl:port name="ServiceSoap" binding="tns:ServiceSoap">
      <soap:address location="http://YOURRTADDRESS/res.cgi" />
    </wsdl:port>
    <wsdl:port name="ServiceSoap12" binding="tns:ServiceSoap12">
      <soap12:address location="http://YOURRTADDRESS/res.cgi" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>


-------------- next part --------------
package RTSoap ;

use lib ( "/opt/rt3/lib", "/opt/rt3/local/lib" );
use RT;
use RT::Ticket;
use RT::Users;
CleanEnv;
RT::LoadConfig;
RT::Init;
our @ISA = qw( SOAP::Server::Parameters );

sub new {
        $self = shift;
        my $class = ref($self) || $self;
        bless {_tic => shift} => $class;
        return $class;
}

sub Hello {
        ### test function ##is soap lite working
        my $self = shift;
        my ($string) = @_;
        return "Hello " . $string;
}

sub RT_User {
        my ($address) = shift;
        unless ($address) {
                return (undef);
        }
        my $user = RT::CurrentUser->new();
        $user->LoadByEmail($address);
        unless ($user->Id){
                return undef;
        }
        return $user;
}

sub GetTicketsByRequestor {
        #### you get a requester and may get status resolved
        ## if you get status = resolved only return a list of resolved tickets else return all non resolved tickets for this requestor

        my $self = shift;
        my %args = %{pop->method};
        my $requestor = $args{'Requester'};
        my $status = $args{'Status'};
        my $error = undef;

        ## Get user
        my $CurrentUser = RT_User($requestor);
        if (!$CurrentUser) {
                $error = "Not RT user, verify email address";
                die $error;
        }
        $RT::Logger->error("Web service invoked do I get back here $requestor");
        my $tickets = new RT::Tickets($CurrentUser);
        if (!$tickets) {
                $error = "No tickets of this status for this user";
                die $error;
        }
        my @collection;
        $tickets->LimitWatcher(TYPE => 'Requestor', VALUE =>$requestor);
        if ($status =~ /resolved/) {
                $tickets->LimitStatus(VALUE => "resolved");
                $tickets->LimitStatus(VALUE => "completed");
        } else {
                $tickets->LimitStatus(VALUE => "open");
                $tickets->LimitStatus(VALUE => "new");
                $tickets->LimitStatus(VALUE => "stalled");
                $tickets->LimitStatus(VALUE => "re-opened");
                $tickets->LimitStatus(VALUE => "monitored");
        }
        $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
        while (my $ticket = $tickets->Next) {
                my @list;
                @list = (
                        SOAP::Data->name("TicketParams" => \SOAP::Data->value(
                                SOAP::Data->name('TicketId')->value($ticket->Id()),
                                SOAP::Data->name('Subject')->value($ticket->Subject()),
                                SOAP::Data->name('Status')->value($ticket->Status())))
                );
                push @collection, at list
        }
        if (!@collection) {
                $error = "Failed to retrieve ticket list ";
                die $error;
        }
        return (
                SOAP::Data->name("TicketsList" => \SOAP::Data->value(
                        SOAP::Data->name('CallItWhatEver')->value(@collection)))
        );

}

sub GetTicket(){
        ### you get a ticket id return the ticket providing the supplied requestor is in this ticket requesters string
        use RT::Transactions;
        my $self = shift;
        my %args = %{pop->method};
        my $requestor = $args{'Requester'};
        my $ticketId = $args{'TicketId'};
        my $error = undef;
### debug
#       $RT::Logger->error("Web service invoked and my requestor is $requestor");
#####
        my @collection;
        my $CurrentUser = RT_User($requestor);
        if (!$CurrentUser) {
                $error = "Not RT user, verify email address";
                die $error;
        }
        my $ticket = new RT::Ticket($CurrentUser,$self->{_tic});
        $ticket->Load($ticketId);
        unless ( $ticket->id ) {
                $error = "Error loading ticket, maybe invalid ticket id" ;
                die $error;
        }
        if ($ticket->Id()){
                unless ($ticket->IsWatcher(Type => 'Requestor', PrincipalId => $CurrentUser->PrincipalId)) {
                        $error = "Permission denied. $requestor is not a requestor for this ticket";
                        die $error;
                }
                $Tid = $ticket->Id();
                $TSubject = $ticket->Subject();
                $TStatus = $ticket->Status();
                $TRequestors = $ticket->Requestors->MemberEmailAddressesAsString;
                $TLastUpdate = $ticket->LastUpdated;
                $TResolved = $ticket->Resolved;
                my $trans = RT::Transactions->new($RT::SystemUser);
                $trans->LimitToTicket($Tid);
                $trans->Limit(
                        FIELD    => 'Type',
                        OPERATOR => '=',
                        VALUE    => "Correspond"
                   );
                   $trans->Limit(
                        FIELD    => 'Type',
                        OPERATOR => '=',
                        VALUE    => "Create"
                   );
                while (my $tran = $trans->Next ) {
                        my $attachments = RT::Attachments->new($RT::SystemUser);
                        $attachments->Limit(FIELD    => 'TransactionId',
                                            OPERATOR => '=',
                                            VALUE    => $tran->Id()
                        );
                        $attachments->Limit(FIELD    => 'ContentType',
                                        OPERATOR => '=',
                                        VALUE    => 'text/plain'
                        );
                        $attachments->Limit(FIELD    => 'Content',
                                        OPERATOR => '!=',
                                        VALUE    => ''
                        );
                        my ($update, at updates) ;
                        while (my $attachment = $attachments->Next) {
                                my $aid = $attachment->Id() ;
                                my $atid = $attachment->TransactionId() ;
                                my $acontent = $attachment->Content();
                                $update = (
                                        SOAP::Data->type('string')->name('Correspondence')->value($acontent)
                                );
                         push @updates,$update ;
                        }
                        my @t = (
                            SOAP::Data->name("Update" => \SOAP::Data->value(
                                        SOAP::Data->type('string')->name('TransactionCreator')->value($tran->CreatorObj->Name),
                                        SOAP::Data->type('string')->name('TransactionCreated')->value($tran->Created),
                                        SOAP::Data->type('complexType')->name('Correspondence')->value(@updates)
                                        ))
                        );
                        push  @collection, at t ;
                }
        } else {
                $error = "Error loading ticket updates";
                die $error;
        }
        # format SOAP::Data Object and return
        return (
                SOAP::Data->name('Basics' => \SOAP::Data->value(
                        SOAP::Data->name('TicketId')->value($Tid),
                        SOAP::Data->name('Subject')->value($TSubject),
                        SOAP::Data->name('Status')->value($TStatus),

                        SOAP::Data->name('LastUpdateTime')->value($TLastUpdate),
                        SOAP::Data->name('ResolvedTime')->value($TResolved),
                        SOAP::Data->name('Requesters')->value($TRequestors))),
                SOAP::Data->name('Updates' => \SOAP::Data->value(
                        SOAP::Data->name('CallItWhatEver')->value(@collection)))
        );
}

sub CreateTicket {
        #### attachments handling is rubbish ... need looking at later 
        use MIME::Entity;
        my $MimeMessage;
        my $self = shift;
        my %args = %{pop->method};
        my $requestor = $args{'Requester'};
        my $cc = $args{'Cc'};
        my $queue = $args{'Queue'};
        my $subject = $args{'Subject'};
        my $txt = $args{'Text'};
        my $attach = $args{'Attachment'};
###### for debug purposes ###
        $RT::Logger->error("SOAPING:do I get text? ($txt)");
        if ($attach) {
                 $RT::Logger->error("SOAPING:I have attachment");
        }

############
        my $CurrentUser = RT_User($requestor);
        if (!$CurrentUser) {
                 $CurrentUser = $RT::SystemUser ; ### we need to create tickets for new users as well
        }

        if ($attach) {
                $MimeMessage = $attach;
        } else {
                $Mime = MIME::Entity->build(
                              From => $requestor,
                              Subject =>$subject,
                              Cc => $cc,
                              Type => 'text/plain',
                              Data => $txt
                        );
                 $MimeMessage = $Mime->stringify();
        }


        my $newticket = new RT::Ticket($CurrentUser);
        my $parser = RT::EmailParser->new();
        $parser->ParseMIMEEntityFromScalar($MimeMessage);
        #$parser->ParseMIMEEntityFromScalar($attach);

        my %create_args = (
                Queue => $queue,
                Requestor => $requestor,
                Cc => $cc,
                Subject => $subject,
                MIMEObj => $parser->Entity
                );

        my ( $id, $Trans, $ErrMsg ) = $newticket->Create(%create_args);
        unless ( $id && $Trans ) {
                die $ErrMsg ;
        }
                    return (SOAP::Data->name('TicketId' => \SOAP::Data->value(
                              SOAP::Data->name('TicketId')->value($id))));
}

sub UpdateTicket {
        ### only update if the supplied requester is the ticket requester 
        ### attachments attchments attachments 
        use MIME::Entity;
        my $MimeMessage;
        my $self = shift;
        my %args = %{pop->method};
        my $txt = $args{'Text'};
        my $attach = $args{'Attachment'};
        my $CurrentUser = RT_User($args{'Requester'});
        my $error = undef;
        if (!$CurrentUser) {
                $error = "Not RT user, verify email address";
                die $error;
        }

        if ($attach && $attach != '') {
                $MimMessage = $attach;
        } else {
                $Mime = MIME::Entity->build(
                              From => $requestor,
                              Subject =>$subject,
                              Cc => $cc,
                              Type => 'text/plain',
                              Data => $txt
                        );
                 $MimeMessage = $Mime->stringify();
        }

        my $ticket = new RT::Ticket($CurrentUser);
        $ticket->Load($args{'TicketId'}) ;
        unless ( $ticket->id ) {
                $error = "Error loading ticket, maybe invalid ticket id";
                die $error;
        }
        unless ($ticket->IsWatcher(Type => 'Requestor', PrincipalId => $CurrentUser->PrincipalId)) {
                        $error = "Permission denied. $requestor is not a requestor for this ticket";
                        die $error;
        }
        my $parser = RT::EmailParser->new();
        $parser->ParseMIMEEntityFromScalar($MimeMessage);
        my ($val,$msg);
        if ( $args{'Status'} && $args{'Status'} ne $ticket->Status ) {
                ( $val, $msg ) = $ticket->SetStatus( $args{'Status'} );
                if ($val == 0) {
                        $msg = "Failed to update status";
                        die $msg;
                }
        }
        if ($MimeMessage) {
                ( $val, $msg ) = $ticket->Correspond( MIMEObj => $parser->Entity,
                                                        CcMessageTo  => $args{'Cc'});
                if ($val == 0) {
                        $msg = "Failed to update ticket";
                        die $msg;
                }
        }
        return (SOAP::Data->name('UpdateStatus')->value("OK"));
}
1;





More information about the Rt-devel mailing list