Mailing List Archive

[svn] r897 - in RTx-Atom: . html/Atom/0.3 html/Atom/0.3/NoAuth lib/RT lib/RTx t
Author: autrijus
Date: Fri May 14 14:11:01 2004
New Revision: 897

Added:
RTx-Atom/lib/RT/
RTx-Atom/lib/RT/Atom.pm
RTx-Atom/lib/RT/Atom.pod
Removed:
RTx-Atom/lib/RTx/
Modified:
RTx-Atom/ (props changed)
RTx-Atom/Makefile.PL
RTx-Atom/html/Atom/0.3/NoAuth/spec.html
RTx-Atom/html/Atom/0.3/dhandler
RTx-Atom/t/1-basic.t
Log:
----------------------------------------------------------------------
r4886@not: autrijus | 2004-05-14T18:10:50.992251Z

* it's RT::Atom not RTx::Atom now.
* RT auth.
----------------------------------------------------------------------


Modified: RTx-Atom/Makefile.PL
==============================================================================
--- RTx-Atom/Makefile.PL (original)
+++ RTx-Atom/Makefile.PL Fri May 14 14:11:01 2004
@@ -4,7 +4,7 @@

use inc::Module::Install;

-RTx('Atom');
+RTx('RT-Atom');
author('Autrijus Tang <autrijus@autrijus.org>');
abstract('Atom API for RT');
license('perl');

Modified: RTx-Atom/html/Atom/0.3/NoAuth/spec.html
==============================================================================
--- RTx-Atom/html/Atom/0.3/NoAuth/spec.html (original)
+++ RTx-Atom/html/Atom/0.3/NoAuth/spec.html Fri May 14 14:11:01 2004
@@ -2,12 +2,12 @@
require lib;
lib->import($m->base_comp->source_dir . '/../../../../lib');

-require RTx::Atom;
+require RT::Atom;
require Pod::Html;
require File::Temp;

my ($fh, $filename) = File::Temp::tempfile();
-my $infile = $INC{'RTx/Atom.pm'};
+my $infile = $INC{'RT/Atom.pm'};
$infile =~ s/pm$/pod/i;

Pod::Html::pod2html(

Modified: RTx-Atom/html/Atom/0.3/dhandler
==============================================================================
--- RTx-Atom/html/Atom/0.3/dhandler (original)
+++ RTx-Atom/html/Atom/0.3/dhandler Fri May 14 14:11:01 2004
@@ -2,10 +2,10 @@
<%INIT>
require lib;
lib->import($m->base_comp->source_dir . '/../../../lib');
-require RTx::Atom;
+require RT::Atom;

# needs discussion on using MD5(pass) as Digest token
-@RT::AtomAuthenticationMethods = qw( WSSE Basic )
+@RT::AtomAuthenticationMethods = qw( WSSE Basic RT )
unless @RT::AtomAuthenticationMethods;

my $realm = $RT::rtname;
@@ -165,6 +165,12 @@
$nonce_cache->set( $auth_nonce, 1 );
}

+AUTH_RT: {
+ last if $CurrentUser or !$methods{RT} or $atom_client;
+ $m->comp('/Elements/SetupSessionCookie', %ARGS);
+ $CurrentUser = delete $session{CurrentUser};
+}
+
# Now for the dreaded "su anotheruser" feature...
my $su = $r->header_in('X-RT-CurrentUser');
if ($CurrentUser and $su and ($su ne $CurrentUser->Id) and ($su ne $CurrentUser->Name)) {

Added: RTx-Atom/lib/RT/Atom.pm
==============================================================================
--- (empty file)
+++ RTx-Atom/lib/RT/Atom.pm Fri May 14 14:11:01 2004
@@ -0,0 +1,18 @@
+package RT::Atom;
+$RT::Atom::VERSION = '0.01';
+
+use strict;
+
+use XML::Simple;
+use Digest::MD5;
+use Digest::SHA1;
+use MIME::Base64;
+
+*RT::Date::W3CDTF = sub {
+ my $self = shift;
+ my $date = $self->ISO . 'Z';
+ $date =~ s/ /T/;
+ return $date;
+} unless defined &RT::Date::W3CDTF;
+
+1;

Added: RTx-Atom/lib/RT/Atom.pod
==============================================================================
--- (empty file)
+++ RTx-Atom/lib/RT/Atom.pod Fri May 14 14:11:01 2004
@@ -0,0 +1,462 @@
+=head1 NAME
+
+RT::Atom - The RT-Atom API
+
+=head1 DESCRIPTION
+
+This RT extension implements a REST-style web service interface, based
+on the B<Atom draft specification>, version 0.3.
+
+For more information on Atom and REST, please consult the references
+in the L</SEE ALSO> section.
+
+=head2 The RT-Atom URI space
+
+Some example canonical URIs are:
+
+ /Atom/0.3 # FeedURI (Container)
+ /Atom/0.3/RT-Tickets # FeedURI (Container)
+ /Atom/0.3/RT-Tickets # PostURI (Container)
+ /Atom/0.3/RT-Tickets/15 # EditURI (Object)
+ /Atom/0.3/RT-Tickets/15,16,17 # PostURI (ResultSet)
+ /Atom/0.3/RT-Tickets/15.Subject # EditURI (Property)
+ /Atom/0.3/RT-Tickets/15/Transactions # FeedURI (Container)
+
+Note that the C<15> above is the C<Id>; if you want element indice,
+use these URIs instead:
+
+ /Atom/0.3/RT-Users/*0 # EditURI (Object)
+ /Atom/0.3/RT-Users/*-1 # EditURI (Object)
+ /Atom/0.3/RT-Users.Count # EditURI (Property)
+
+A RT-Atom server may also supply alias URIs. Whenever an user request such
+a URI, it is redirected to the canonical URL with a I<301 Moved Permanently>.
+
+Here are some example aliases:
+
+ /Atom # /Atom/0.3
+ /Atom/0.3/tickets # /Atom/0.3/RT-Tickets
+ /Atom/0.3/Tickets # /Atom/0.3/RT-Tickets
+ /Atom/0.3/Ticket/15 # /Atom/0.3/RT-Tickets/15
+ /Atom/0.3/Users/somename # /Atom/0.3/Users/1234
+
+=head2 Sample exchange
+
+Create an C<autrijus> user, then add it to all groups that has C<root>
+as member.
+
+First, the B<RT::Client> code:
+
+ my $rt = RT::Client->new('http://guest:guest@localhost/');
+
+ my $user = $rt->Users->add(
+ Name => 'autrijus',
+ EmailAddress => 'autrijus@example.com',
+ );
+
+ $rt->Groups->search(Members => { Name => 'root' })->update(
+ Members => { add => $user },
+ );
+
+And now the actual requests and responses. First, the Authentication
+part: (The C<Accept> header will be omitted for brevity from now on.)
+
+ HEAD /Atom/0.3
+ Accept: application/x.atom+xml,*/*
+
+ 401 Authorization Required
+ WWW-Authenticate: WSSE realm="localhost", profile="UsernameToken"
+
+Log in and probe the C<Users> collection:
+
+ OPTIONS /Atom/0.3/Users
+ X-WSSE: UsernameToken Username="guest", ...
+
+ 301 Moved Permanently
+ Location: /Atom/0.3/RT-Users
+
+Try again: (The C<X-WSSE> header is generated anew; it will be omitted
+for brevity from now on.)
+
+ OPTIONS /Atom/0.3/Users
+ X-WSSE: UsernameToken Username="guest", ...
+
+ 200 OK
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body Name=""
+ EmailAddress=""
+ ...>
+ ...
+ </body>
+ </content>
+ </entry>
+
+Now create a user. RT-Atom supports two type of payloads for this,
+distinguished by their C<Content-Type> headers. First is AtomEntry:
+
+ POST /Atom/0.3/Users
+ Content-Type: application/x.atom+xml
+
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body Name="autrijus"
+ EmailAddress="autrijus@example.com" />
+ </content>
+ </entry>
+
+Another one is a form post:
+
+ POST /Atom/0.3/Users
+ Content-Type: application/x-www-form-urlencoded
+
+ Name=autrijus&EmailAddress=autrijus@example.com
+
+In both cases, the server will return:
+
+ 303 See Other
+ Location: /Atom/0.3/RT-Users/20
+
+Now we can learn something about the freshly created user:
+
+ GET /Atom/0.3/RT-Users/20
+
+ 200 OK
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body Name="autrijus"
+ EmailAddress="autrijus@example.com"
+ ...>
+ ...
+ </body>
+ </content>
+ </entry>
+
+Next we learn something about Groups:
+
+ OPTIONS /Atom/0.3/Groups
+
+ 301 Moved Permanently
+ Location: /Atom/0.3/RT-Groups
+
+ OPTIONS /Atom/0.3/RT-Groups
+
+ 200 OK
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body Name="" ...>
+ <Members />
+ </body>
+ </content>
+ </entry>
+
+Now we make a query on Groups:
+
+ HEAD /Atom/0.3/RT-Groups?Members-name=root&rows=all
+
+ 200 OK
+ Content-Location: /Atom/0.3/RT-Groups/1,2,3,5,8,13
+
+Before we perform an update on the result set, we again probe
+for its representation:
+
+ OPTIONS /Atom/0.3/RT-Groups/1,2,3,5,8,13
+
+ 200 OK
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body>
+ <Members />
+ </body>
+ </content>
+ </entry>
+
+Finally, the modification and its response:
+
+ POST /Atom/0.3/RT-Groups/1,2,3,5,8,13
+ Content-Type: application/x-www-form-urlencoded
+
+ Members-add=30
+
+The server may respond with this:
+
+ 207 Multiple Status
+ <entry>
+ <content type="multipart/parallel" mode="xml">
+ <body>
+ <response status="200">Member added.</head>
+ <response status="200">Member added.</head>
+ </body>
+ </content>
+ </entry>
+
+=head2 Authentication
+
+The authentication algorithm uses the C<WWW-Authenticate>,
+C<Authorization>, and C<X-WSSE> headers as specified in the Atom
+Authentication Protocol.
+
+However, instead of using plaintext as the shared password between
+client and server, RT-Atom uses this digest function:
+
+ md5_hex(join(':', $username, $realm, md5_hex($password)));
+
+The RT server may choose to support other authentication methods, such
+as C<Basic> or C<Digest>.
+
+=head2 Identity Switching
+
+Once authenticated, the server should check for the C<X-RT-CurrentUser>
+header. If this header is present, it takes one of the following actions:
+
+=over 4
+
+=item If the authenticated user does not have the C<SuperUser> right
+
+The server returns I<401 Authorization Required> without processing the
+request body.
+
+=item If the server cannot find the new user
+
+The server returns I<406 Forbidden> without processing the request body.
+
+=item If the user has the C<SuperUser> right, and a new user is found
+
+The client assumes the identity of the new user specified in the header.
+The request proceeds as usual.
+
+=back
+
+=head2 Content Negotiation
+
+The server understands a number of HTTP headers for content negotiation:
+
+=over 4
+
+=item Accept
+
+Specifies the content type the client is willing to process. A RT-Atom
+client must include C<application/x.atom+xml> in its C<Accept> list.
+
+=item Accept-Charset
+
+The character encoding expected by the client. If unspecified, defaults
+to C<UTF-8>. If the requested encoding cannot represent certain codepoints
+in the response, the server must use XML character references (C<&#xABCD;>)
+instead.
+
+If none of the requested encodings are supported by the server, a I<406
+Not Acceptable> error is returned.
+
+=item Accept-Language
+
+The languages to use in human-readable C<CDATA> parts, notably response texts.
+
+=back
+
+=head1 RESOURCE TYPES
+
+=head2 Container
+
+...
+
+=head2 ResultSet
+
+...
+
+=head2 Object
+
+...
+
+=head2 Property
+
+...
+
+=head1 OPERATIONS
+
+Here is a list of all operations supported by this API, including their
+possible response status codes and meanings:
+
+=head2 Search - I<GET FeedURI>
+
+Search for objects within an container.
+
+Possible query parameters: I<rows> (mandatory), I<page>, I<query>,
+I<columns>. Additional query parameters may also be available.
+
+If entries are found, the C<Content-Location> header is set to a URL
+pointing to the ResultSet.
+
+ 200: Success. Body is the result serialized as an AtomFeed.
+ 400: Request failed. Body is the error message.
+ 404: There is no container matching the specified URI.
+
+=head2 Get - I<GET EditURI>
+
+Retrieve a representation of an object or property.
+
+Possible query parameters: I<expand>.
+
+ 200: Success. Body is the serialized item.
+ 400: Request failed. Body is the error message.
+ 404: There is no object matching the specified URI.
+
+=head2 Set - I<PUT EditURI>
+
+Modifies an object or property with the serialization in the request body.
+
+ 200: Success. Body is the serialized item again.
+ 400: Request failed. Body is the error message.
+ 404: There is no object matching the specified URI.
+
+Clients without I<PUT> support may use I<POST EditURI!PUT> instead.
+
+=head2 Remove - I<DELETE EditURI>
+
+Remove the specified object.
+
+ 200: Successfully deleted. Body is the success message.
+ 400: Request failed. Body is the error message.
+ 404: There is no object matching the specified URI.
+
+Clients without I<DELETE> support may use I<POST EditURI!DELETE> instead.
+
+=head2 Describe - I<OPTIONS [ PostURI | EditURI | FeedURI ]>
+
+On a container's I<PostURI>, returns the schema of objects acceptable by this
+container.
+
+On an object's I<PostURI>, returns the schemata acceptable by it,
+differentiated with the C<type> attribute.
+
+On I<EditURI>, returns the schema of the object or the property, which is a
+I<GET> without actual contents.
+
+On I<FeedURI>, returns the schema of available query parameters and their types.
+
+ 200: Success. Body is the requested schema.
+ 400: Request failed. Body is the error message.
+ 404: There is no container matching the specified URI.
+
+Clients without I<OPTIONS> support may use I<GET AnyURI!OPTIONS> instead.
+
+=head2 Add - I<POST PostURI> (Container)
+
+Create a new object from the AtomEntry in the request's body.
+
+ 200: Created, but the new object has no EditURI. Body is the
+ success message.
+ 303: Created. The 'Location' header is set to the new object's
+ EditURI (for subsequent Get/Update). Body is the success message.
+ 400: Request failed. Body is the error message.
+ 404: There is no container matching the specified URI.
+
+=head2 Update - I<POST PostURI> (Object)
+
+Updates an object.
+
+ 207: Updated. Body is the status code and messages for each update.
+ 400: Request failed. Body is the error message.
+ 404: The specific object is not found, or supports no such post type.
+
+=head1 LINK DISCOVERY
+
+Methods, object membership and properties are all discovered via the
+C<link> tag inside I<AtomFeed> and I<AtomEntry> constructs.
+
+The design goal is to facilitate lazy loading - the client need not
+to follow the link to retrieve any representations immediately; it
+can wait until the first operation is performed on that object, and
+follow the link responsible for that operation.
+
+Whenever the client receives an Atom construct, it may look at each
+C<link> tag. The C<title> attribute is the member name of the link;
+but if it begins with C<_>, then it is a backlink.
+
+The C<href> attribute is the target URI. The C<rel> attribute determines
+the type of the link target:
+
+=over 4
+
+=item service.feed
+
+A Container.
+
+=item service.edit
+
+An Object or Property.
+
+=item service.post
+
+An operation supported by the object that shares the same C<title>.
+If no such object is found, this operation applies to the object itself.
+
+=back
+
+For example, an object's Atom representation may have the following links:
+
+ <link title="Groups"
+ rel="service.feed"
+ href="/Atom/0.3/RT-Groups" />
+ <link title="Groups"
+ rel="service.post"
+ href="/Atom/0.3/RT-Groups" />
+
+The client may then infer these relationships:
+
+=over 4
+
+=item * $obj has a member named I<Groups>.
+
+=item * $obj->Groups is a I<Container>.
+
+=item * $obj->Groups may be called to I<add> an object inside it.
+
+=item * $obj->Groups->add( key => 'value' ) should be translated to this:
+
+ POST /Atom/0.3/RT-Groups
+ Content-Type: application/x-www-form-urlencoded
+
+ key=value
+
+Or this:
+
+ POST /Atom/0.3/RT-Groups
+ Content-Type: application/x.atom+xml
+
+ <entry>
+ <content type="text/xml" mode="xml">
+ <body key="value" />
+ </content>
+ </entry>
+
+=back
+
+=head1 SEE ALSO
+
+Atom Tutorial:
+L<http://www.atomenabled.org/developers/tutorials/api-quick-guide.php>
+
+Atom API Specification (definitions of I<FeedURI>, I<EditURI> and
+I<PostURI>): L<http://www.atomenabled.org/developers/api/atom-api-spec.php>
+
+Atom Format Specification (definitions of I<AtomFeed> and I<AtomEntry>):
+L<http://www.atomenabled.org/developers/syndication/atom-format-spec.php>
+
+Atom Authentication Protocol:
+L<http://www.xml.com/pub/a/2003/12/17/dive.html>
+
+HTTP 1.1 Status codes:
+L<http://www.w3.org/Protocols/rfc2616/rfc2616.html>.
+
+Paul Prescod's REST resources: L<http://www.prescod.net/rest/>
+
+The Atom Wiki: L<http://www.intertwingly.net/wiki/pie/FrontPage>
+
+The REST Wiki: L<http://internet.conveyor.com/RESTwiki/moin.cgi/FrontPage>
+
+=head1 AUTHORS
+
+Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
+
+=cut

Modified: RTx-Atom/t/1-basic.t
==============================================================================
--- RTx-Atom/t/1-basic.t (original)
+++ RTx-Atom/t/1-basic.t Fri May 14 14:11:01 2004
@@ -3,7 +3,7 @@

print "1..1\n";

-require RTx::Atom;
+require RT::Atom;

print "ok 1\n";

_______________________________________________
Rt-commit mailing list
Rt-commit@lists.bestpractical.com
http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-commit