package Routes::Moongate;
use Dancer2 appname => 'DocsLib';
use v5.34.0;
use Path::Tiny;
use Data::Printer;
use App::Model; # D2 plugin, provides 'model' keyword
use Dancer2::Plugin::Deferred;
use Dancer2::Plugin::Auth::Tiny;
my $PREFIX = 'moongate';
prefix "/$PREFIX";
my $docs_path = path( config->{documents_path}, $PREFIX ); # debug $docs_path;
# set path to documents folder:
model->moongate->set_docs_path($docs_path);
hook before_template_render => sub {
my $tokens = shift; # need to have unique token name across all route files
my %h = (
home => '/',
new => '/new_document',
edit => '/edit',
create => '/create',
search => '/search',
update => '/update',
summary => '/summary',
document => '/id',
download => '/download',
);
$tokens->{uri_for_section}->{$PREFIX}->{$_}
= uri_for('/'. $PREFIX . $h{$_}) for keys %h; # p $tokens;
};
=begin # rules for route names & uri_for_route:
cannot use method 'any' with route names: "Route with this name ($name) already exists"
probably when route name is registered for GET, then for POST/HEAD/etc
cannot use uri_for_route in any template loaded after forward (data is deleted)
=cut
# these routes need unique (to DocsLib app) route-names (for redirect):
get moongate_home => '/' => needs login => \&home;
get moongate_entry => '/id/:id[Int]' => \&get_document;
# these routes need permissions:
get '/edit/:id[Int]' => needs login => \&edit_document;
post '/create' => needs login => \&create_document;
post '/update/:id[Int]' => needs login => \&update_document;
# these routes don't need permissions or names (so can use 'any')
get '/new_document' => \&new_document;
get '/summary' => \&summary;
get '/download/:id[Str]' => \&download;
post '/search' => \&search;
# ==============================================================================
sub flash { deferred @_ }
sub home { template home => { title => 'Moongate' } }
sub new_document {
var next_route => 'create';
template $PREFIX.'/record.tt', { prefix => $PREFIX };
}
sub get_document {
my $id = route_parameters->get('id');
my $rec = model->moongate->get_document($id); # p $rec; # AoH
vars->{next_route} ||= 'edit/'.$id; # may already be set by edit_document()
template $PREFIX.'/record.tt', { entry => $rec };
}
sub edit_document {
my $id = route_parameters->get('id');
var next_route => 'update/'.$id;
forward '/'.$PREFIX.'/id/'.$id;
}
sub create_document {
my $params = request->parameters->as_hashref; # p $params;
# get upload data - new entry only, passed as param if edit:
my $data_file = upload('filename'); # p $data_file;
# if params.id present must be edit; if data_file submitted, must be replacement,
# or if original record had filename but no filename submitted, get old filename
# and store in var for later deletion:
if ( $params->{id} ) {
my $rec = model->moongate->get_document($params->{id}); # p $rec; # AoH
if ( $data_file || ( $rec->{filename} && ! $params->{filename} ) ) {
var file_to_delete => $rec->{filename} || undef; # may not be one
}
}
my $res = model->moongate->save_document($params, $data_file); # p $res;
if ( $res->{error} ) {
var input_error => $res->{error};
return template $PREFIX.'/record.tt', { entry => $params };
}
# no error:
my $action = $params->{id} ? 'update_success' : 'input_success'; # update if id supplied
flash ( $action => 1 ); # doesn't need message
if ($data_file) { # upload file to docs dir if uploaded:
my $filepath = path($docs_path, $params->{filename});
unless ( $data_file->copy_to($filepath) ) { # true or success, otherwise sets $!
my $err = $!;
warning "upload $filepath failed: $err";
send_error "upload $filepath failed: $err", 500;
}
debug "upload $filepath success";
}
# delete old file if flagged for deletion:
if ( my $old_filename = vars->{file_to_delete} ) {
my $filepath = path( $docs_path, $old_filename ); # p $filepath;
unless ( unlink( $filepath ) ) {
my $err = $!;
warning "deleting $filepath failed: $err";
send_error "deleting $filepath failed: $err", 500;
}
debug "deleted old file $filepath";
}
redirect uri_for_route( 'moongate_entry', { id => $res->{id} } );
}
sub update_document { # just captures document_id & forwards:
forward '/'.$PREFIX.'/create', { id => route_parameters->get('id') };
}
sub summary {
my $rec = model->moongate->get_all_documents; # p $rec; # AoH
template $PREFIX.'/summary.tt', { records => $rec };
}
sub search {
my $str = body_parameters->get('search'); # =~ s{\s+}{}gr; sometimes need space
my $rec = model->moongate->find_documents($str); # p $rec; # AoH
template $PREFIX.'/summary.tt', { records => $rec };
}
sub download {
my $doc_id = route_parameters->get('id');
var document_id => $doc_id;
my $directory = Path::Tiny->new($docs_path);
var download_dir => $directory;
forward '/download';
}
true;