package Reporter::Routes;
use Dancer2;
use Dancer2::Plugin::Deferred;
use Data::Printer;
use Reporter;
use Reporter::Routes::AJAX;
use Reporter::Routes::Test;
=begin # seems to work the same setting $Local::QueryLogger::CurrentUsername directly
use Tie::RefHash::Weak;
use Scope::Guard qw(guard);
{
tie my %refhash, 'Tie::RefHash::Weak';
sub set_username {
my ($request, $username) = @_; # p $request; p $username;
$refhash{$request} = guard { undef $Local::QueryLogger::CurrentUsername };
$Local::QueryLogger::CurrentUsername = $username;
return;
}
}
=cut
# disable sql_trace if test script (needs explicit export SQL_TRACE=1 if req'd):
set enable_sql_trace => 0 if $ENV{HARNESS_VERSION};
# app, contains model & db classes:
our $app = Reporter->new( dbname => 'hilis4', config => config() );
# make $app available to other routes that need it:
$Reporter::Routes::AJAX::app = $app;
sub flash { deferred @_ } # to use old term flash instead of deferred
hook before => sub {
# discard old db connection if mysql has gone away since last request:
$app->check_db_connection; # Local::DB - creates new DBIx::Simple object on demand
# sql query output to stdout:
$app->enable_sql_trace if setting('enable_sql_trace'); # development env
# all routes need login (except /login):
my $session = session('user_profile'); # p $session; # beware auto-vivification here
unless ( $session ) {
redirect '/login' unless request->path_info =~ m!^/login!;
}
# set_username(request(), $session->{username}); # works the same setting directly:
$Local::QueryLogger::CurrentUsername = $session->{username};
};
hook before_template_render => sub { # do NOT use 'var' in here or 500.tt fails
my $tokens = shift;
$tokens->{symbolise} = sub { $app->symbolise(@_) };
$tokens->{app_version} = $app->version; # warn $app->version;
};
# fix for broken 500.tt rendering if use of 'var' in before_template_render() :
# hook on_route_exception => sub { send_error($_[1]) }; # err msg available in [% content %]
# default route:
get '/' => sub {
{ # get list of reported requests for this user:
my $user = session('user_profile'); # p $user;
my $data = $app->model->get_reports_for_user($user->{id});
var user_reports => $data;
}
template load => { target => uri_for('/load') };
};
# login route:
get '/login' => sub { template login => {} };
# submitted user credentials:
post '/login' => sub {
my $params = params; # p $params;
# validate username/password
if ( my $user = $app->model->authenticate_user($params) ) { # p $user;
session user_profile => $user;
redirect '/';
}
else {
my $failed_logins = session('failed_logins') || 0;
session failed_logins => $failed_logins + 1; # increment
redirect '/login';
}
};
get '/load' => sub {
my $params = params; # p $params;
# validate lab number format:
my $validation = $app->model->validator->validate( search => $params );
# p $validation;
if ( $validation->{failed} ) { # p $result->{errors};
return template load => $validation; # href containing dfv_errs key
}
my $lab_number = param('lab_number');
my $session = session('user_profile');
{ # get request for lab_number:
my %h = (
lab_number => $lab_number,
user_id => $session->{id},
);
my $data = $app->model->load_request(\%h); # p $data;
if (! $data) {
my $msg = 'request with lab number %s not found';
flash warning => sprintf $msg, $lab_number;
redirect '/';
}
# store data in session for tt, and in case needed for re-display to report.tt:
session record => $data;
}
{ # get validation profile to configure required fields:
my $profile = $app->model->get_validation_profile('report'); # p $profile;
session validation_profile => $profile;
}
# tt gets data from session.record:
template report => { target => uri_for('/report') };
};
post '/report/:request_id' => sub {
my $params = params; # p $params;
my $validation = $app->model->validator->validate( report => $params );
# p $validation;
my $record = session('record');
$record->{report} = $params; # in case validation fails
if ( $validation->{failed} ) { # p $validation->{errors};
my %args = (
target => uri_for('/report'),
dfv_errs => $validation->{dfv_errs}, # href containing dfv_errs key
);
return template report => \%args;
}
my $data = $validation->{valid}; # p $data;
my $user = session('user_profile'); # p $user;
# add user_id & request_id to $data:
$data->{request_id} = param('request_id');
$data->{user_id} = $user->{id}; # p $data;
my $result = $app->model->save_report($data);
if ( my $err = $result->{error} ) { # p $result;
my %args = ( target => uri_for('/report'), error => $err );
return template report => \%args;
} # p $params->{request_id};
else {
flash info => $result->{message};
}
my $lab_number = $app->model->get_lab_number($params->{request_id}); # p $lab_number;
redirect '/load?lab_number='.$lab_number;
};
# logout route:
get '/logout' => sub {
app->destroy_session;
redirect('/'); # should redirect to /login
};
get '/gitlog' => sub { template gitlog => { log => $app->gitlog } };
# default Dancer2 app index page:
get '/index' => sub { template index => {}, { layout => 'index' } };
#===============================================================================
# http://blog.geekuni.com/2015/06/three-ways-to-implement-sessions.html
=begin
get '/count' => sub {
if ( my $user = session('user') ) {
session count => session('count') + 1;
my $ordinal = $app->model->num2ordinal(session('count')); p $ordinal;
return
'<a href="/count">Click here</a> for the name of the eldest son of ' .
'<b>Count von '. ucfirst $user.' the '. ucfirst $ordinal .'</b>';
}
return 'Cookie Monster!';
};
get '/do_login/:user' => sub {
session user => params->{user};
session count => 0;
redirect '/count';
};
=cut
#===============================================================================
true;