[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