From a6193820a7bc5b9d30008a1ce247717a6cd179b8 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 12 May 2021 07:30:24 +0000 Subject: [PATCH] Bug 28235: Build core functionality for Mojolicious controllers https://bugs.koha-community.org/show_bug.cgi?id=28325 --- Koha/Auth.pm | 151 ++++++++++++++++++++++++++++++++++++ Koha/Staff.pm | 86 ++++++++++++++++++++ Koha/Staff/Controller/Tools/Home.pm | 54 +++++++++++++ Koha/Template.pm | 41 ++++++++++ debian/templates/plack.psgi | 32 ++++++++ staff | 21 +++++ 6 files changed, 385 insertions(+) create mode 100644 Koha/Auth.pm create mode 100644 Koha/Staff.pm create mode 100644 Koha/Staff/Controller/Tools/Home.pm create mode 100644 Koha/Template.pm create mode 100755 staff diff --git a/Koha/Auth.pm b/Koha/Auth.pm new file mode 100644 index 0000000000..38e86d150c --- /dev/null +++ b/Koha/Auth.pm @@ -0,0 +1,151 @@ +package Koha::Auth; + +use strict; +use warnings; + +use C4::Auth qw//; +use C4::Context qw//; + +=head2 authenticate + + my $user = Koha::Auth->authenticate({ + sessionID => $sessionID, + }); + +Verifies that this user has an authenticated Koha session + +=cut + +#NOTE: This method requires that a Koha session exists +sub authenticate { + my ($class,$args) = @_; + my ($auth_user,$auth_session,$auth_cookie); + my $sessionID = $args->{sessionID}; + if ($sessionID){ + my $session = C4::Auth::get_session($sessionID); + if ($session){ + my $id = $session->param('id'); + if ( $id ){ + my $patrons = Koha::Patrons->search({ userid => $id }); + if ($patrons->count){ + $auth_user = $patrons->next; + $auth_session = $session; + _set_userenv_compat({ session => $session }); + } + } + } + } + if ($auth_user){ + #FIXME: Check for timeout + } + #FIXME: Ideally, it would be nice to calculate patron authorizations at login time, + #rather than on each page load (like we do currently)... + return ($auth_user,$auth_session,$auth_cookie); +} + +#NOTE: Needed since C4::Context->userenv is so ubiquitous +sub _set_userenv_compat { + my ($args) = @_; + my $session = $args->{session}; + if ($session){ + C4::Context->_new_userenv($session->param('id')); + C4::Context->set_userenv( + $session->param('number'), $session->param('id'), + $session->param('cardnumber'), $session->param('firstname'), + $session->param('surname'), $session->param('branch'), + $session->param('branchname'), $session->param('flags'), + $session->param('emailaddress'), $session->param('shibboleth'), + $session->param('desk_id'), $session->param('desk_name') + ); + } +} + +=head2 authorize + + my $flags = Koha::Auth->authorize({ + session => $session, + flagsrequired => { self_check => 'self_checkout_module' }, + }); + +=cut + +sub authorize { + my ($class,$args) = @_; + my $flags; + my $session = $args->{session}; + my $flagsrequired = $args->{flagsrequired}; + if ($session && $flagsrequired){ + my $userid = $session->param('id'); + if ($userid){ + $flags = C4::Auth::haspermission($userid,$flagsrequired); + } + } + return $flags; +} + +sub get_authz_from_flags { + my ($args) = @_; + my $flags = $args->{flags}; + my $authz; + + #FIXME: This contains a lot of copy/paste from C4::Auth + my $all_perms = C4::Auth::get_all_subpermissions(); + + if ($flags){ + if ( $flags->{superlibrarian} == 1 ){ + #NOTE: These are similar but slightly different to @flatroots... + my @perms = qw/ + circulate + catalogue + parameters + borrowers + permissions + reserveforothers + editcatalogue + updatecharges + acquisition + tools + editauthorities + serials + reports + staffaccess + plugins + coursereserves + clubs + ill + stockrotation + problem_reports + /; + foreach my $perm (@perms){ + $authz->{ "CAN_user_${perm}" } = 1; + } + foreach my $module ( keys %$all_perms ) { + foreach my $subperm ( keys %{ $all_perms->{$module} } ) { + $authz->{ "CAN_user_${module}_${subperm}" } = 1; + } + } + } + else { + foreach my $module ( keys %$all_perms ) { + if ( defined($flags->{$module}) && $flags->{$module} == 1 ) { + foreach my $subperm ( keys %{ $all_perms->{$module} } ) { + $authz->{ "CAN_user_${module}_${subperm}" } = 1; + } + } elsif ( ref( $flags->{$module} ) ) { + foreach my $subperm ( keys %{ $flags->{$module} } ) { + $authz->{ "CAN_user_${module}_${subperm}" } = 1; + } + } + } + foreach my $module ( keys %$flags ) { + if ( $flags->{$module} == 1 or ref( $flags->{$module} ) ) { + $authz->{ "CAN_user_$module" } = 1; + } + } + } + } + + return $authz; +} + +1; diff --git a/Koha/Staff.pm b/Koha/Staff.pm new file mode 100644 index 0000000000..b92e6156c2 --- /dev/null +++ b/Koha/Staff.pm @@ -0,0 +1,86 @@ +package Koha::Staff; + +use Mojo::Base 'Mojolicious'; +use Koha::Auth; +use Koha::Template; +use C4::Context; + +sub startup { + my $self = shift; + + #FIXME: Move into a plugin? + $self->helper( + staff_authorize => sub { + my ($c,$args) = @_; + my $session = $c->stash->{__koha_session__}; + my $flags = Koha::Auth->authorize({ + session => $session, + flagsrequired => $args->{flagsrequired}, + }); + if($flags){ + $c->stash->{__koha_flags__} = $flags; + $c->stash->{__koha_authz__} = Koha::Auth::get_authz_from_flags({ flags => $flags }); + return ($flags,$c->stash->{__koha__user__}); + } + else { + $c->render( text => 'Forbidden', status => 403 ); + return; + } + } + ); + #FIXME: Move into a plugin? + $self->helper( + prepare_template => sub { + my ($c,$args) = @_; + my $template_filename = $args->{template_filename}; + my $interface = $args->{interface}; + my $template = Koha::Template::prepare_template({ + template_filename => $template_filename, + interface => $interface, + koha_session => $c->stash->{__koha_session__}, + koha_user => $c->stash->{__koha_user__}, + koha_authz => $c->stash->{__koha_authz__}, + }); + return $template; + } + ); + + # Router + my $r = $self->routes; + + #NOTE: The /login route is public and does not require authentication + #FIXME: Implement a Mojolicious login route + #$r->get('/login')->to( controller => 'login', action => 'index' ); + + #NOTE: All other routes require authentication + my $auth = $r->under('/' => sub { + my $c = shift; + my $sessionID = $c->cookie('CGISESSID'); + my ($user,$session) = Koha::Auth->authenticate({ + sessionID => $sessionID, + }); + if ($user && $session){ + $c->stash->{__koha_user__} = $user; + $c->stash->{__koha_session__} = $session; + $c->cookie( + 'CGISESSID' => $session->id, + { + httponly => 1, + secure => ( C4::Context->https_enabled() ? 1 : 0 ), + path => '/', + } + ); + return 1; + } + else { + #FIXME: In future, redirect to a /login route + $c->redirect_to('/index.html'); + return; + } + }); + my $tools = $auth->under('tools'); + $tools->any(['GET','POST'] => '/:controller/:action' => { action => 'index' })->to(namespace => 'Koha::Staff::Controller::Tools'); + #FIXME: handle 404 errors with catch all routes +} + +1; diff --git a/Koha/Staff/Controller/Tools/Home.pm b/Koha/Staff/Controller/Tools/Home.pm new file mode 100644 index 0000000000..5f0ca65a49 --- /dev/null +++ b/Koha/Staff/Controller/Tools/Home.pm @@ -0,0 +1,54 @@ +package Koha::Staff::Controller::Tools::Home; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Mojo::Base 'Mojolicious::Controller'; + + +use C4::Context; +use Koha::Plugins; +use Koha::Reviews; +use C4::Tags qw/get_count_by_tag_status/; + +sub index { + my $c = shift; + + return $c->reply->not_found; +return $c->render( text => 'stuff' ); + return 1; + + my ($flags,$loggedinuser) = $c->staff_authorize({ flagsrequired => { 'tools' => '*' } }); + my $template = $c->prepare_template({ + template_filename => 'tools/tools-home.tt', + interface => 'intranet', + }); + + my $pendingcomments = Koha::Reviews->search_limited({ approved => 0 })->count; + $template->{VARS}->{pendingcomments} = $pendingcomments; + my $pendingtags = get_count_by_tag_status(0); + $template->{VARS}->{pendingtags} = $pendingtags; + + if ( C4::Context->config('enable_plugins') ) { + my @tool_plugins = Koha::Plugins->new()->GetPlugins({ + method => 'tool', + }); + $template->{VARS}->{tool_plugins} = \@tool_plugins if @tool_plugins; + } + + $c->render( text => $template->output, status => 200 ); +} + +1; diff --git a/Koha/Template.pm b/Koha/Template.pm new file mode 100644 index 0000000000..5ae1dbdac6 --- /dev/null +++ b/Koha/Template.pm @@ -0,0 +1,41 @@ +package Koha::Template; + +use strict; +use warnings; + +use C4::Templates; + +sub prepare_template { + my ($args) = @_; + my $template; + my $session = $args->{koha_session}; + my $user = $args->{koha_user}; + my $authz = $args->{koha_authz}; + my $template_filename = $args->{template_filename}; + my $interface = $args->{interface}; + if ($template_filename && $interface){ + #FIXME: See Bug 27293 about refactoring C4::Templates::gettemplate for providing the "language" param and "KohaOpacLanguage" cookie + $template = C4::Templates::gettemplate($template_filename,$interface); + if ($template){ + if ($session){ + $template->{VARS}->{ sessionID } = $session->param('id'); + } + if ($user){ + $template->{VARS}->{ logged_in_user } = $user; + $template->{VARS}->{ loggedinusernumber } = $user->borrowernumber; + $template->{VARS}->{ loggedinusername } = $user->userid; + } + if ($authz){ + foreach my $key ( keys %$authz ){ + $template->{VARS}->{ $key } = $authz->{$key}; + } + } + + #NOTE: You could include all the syspref stuff here that exists in C4::Auth, + #but I rather avoid it, and have templates update to use the Koha.Preference mechanism instead. + } + } + return $template; +} + +1; diff --git a/debian/templates/plack.psgi b/debian/templates/plack.psgi index 89cd6ef48f..94ca5f792c 100644 --- a/debian/templates/plack.psgi +++ b/debian/templates/plack.psgi @@ -66,6 +66,19 @@ my $apiv1 = builder { $server->to_psgi_app; }; +my $staff_interface = builder { + my $server = Mojo::Server::PSGI->new; + $server->build_app('Koha::Staff'); + my $app = $server->app; + $app->hook( before_dispatch => sub { + my $c = shift; + #NOTE: Rewrite the base path to strip off the mount prefix + my $path = $c->req->url->base->path(Mojo::Path->new); + + }); + $server->to_psgi_app; +}; + Koha::Logger->_init; builder { @@ -114,6 +127,25 @@ builder { } $intranet; }; + mount '/intranet/staff' => builder { + #NOTE: it is important that these are relative links + enable 'ErrorDocument', + 400 => 'errors/400.pl', + 401 => 'errors/401.pl', + 402 => 'errors/402.pl', + 403 => 'errors/403.pl', + 404 => 'errors/404.pl', + 500 => 'errors/500.pl', + subrequest => 1; + #NOTE: Without this middleware to catch fatal errors, ErrorDocument won't be able to render a 500 document + #NOTE: This middleware must be closer to the PSGI app than ErrorDocument + enable "HTTPExceptions"; + if ( Log::Log4perl->get_logger('plack-intranet')->has_appenders ){ + enable 'Log4perl', category => 'plack-intranet'; + enable 'LogWarn'; + } + $staff_interface; + }; mount '/api/v1/app.pl' => builder { if ( Log::Log4perl->get_logger('plack-api')->has_appenders ){ enable 'Log4perl', category => 'plack-api'; diff --git a/staff b/staff new file mode 100755 index 0000000000..f5b4a97808 --- /dev/null +++ b/staff @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +require Mojolicious::Commands; +Mojolicious::Commands->start_app('Koha::Staff'); -- 2.11.0