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 <[EMAIL PROTECTED]>:
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: [EMAIL PROTECTED]
Discover RT's hidden secrets with RT Essentials from O'Reilly Media.
Buy a copy at http://rtbook.bestpractical.com
#!/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;<?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>
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,@list
}
if ([EMAIL PROTECTED]) {
$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,@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,@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;
_______________________________________________
http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-users
Community help: http://wiki.bestpractical.com
Commercial support: [EMAIL PROTECTED]
Discover RT's hidden secrets with RT Essentials from O'Reilly Media.
Buy a copy at http://rtbook.bestpractical.com