The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Yancy::Controller::Yancy::MultiTenant - A controller to show a user only their content

VERSION

version 1.055

SYNOPSIS

    use Mojolicious::Lite;
    plugin Yancy => {
        schema => {
            blog => {
                properties => {
                    id => { type => 'integer' },
                    user_id => { type => 'integer' },
                    title => { type => 'string' },
                    html => { type => 'string' },
                },
            },
        },
    };

    app->routes->get( '/user/:user_id' )->to(
        'yancy-multi_tenant#list',
        schema => 'blog',
        template => 'index'
    );

    __DATA__
    @@ index.html.ep
    % for my $item ( @{ stash 'items' } ) {
        <h1><%= $item->{title} %></h1>
        <%== $item->{html} %>
    % }

DESCRIPTION

This module contains routes to manage content owned by users. When paired with an authentication plugin like Yancy::Plugin::Auth::Basic, each user is allowed to manage their own content.

This controller extends Yancy::Controller::Yancy to add filtering content by a user's ID.

METHODS

list

    $routes->get( '/:user_id' )->to(
        'yancy-multi_tenant#list',
        schema => $schema_name,
        template => $template_name,
    );

This method is used to list content owned by the given user (specified in the user_id stash value).

Input Stash

This method extends "list" in Yancy::Controller::Yancy and adds the following configuration and stash values:

user_id

The ID of the user whose content should be listed. Required. Should match a value in the user_id_field.

user_id_field

The field in the item that holds the user ID. Defaults to user_id.

get

    $routes->get( '/:user_id/:id' )->to(
        'yancy-multi_tenant#get',
        schema => $schema_name,
        template => $template_name,
    );

This method is used to show a single item owned by a user (given by the user_id stash value).

Input Stash

This method extends "get" in Yancy::Controller::Yancy and adds the following configuration and stash values:

user_id

The ID of the user whose content should be listed. Required. Should match a value in the user_id_field.

user_id_field

The field in the item that holds the user ID. Defaults to user_id.

set

    $routes->any( [ 'GET', 'POST' ] => '/:id/edit' )->to(
        'yancy#set',
        schema => $schema_name,
        template => $template_name,
    );

    $routes->any( [ 'GET', 'POST' ] => '/create' )->to(
        'yancy#set',
        schema => $schema_name,
        template => $template_name,
        forward_to => $route_name,
    );

This route creates a new item or updates an existing item in a schema. If the user is making a GET request, they will simply be shown the template. If the user is making a POST or PUT request, the form parameters will be read, the data will be validated against the schema configuration, and the user will either be shown the form again with the result of the form submission (success or failure) or the user will be forwarded to another place.

This method does not authenticate users. User authentication and authorization should be performed by an auth plugin like Yancy::Plugin::Auth::Basic.

Input Stash

This method extends "set" in Yancy::Controller::Yancy and adds the following configuration and stash values:

user_id

The ID of the user whose content is being edited. Required. Will be set in the user_id_field.

user_id_field

The field in the item that holds the user ID. Defaults to user_id. This field will be filled in with the user_id stash value.

delete

    $routes->any( [ 'GET', 'POST' ], '/delete/:id' )->to(
        'yancy#delete',
        schema => $schema_name,
        template => $template_name,
        forward_to => $route_name,
    );

This route deletes an item from a schema. If the user is making a GET request, they will simply be shown the template (which can be used to confirm the delete). If the user is making a POST or DELETE request, the item will be deleted and the user will either be shown the form again with the result of the form submission (success or failure) or the user will be forwarded to another place.

This method does not authenticate users. User authentication and authorization should be performed by an auth plugin like Yancy::Plugin::Auth::Basic.

Input Stash

This method extends "delete" in Yancy::Controller::Yancy and adds the following configuration and stash values:

user_id

The ID of the user whose content is being edited. Required. Will be set in the user_id_field.

user_id_field

The field in the item that holds the user ID. Defaults to user_id. This field will be filled in with the user_id stash value.

EXAMPLES

To use this controller when the URL displays a username and the content uses an internal ID, you can use an under route to map the username in the path to the ID:

    my $user_route = app->routes->under( '/:username', sub {
        my ( $c ) = @_;
        my $username = $c->stash( 'username' );
        my @users = $c->yancy->list( user => { username => $username } );
        if ( my $user = $users[0] ) {
            $c->stash( user_id => $user->{id} );
            return 1;
        }
        return $c->reply->not_found;
    } );

    # /:username - List blog posts
    $user_route->get( '' )->to(
        'yancy-multi_tenant#list',
        schema => 'blog',
        template => 'blog_list',
    );
    # /:username/:id/:slug - Get a single blog post
    $user_route->get( '/:id/:slug' )->to(
        'yancy-multi_tenant#get',
        schema => 'blog',
        template => 'blog_view',
    );

To build a website where content is only for the current logged-in user, combine this controller with an auth plugin like Yancy::Plugin::Auth::Basic. Use an under route to set the user_id from the current user.

    app->yancy->plugin( 'Auth::Basic', {
        route => any( '' ), # All routes require login
        schema => 'user',
        username_field => 'username',
        password_digest => { type => 'SHA-1' },
    } );

    my $user_route = app->yancy->auth->route->under( '/', sub {
        my ( $c ) = @_;
        my $user = $c->yancy->auth->current_user;
        $c->stash( user_id => $user->{id} );
        return 1;
    } );

    # / - List todo items
    $user_route->get( '' )->to(
        'yancy-multi_tenant#list',
        schema => 'todo_item',
        template => 'todo_list',
    );

SEE ALSO

Yancy::Controller::Yancy, Mojolicious::Controller, Yancy

AUTHOR

Doug Bell <preaction@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2020 by Doug Bell.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.