Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config route #26

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 43 additions & 9 deletions lib/Mojolicious/Plugin/Yancy.pm
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,27 @@ connections.
helper pg => sub { state $pg = Mojo::Pg->new( 'postgres:///myapp' ) };
plugin Yancy => { backend => { Pg => app->pg } };

=item editor

Configuration for the Yancy web application. A hash, permitting these
keys:

=over

=item route

A base route to add Yancy to. This allows you to customize the URL
and add authentication or authorization. Defaults to allowing access
to the Yancy web application under C</yancy>, and the REST API under
C</yancy/api>.
and add authentication or authorization. If a string is supplied, it
will be turned into a L<Mojolicious::Routes::Route> object with that
path, under the app. Defaults to C</yancy>.

=item api_route

A route as above, for the editor's REST API, living under the editor's
route. A string may also be supplied, defaulting to C</api>. This means
the default REST API path will be C</yancy/api>.

=back

=item return_to

Expand Down Expand Up @@ -103,6 +118,19 @@ authentication or authorization checks:
} );
$auth_route->add_child( $_ ) for @need_auth;

=head2 yancy.api_route

Get the route where the Yancy API will appear. Useful for adding
authentication or authorization checks:

my $api_route = $c->yancy->api_route;
my @need_auth = @{ $api_route->children };
my $auth_route = $api_route->under( sub {
# ... Check auth
return 1;
} );
$auth_route->add_child( $_ ) for @need_auth;

=head2 yancy.plugin

Add a Yancy plugin. Yancy plugins are Mojolicious plugins that require
Expand Down Expand Up @@ -410,8 +438,13 @@ has _filters => sub { {} };

sub register {
my ( $self, $app, $config ) = @_;
my $route = $config->{route} // $app->routes->any( '/yancy' );
$route->to( return_to => $config->{return_to} // '/' );
my $editor_route = $config->{editor}{route} // '/yancy';
$editor_route = $app->routes->any( $editor_route )
if !UNIVERSAL::isa( $editor_route, 'Mojolicious::Routes::Route' );
$editor_route->to( return_to => $config->{return_to} // '/' );
my $api_route = $config->{editor}{api_route} // '/api';
$api_route = $editor_route->any( $api_route )->name( 'yancy.api' )
if !UNIVERSAL::isa( $api_route, 'Mojolicious::Routes::Route' );
$config->{api_controller} //= 'Yancy::API';
$config->{openapi} = _ensure_json_data( $app, $config->{openapi} );

Expand All @@ -423,7 +456,7 @@ sub register {

# Helpers
$app->helper( 'yancy.config' => sub { return $config } );
$app->helper( 'yancy.route' => sub { return $route } );
$app->helper( 'yancy.route' => sub { return $editor_route } );
$app->helper( 'yancy.backend' => sub {
state $backend = load_backend( $config->{backend}, $config->{collections} || $config->{openapi}{definitions} );
} );
Expand All @@ -444,7 +477,7 @@ sub register {
$app->helper( 'yancy.filter.apply' => curry( \&_helper_filter_apply, $self ) );

# Routes
$route->get( '/' )->name( 'yancy.index' )
$editor_route->get( '/' )->name( 'yancy.index' )
->to(
template => 'yancy/index',
controller => $config->{api_controller},
Expand Down Expand Up @@ -497,10 +530,11 @@ sub register {
$self->_openapi_spec_add_mojo( $spec, $config );

my $openapi = $app->plugin( OpenAPI => {
route => $route->any( '/api' )->name( 'yancy.api' ),
route => $api_route,
spec => $spec,
default_response_name => '_Error',
} );
$app->helper( 'yancy.api_route' => sub { $api_route } );
$app->helper( 'yancy.openapi' => sub { $openapi } );

# Add supported formats to silence warnings from JSON::Validator
Expand Down Expand Up @@ -742,7 +776,7 @@ sub _openapi_spec_from_schema {
info => $config->{info} || { title => 'Yancy', version => 1 },
swagger => '2.0',
host => $config->{host} // hostname(),
basePath => '/api',
basePath => $config->{editor}{api_route} // '/api',
schemes => [qw( http )],
consumes => [qw( application/json )],
produces => [qw( application/json )],
Expand Down
2 changes: 1 addition & 1 deletion lib/Yancy.pm
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ __DATA__
<p>This is the default not found page.</p>

<h2>Getting Started</h2>
<p>To edit your data, go to <a href="/yancy">/yancy</a>.</p>
<p>To edit your data, go to <a href="<%== url_for 'yancy.index' %>"><%== url_for 'yancy.index' %></a>.</p>
<p>Add your templates to <tt><%= app->home->child( 'templates' ) %></tt>. Each template becomes a URL in your
site:</p>
<ul>
Expand Down
23 changes: 23 additions & 0 deletions lib/Yancy/Help/Config.pod
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,29 @@ To customize how Yancy responds to API requests with data, you can
create a custom controller and set the class name here. For details how
to create a custom API controller, see L<Yancy::Controller::Yancy::API>.

=head2 C<editor>

A hash, under which lives configuration for the Yancy editor, with these
possible keys:

=over

=item route

To customize the URL under which the Yancy editor is found. If not given,
defaults to C</yancy>. If a L<Mojolicious::Routes::Route> object is not
given, it will be treated as a string, and used to create one.

Note, the various assets will still live on the web app under C</yancy>.

=item api_route

A route as above, for the editor's REST API, living under the editor's
route. A string may also be supplied, defaulting to C</api>. This means
the default REST API path will be C</yancy/api>.

=back

=head1 SEE ALSO

L<Yancy>, L<Mojolicious::Plugin::Yancy>
Expand Down
27 changes: 27 additions & 0 deletions t/api.t
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,33 @@ subtest 'read_schema collections' => \&test_api,
} ),
'/yancy/api';

( $backend_url, $backend, %items ) = init_backend( $collections, %data );
subtest 'different Yancy URL' => \&test_api,
Test::Mojo->new( 'Yancy', {
backend => $backend_url,
collections => $collections,
editor => { route => '/yancy2' },
} ),
'/yancy2/api';

( $backend_url, $backend, %items ) = init_backend( $collections, %data );
subtest 'different API URL' => \&test_api,
Test::Mojo->new( 'Yancy', {
backend => $backend_url,
collections => $collections,
editor => { api_route => '/api2' },
} ),
'/yancy/api2';

( $backend_url, $backend, %items ) = init_backend( $collections, %data );
subtest 'different API and Yancy URLs' => \&test_api,
Test::Mojo->new( 'Yancy', {
backend => $backend_url,
collections => $collections,
editor => { route => '/yancy2', api_route => '/api2' },
} ),
'/yancy2/api2';

my $openapi = decode_json path ( $Bin, 'share', 'openapi-spec.json' )->slurp;
( $backend_url, $backend, %items ) = init_backend( $collections, %data );
subtest 'pass openapi' => \&test_api,
Expand Down
2 changes: 1 addition & 1 deletion t/plugin/auth/basic.t
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ subtest 'standalone plugin' => sub {
$t->app->plugin( 'Yancy', {
backend => $backend_url,
collections => $collections,
route => $base_route->any( '/yancy' ),
editor => { route => $base_route->any( '/yancy' ) },
} );

unshift @{$t->app->plugins->namespaces}, 'Yancy::Plugin';
Expand Down
15 changes: 15 additions & 0 deletions t/standalone.t
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,19 @@ subtest 'with openapi spec file' => sub {
;
};

subtest 'configurable editor path' => sub {
my $t = Test::Mojo->new( 'Yancy', {
backend => $backend_url,
collections => $collections,
read_schema => 1,
editor => { route => '/notyancy' },
} );
$t->get_ok( '/notyancy/api' ) # if just /notyancy, SEGV w/Devel::Cover
->status_is( 200 )
;
$t->get_ok( '/yancy/bootstrap.css' ) # still located there, static
->status_is( 200 )
;
};

done_testing;