[Bps-public-commit] rt-extension-rest2 branch, dev, created. debe164714350ad8343a282ccbdaaa37b6882e61

Wallace Reis wreis at bestpractical.com
Mon Dec 22 07:08:45 EST 2014


The branch, dev has been created
        at  debe164714350ad8343a282ccbdaaa37b6882e61 (commit)

- Log -----------------------------------------------------------------
commit e5748fdc5fe8a3c841e13eb58424186f6907baef
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Mon Dec 15 18:26:16 2014 -0200

    Move Log middleware to its class

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 55b00d7..1786b66 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -182,48 +182,48 @@ sub to_psgi_app { shift->to_app(@_) }
 
 sub to_app {
     my $class = shift;
-    return sub {
-        my ($env) = @_;
-        $env->{'psgix.logger'} = sub {
-            my $what = shift;
-            RT->Logger->log(%$what);
-        };
-        # XXX TODO: logging of SQL queries in RT's framework for doing so
+
+    return builder {
+        enable '+RT::Extension::REST2::Middleware::Log';
+
         # XXX TODO: Need a dispatcher?  Or do it inside resources?  Web::Simple?
         RT::ConnectToDatabase();
-        my $dispatch = builder {
-            # XXX TODO: better auth integration
-            enable "Auth::Basic",
-                realm         => RT->Config->Get("rtname") . " API",
-                authenticator => sub {
-                    my ($user, $pass, $env) = @_;
-                    my $cu = RT::CurrentUser->new;
-                    $cu->Load($user);
-
-                    if ($cu->id and $cu->IsPassword($pass)) {
-                        $env->{"rt.current_user"} = $cu;
-                        return 1;
-                    } else {
-                        RT->Logger->error("FAILED LOGIN for $user from $env->{REMOTE_ADDR}");
-                        return 0;
-                    }
-                };
-            for ($class->resources) {
-                (my $path = lc $_) =~ s{::}{/}g;
-                mount "/$path" => resource($_);
-            }
-            mount "/"       => sub { [ 404, ['Content-type' => 'text/plain'], ['Unknown resource'] ] };
-        };
-        $dispatch->(@_);
-    }
+        sub {
+            my ($env) = @_;
+            my $dispatch = builder {
+                # XXX TODO: better auth integration
+                enable "Auth::Basic",
+                    realm         => RT->Config->Get("rtname") . " API",
+                    authenticator => sub {
+                        my ($user, $pass, $env) = @_;
+                        my $cu = RT::CurrentUser->new;
+                        $cu->Load($user);
+
+                        if ($cu->id and $cu->IsPassword($pass)) {
+                            $env->{"rt.current_user"} = $cu;
+                            return 1;
+                        } else {
+                            RT->Logger->error("FAILED LOGIN for $user from $env->{REMOTE_ADDR}");
+                            return 0;
+                        }
+                    };
+                for ($class->resources) {
+                    (my $path = lc $_) =~ s{::}{/}g;
+                    mount "/$path" => resource($_);
+                }
+                mount "/"       => sub { [ 404, ['Content-type' => 'text/plain'], ['Unknown resource'] ] };
+            };
+            $dispatch->(@_);
+        }
+    };
 }
 
 # Called by RT::Interface::Web::Handler->PSGIApp
 sub PSGIWrap {
     my ($class, $app) = @_;
-    builder {
-        mount "/REST/2.0"   => $class->to_app;
-        mount "/"           => $app;
+    return builder {
+        mount '/REST/2.0' => $class->to_app;
+        mount '/' => $app;
     };
 }
 
diff --git a/lib/RT/Extension/REST2/Middleware/Log.pm b/lib/RT/Extension/REST2/Middleware/Log.pm
new file mode 100644
index 0000000..75e95b1
--- /dev/null
+++ b/lib/RT/Extension/REST2/Middleware/Log.pm
@@ -0,0 +1,20 @@
+package RT::Extension::REST2::Middleware::Log;
+
+use strict;
+use warnings;
+
+use base 'Plack::Middleware';
+
+sub call {
+    my ( $self, $env ) = @_;
+
+    # XXX TODO: logging of SQL queries in RT's framework for doing so
+    $env->{'psgix.logger'} = sub {
+        my $what = shift;
+        RT->Logger->log(%$what);
+    };
+
+    return $self->app->($env);
+}
+
+1;

commit 38558c271fbc97c64966ff8d0c3ba770e3c1ca47
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Mon Dec 15 18:35:36 2014 -0200

    Move Auth middleware to its own class

diff --git a/Makefile.PL b/Makefile.PL
index ff9b102..662a183 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -18,6 +18,7 @@ requires 'Plack::Builder';
 requires 'Scalar::Util';
 requires 'Sub::Exporter';
 requires 'Web::Machine' => '0.12';
+requires 'Class::Method::Modifiers';
 
 sign;
 WriteAll;
diff --git a/TODO b/TODO
index f783fad..5fb013e 100644
--- a/TODO
+++ b/TODO
@@ -11,7 +11,6 @@ Find TODOs in the code via `ag TODO`.
   - /scrips
   - /roles
   - /templates
-* Implement Basic HTTP authen
 * Remove any session mocking
 
 XXX TODO: Include Links in record serializations
diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 1786b66..7f6ca03 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -132,10 +132,9 @@ numbers start at 1.
 
 =head2 Authentication
 
-Currently authentication is limited to internal RT usernames and passwords,
-provided via HTTP Basic auth.  Most HTTP libraries already have a way of
-providing basic auth credentials when making requests.  Using curl, for
-example:
+Authentication is limited to internal RT usernames and passwords, provided via
+HTTP Basic auth. Most HTTP libraries already have a way of providing basic
+auth credentials when making requests.  Using curl, for example:
 
     curl -u username:password …
 
@@ -183,30 +182,15 @@ sub to_psgi_app { shift->to_app(@_) }
 sub to_app {
     my $class = shift;
 
+    RT::ConnectToDatabase();
+
     return builder {
         enable '+RT::Extension::REST2::Middleware::Log';
+        enable '+RT::Extension::REST2::Middleware::Auth';
 
-        # XXX TODO: Need a dispatcher?  Or do it inside resources?  Web::Simple?
-        RT::ConnectToDatabase();
         sub {
             my ($env) = @_;
             my $dispatch = builder {
-                # XXX TODO: better auth integration
-                enable "Auth::Basic",
-                    realm         => RT->Config->Get("rtname") . " API",
-                    authenticator => sub {
-                        my ($user, $pass, $env) = @_;
-                        my $cu = RT::CurrentUser->new;
-                        $cu->Load($user);
-
-                        if ($cu->id and $cu->IsPassword($pass)) {
-                            $env->{"rt.current_user"} = $cu;
-                            return 1;
-                        } else {
-                            RT->Logger->error("FAILED LOGIN for $user from $env->{REMOTE_ADDR}");
-                            return 0;
-                        }
-                    };
                 for ($class->resources) {
                     (my $path = lc $_) =~ s{::}{/}g;
                     mount "/$path" => resource($_);
diff --git a/lib/RT/Extension/REST2/Middleware/Auth.pm b/lib/RT/Extension/REST2/Middleware/Auth.pm
new file mode 100644
index 0000000..18587de
--- /dev/null
+++ b/lib/RT/Extension/REST2/Middleware/Auth.pm
@@ -0,0 +1,29 @@
+package RT::Extension::REST2::Middleware::Auth;
+
+use strict;
+use warnings;
+
+use base 'Plack::Middleware::Auth::Basic';
+
+use Class::Method::Modifiers;
+
+before prepare_app => sub {
+    my $self = shift;
+    $self->realm( RT->Config->Get('rtname') . ' REST API' );
+
+    $self->authenticator(sub {
+        my ($user, $pass, $env) = @_;
+        my $cu = RT::CurrentUser->new;
+        $cu->Load($user);
+        if ($cu->id and $cu->IsPassword($pass)) {
+            $env->{'rt.current_user'} = $cu;
+            return 1;
+        }
+        else {
+            RT->Logger->info("Failed login for $user");
+            return 0;
+        }
+    });
+};
+
+1;

commit 6a31007b15bbc5755be0800c63bbb3c51cd5c3ba
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Mon Dec 15 19:29:25 2014 -0200

    Avoid '/REST/2.0' magical value

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 7f6ca03..d942e0b 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -5,6 +5,7 @@ use 5.010;
 package RT::Extension::REST2;
 
 our $VERSION = '0.01';
+our $REST_PATH = '/REST/2.0';
 
 use UNIVERSAL::require;
 use Plack::Builder;
@@ -202,23 +203,23 @@ sub to_app {
     };
 }
 
+sub base_path {
+    RT->Config->Get('WebPath') . $REST_PATH
+}
+
+sub base_uri {
+    RT->Config->Get('WebBaseURL') . shift->base_path
+}
+
 # Called by RT::Interface::Web::Handler->PSGIApp
 sub PSGIWrap {
     my ($class, $app) = @_;
     return builder {
-        mount '/REST/2.0' => $class->to_app;
+        mount $REST_PATH => $class->to_app;
         mount '/' => $app;
     };
 }
 
-sub base_path {
-    RT->Config->Get("WebPath") . "/REST/2.0"
-}
-
-sub base_uri {
-    RT->Config->Get("WebBaseURL") . base_path()
-}
-
 =head1 INSTALLATION
 
 =over

commit 8e27096989748cd5352ad0528424f988cc6df174
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Tue Dec 16 14:06:10 2014 -0200

    Documentation changes

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index d942e0b..ae753aa 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -17,6 +17,48 @@ use Web::Machine;
 
 RT-Extension-REST2 - Adds a modern REST API to RT under /REST/2.0/
 
+=head1 INSTALLATION
+
+=over
+
+=item C<perl Makefile.PL>
+
+=item C<make>
+
+=item C<make install>
+
+May need root permissions
+
+=item Edit your F</opt/rt4/etc/RT_SiteConfig.pm>
+
+Add this line:
+
+    Plugin('RT::Extension::REST2');
+
+=item Clear your mason cache
+
+    rm -rf /opt/rt4/var/mason_data/obj
+
+=item Restart your webserver
+
+=back
+
+=head1 CONFIGURATION
+
+=over
+
+=item C<$RESTPath>
+
+The relative path from C<$WebPath> where you want to have the REST API being
+served.
+
+C<$RESTPath> requires a leading / but no trailing /, or it can be blank.
+
+Defaults to C</REST/2.0>. Thus, if you have C<$WebPath> set to C</rt> then the
+base REST API URI will be like C<https://example.com/rt/REST/2.0>.
+
+=back
+
 =head1 USAGE
 
 =head2 Summary
@@ -87,7 +129,7 @@ These resources accept a basic JSON structure as the search conditions which
 specifies one or more fields to limit on (using specified operators and
 values).  An example:
 
-    curl -si -u user:pass http://rt.example.com/REST/2.0/queues -XPOST --data-binary '
+    curl -si -u user:pass https://rt.example.com/REST/2.0/queues -XPOST --data-binary '
         [
             { "field":    "Name",
               "operator": "LIKE",
@@ -220,35 +262,9 @@ sub PSGIWrap {
     };
 }
 
-=head1 INSTALLATION
-
-=over
-
-=item C<perl Makefile.PL>
-
-=item C<make>
-
-=item C<make install>
-
-May need root permissions
-
-=item Edit your F</opt/rt4/etc/RT_SiteConfig.pm>
-
-Add this line:
-
-    Plugin('RT::Extension::REST2');
-
-=item Clear your mason cache
-
-    rm -rf /opt/rt4/var/mason_data/obj
-
-=item Restart your webserver
-
-=back
-
 =head1 AUTHOR
 
-Thomas Sibley <trs at bestpractical.com>
+Best Practical Solutions, LLC <modules at bestpractical.com>
 
 =head1 BUGS
 

commit d86ef4b95f6412261471a0e6fa6e66e48a46d1aa
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Wed Dec 17 16:41:05 2014 -0200

    Use Web::Simple as dispatcher
    
    When processing comes to Resources layer, PATH_INFO does not contain just
    the /:id anymore -- due the use of Web::Simple and not simply mount() call.
    
    The REST path is just a prefix, so it is not necessary that we write every
    single route rule containing such prefix. What matters for REST API core is
    the stuff after the base path, that is, stuff like /tickets/1. Hence the use
    of ReverseProxyPath.

diff --git a/Makefile.PL b/Makefile.PL
index 662a183..ecad65f 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -18,7 +18,10 @@ requires 'Plack::Builder';
 requires 'Scalar::Util';
 requires 'Sub::Exporter';
 requires 'Web::Machine' => '0.12';
+requires 'Web::Simple';
 requires 'Class::Method::Modifiers';
+requires 'Plack::Middleware::RequestHeaders';
+requires 'Plack::Middleware::ReverseProxyPath';
 
 sign;
 WriteAll;
diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index ae753aa..9314255 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -9,7 +9,7 @@ our $REST_PATH = '/REST/2.0';
 
 use UNIVERSAL::require;
 use Plack::Builder;
-use Web::Machine;
+use RT::Extension::REST2::Dispatcher;
 
 =encoding utf-8
 
@@ -202,24 +202,6 @@ handle them appropriately.
 
 # XXX TODO: API doc
 
-sub resources {
-    return qw(
-        Queue
-        Queues
-        Ticket
-        Tickets
-        User
-        Users
-        Download::CF
-    );
-}
-
-sub resource {
-    Web::Machine->new(
-        resource => "RT::Extension::REST2::Resource::$_[0]",
-    )->to_app;
-}
-
 sub to_psgi_app { shift->to_app(@_) }
 
 sub to_app {
@@ -227,21 +209,18 @@ sub to_app {
 
     RT::ConnectToDatabase();
 
+    my $rest_path = $class->rest_path;
+
     return builder {
         enable '+RT::Extension::REST2::Middleware::Log';
         enable '+RT::Extension::REST2::Middleware::Auth';
-
-        sub {
-            my ($env) = @_;
-            my $dispatch = builder {
-                for ($class->resources) {
-                    (my $path = lc $_) =~ s{::}{/}g;
-                    mount "/$path" => resource($_);
-                }
-                mount "/"       => sub { [ 404, ['Content-type' => 'text/plain'], ['Unknown resource'] ] };
-            };
-            $dispatch->(@_);
-        }
+        enable 'RequestHeaders',
+            set => [
+                'X-Forwarded-Script-Name' => '/',
+                'X-Traversal-Path' => $rest_path,
+            ];
+        enable 'ReverseProxyPath';
+        RT::Extension::REST2::Dispatcher->to_psgi_app;
     };
 }
 
diff --git a/lib/RT/Extension/REST2/Dispatcher.pm b/lib/RT/Extension/REST2/Dispatcher.pm
new file mode 100644
index 0000000..5bbfd89
--- /dev/null
+++ b/lib/RT/Extension/REST2/Dispatcher.pm
@@ -0,0 +1,24 @@
+package RT::Extension::REST2::Dispatcher;
+
+use strict;
+use warnings;
+use Web::Simple;
+use Web::Machine;
+
+sub dispatch_request {
+    my ($self) = @_;
+    sub (/*/*) {
+        my $resource_name = ucfirst lc $_[1];
+        my $resource = "RT::Extension::REST2::Resource::${resource_name}";
+        if ( $resource->require ) {
+            Web::Machine->new(
+                resource => $resource,
+            )->to_app;
+        }
+        else {
+            return undef;
+        }
+    },
+}
+
+1;
diff --git a/lib/RT/Extension/REST2/Resource/Record.pm b/lib/RT/Extension/REST2/Resource/Record.pm
index 607be90..c1380bf 100644
--- a/lib/RT/Extension/REST2/Resource/Record.pm
+++ b/lib/RT/Extension/REST2/Resource/Record.pm
@@ -36,7 +36,7 @@ sub _build_record_class {
 sub _build_record {
     my $self = shift;
     my $record = $self->record_class->new( $self->current_user );
-    my $id = bind_path('/:id', $self->request->path_info);
+    my ($type, $id) = bind_path('/:type/:id', $self->request->path_info);
     $record->Load($id) if $id;
     return $record;
 }

commit ae0a413b10fc7c391d1cb45b628b6dbce9122e96
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Thu Dec 18 17:18:49 2014 -0200

    RTx() provides both all_from and readme_from

diff --git a/Makefile.PL b/Makefile.PL
index ecad65f..4b11103 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -1,8 +1,6 @@
 use inc::Module::Install;
 
 RTx 'RT-Extension-REST2';
-all_from 'lib/RT/Extension/REST2.pm';
-readme_from 'lib/RT/Extension/REST2.pm';
 license  'gplv2';
 
 requires_rt('4.2.4');

commit 5cf3da179d7b59d3cd1c87eb566496db4feff798
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Fri Dec 19 10:15:33 2014 -0200

    Baseline for viewing docs

diff --git a/Makefile.PL b/Makefile.PL
index 4b11103..fcbab41 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -20,6 +20,8 @@ requires 'Web::Simple';
 requires 'Class::Method::Modifiers';
 requires 'Plack::Middleware::RequestHeaders';
 requires 'Plack::Middleware::ReverseProxyPath';
+requires 'Module::Path';
+requires 'Pod::POM';
 
 sign;
 WriteAll;
diff --git a/lib/RT/Extension/REST2/Dispatcher.pm b/lib/RT/Extension/REST2/Dispatcher.pm
index 5bbfd89..309ad07 100644
--- a/lib/RT/Extension/REST2/Dispatcher.pm
+++ b/lib/RT/Extension/REST2/Dispatcher.pm
@@ -4,9 +4,17 @@ use strict;
 use warnings;
 use Web::Simple;
 use Web::Machine;
+use RT::Extension::REST2::PodViewer 'podview_as_html';
 
 sub dispatch_request {
     my ($self) = @_;
+    sub (/) {
+        return [
+            200,
+            ['Content-Type' => 'text/html'],
+            [ podview_as_html('RT::Extension::REST2') ]
+        ];
+    },
     sub (/*/*) {
         my $resource_name = ucfirst lc $_[1];
         my $resource = "RT::Extension::REST2::Resource::${resource_name}";
diff --git a/lib/RT/Extension/REST2/PodViewer.pm b/lib/RT/Extension/REST2/PodViewer.pm
new file mode 100644
index 0000000..ab0dcb2
--- /dev/null
+++ b/lib/RT/Extension/REST2/PodViewer.pm
@@ -0,0 +1,19 @@
+package RT::Extension::REST2::PodViewer;
+
+use strict;
+use warnings;
+use Module::Path 'module_path';
+use Pod::POM;
+use Pod::POM::View::HTML;
+
+use Sub::Exporter -setup => {
+    exports => [qw(podview_as_html)]
+};
+
+sub podview_as_html {
+    my ($module_name) = @_;
+    my $pom = Pod::POM->new->parse( module_path($module_name) );
+    return $pom->present('Pod::POM::View::HTML');
+}
+
+1;

commit 9cdc49e8876dc4e961735ff50bac7375f45ecbe0
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Fri Dec 19 10:43:41 2014 -0200

    Recommends JSON::XS

diff --git a/Makefile.PL b/Makefile.PL
index fcbab41..9e8859a 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -23,5 +23,7 @@ requires 'Plack::Middleware::ReverseProxyPath';
 requires 'Module::Path';
 requires 'Pod::POM';
 
+recommends 'JSON::XS';
+
 sign;
 WriteAll;

commit 49e4ec0cfc1ed27f92ab202947642f18c57157fb
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Fri Dec 19 10:53:29 2014 -0200

    Bump VERSION

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 9314255..8ecbb87 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -4,7 +4,7 @@ use 5.010;
 
 package RT::Extension::REST2;
 
-our $VERSION = '0.01';
+our $VERSION = '1.01';
 our $REST_PATH = '/REST/2.0';
 
 use UNIVERSAL::require;

commit debe164714350ad8343a282ccbdaaa37b6882e61
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Fri Dec 19 10:56:56 2014 -0200

    Update Copyright

diff --git a/lib/RT/Extension/REST2.pm b/lib/RT/Extension/REST2.pm
index 8ecbb87..8c7cba6 100644
--- a/lib/RT/Extension/REST2.pm
+++ b/lib/RT/Extension/REST2.pm
@@ -254,7 +254,7 @@ L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-REST
 
 =head1 LICENSE AND COPYRIGHT
 
-This software is Copyright (c) 2013 by Best Practical Solutions
+This software is Copyright (c) 2015 by Best Practical Solutions, LLC.
 
 This is free software, licensed under:
 

-----------------------------------------------------------------------


More information about the Bps-public-commit mailing list